sl@0: /*
sl@0:  *
sl@0:  * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
sl@0:  *
sl@0:  */
sl@0: 
sl@0: #include "LETypes.h"
sl@0: #include "OpenTypeTables.h"
sl@0: #include "GlyphDefinitionTables.h"
sl@0: #include "GlyphPositionAdjustments.h"
sl@0: #include "GlyphIterator.h"
sl@0: #include "LEGlyphStorage.h"
sl@0: #include "Lookups.h"
sl@0: #include "LESwaps.h"
sl@0: 
sl@0: U_NAMESPACE_BEGIN
sl@0: 
sl@0: GlyphIterator::GlyphIterator(LEGlyphStorage &theGlyphStorage, GlyphPositionAdjustments *theGlyphPositionAdjustments, le_bool rightToLeft, le_uint16 theLookupFlags, LETag theFeatureTag,
sl@0:     const GlyphDefinitionTableHeader *theGlyphDefinitionTableHeader)
sl@0:   : direction(1), position(-1), nextLimit(-1), prevLimit(-1),
sl@0:     glyphStorage(theGlyphStorage), glyphPositionAdjustments(theGlyphPositionAdjustments),
sl@0:     srcIndex(-1), destIndex(-1), lookupFlags(theLookupFlags), featureTag(theFeatureTag),
sl@0:     glyphClassDefinitionTable(NULL), markAttachClassDefinitionTable(NULL)
sl@0: 
sl@0: {
sl@0:     le_int32 glyphCount = glyphStorage.getGlyphCount();
sl@0: 
sl@0:     if (theGlyphDefinitionTableHeader != NULL) {
sl@0:         glyphClassDefinitionTable = theGlyphDefinitionTableHeader->getGlyphClassDefinitionTable();
sl@0:         markAttachClassDefinitionTable = theGlyphDefinitionTableHeader->getMarkAttachClassDefinitionTable();
sl@0:     }
sl@0: 
sl@0:     nextLimit = glyphCount;
sl@0: 
sl@0:     if (rightToLeft) {
sl@0:         direction = -1;
sl@0:         position = glyphCount;
sl@0:         nextLimit = -1;
sl@0:         prevLimit = glyphCount;
sl@0:     }
sl@0: }
sl@0: 
sl@0: GlyphIterator::GlyphIterator(GlyphIterator &that)
sl@0:   : glyphStorage(that.glyphStorage)
sl@0: {
sl@0:     direction    = that.direction;
sl@0:     position     = that.position;
sl@0:     nextLimit    = that.nextLimit;
sl@0:     prevLimit    = that.prevLimit;
sl@0: 
sl@0:     glyphPositionAdjustments = that.glyphPositionAdjustments;
sl@0:     srcIndex = that.srcIndex;
sl@0:     destIndex = that.destIndex;
sl@0:     lookupFlags = that.lookupFlags;
sl@0:     featureTag = that.featureTag;
sl@0:     glyphClassDefinitionTable = that.glyphClassDefinitionTable;
sl@0:     markAttachClassDefinitionTable = that.markAttachClassDefinitionTable;
sl@0: }
sl@0: 
sl@0: GlyphIterator::GlyphIterator(GlyphIterator &that, LETag newFeatureTag)
sl@0:   : glyphStorage(that.glyphStorage)
sl@0: {
sl@0:     direction    = that.direction;
sl@0:     position     = that.position;
sl@0:     nextLimit    = that.nextLimit;
sl@0:     prevLimit    = that.prevLimit;
sl@0: 
sl@0:     glyphPositionAdjustments = that.glyphPositionAdjustments;
sl@0:     srcIndex = that.srcIndex;
sl@0:     destIndex = that.destIndex;
sl@0:     lookupFlags = that.lookupFlags;
sl@0:     featureTag = newFeatureTag;
sl@0:     glyphClassDefinitionTable = that.glyphClassDefinitionTable;
sl@0:     markAttachClassDefinitionTable = that.markAttachClassDefinitionTable;
sl@0: }
sl@0: 
sl@0: GlyphIterator::GlyphIterator(GlyphIterator &that, le_uint16 newLookupFlags)
sl@0:   : glyphStorage(that.glyphStorage)
sl@0: {
sl@0:     direction    = that.direction;
sl@0:     position     = that.position;
sl@0:     nextLimit    = that.nextLimit;
sl@0:     prevLimit    = that.prevLimit;
sl@0: 
sl@0:     glyphPositionAdjustments = that.glyphPositionAdjustments;
sl@0:     srcIndex = that.srcIndex;
sl@0:     destIndex = that.destIndex;
sl@0:     lookupFlags = newLookupFlags;
sl@0:     featureTag = that.featureTag;
sl@0:     glyphClassDefinitionTable = that.glyphClassDefinitionTable;
sl@0:     markAttachClassDefinitionTable = that.markAttachClassDefinitionTable;
sl@0: }
sl@0: 
sl@0: GlyphIterator::~GlyphIterator()
sl@0: {
sl@0:     // nothing to do, right?
sl@0: }
sl@0: 
sl@0: void GlyphIterator::reset(le_uint16 newLookupFlags, LETag newFeatureTag)
sl@0: {
sl@0:     position    = prevLimit;
sl@0:     featureTag  = newFeatureTag;
sl@0:     lookupFlags = newLookupFlags;
sl@0: }
sl@0: 
sl@0: LEGlyphID *GlyphIterator::insertGlyphs(le_int32 count, LEErrorCode& success)
sl@0: {
sl@0:     return glyphStorage.insertGlyphs(position, count, success);
sl@0: }
sl@0: 
sl@0: le_int32 GlyphIterator::applyInsertions()
sl@0: {
sl@0:     le_int32 newGlyphCount = glyphStorage.applyInsertions();
sl@0: 
sl@0:     if (direction < 0) {
sl@0:         prevLimit = newGlyphCount;
sl@0:     } else {
sl@0:         nextLimit = newGlyphCount;
sl@0:     }
sl@0: 
sl@0:     return newGlyphCount;
sl@0: }
sl@0: 
sl@0: le_int32 GlyphIterator::getCurrStreamPosition() const
sl@0: {
sl@0:     return position;
sl@0: }
sl@0: 
sl@0: le_bool GlyphIterator::isRightToLeft() const
sl@0: {
sl@0:     return direction < 0;
sl@0: }
sl@0: 
sl@0: le_bool GlyphIterator::ignoresMarks() const
sl@0: {
sl@0:     return (lookupFlags & lfIgnoreMarks) != 0;
sl@0: }
sl@0: 
sl@0: le_bool GlyphIterator::baselineIsLogicalEnd() const
sl@0: {
sl@0:     return (lookupFlags & lfBaselineIsLogicalEnd) != 0;
sl@0: }
sl@0: 
sl@0: LEGlyphID GlyphIterator::getCurrGlyphID() const
sl@0: {
sl@0:     if (direction < 0) {
sl@0:         if (position <= nextLimit || position >= prevLimit) {
sl@0:             return 0xFFFF;
sl@0:         }
sl@0:     } else {
sl@0:         if (position <= prevLimit || position >= nextLimit) {
sl@0:             return 0xFFFF;
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     return glyphStorage[position];
sl@0: }
sl@0: 
sl@0: void GlyphIterator::getCursiveEntryPoint(LEPoint &entryPoint) const
sl@0: {
sl@0:     if (direction < 0) {
sl@0:         if (position <= nextLimit || position >= prevLimit) {
sl@0:             return;
sl@0:         }
sl@0:     } else {
sl@0:         if (position <= prevLimit || position >= nextLimit) {
sl@0:             return;
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     glyphPositionAdjustments->getEntryPoint(position, entryPoint);
sl@0: }
sl@0: 
sl@0: void GlyphIterator::getCursiveExitPoint(LEPoint &exitPoint) const
sl@0: {
sl@0:     if (direction < 0) {
sl@0:         if (position <= nextLimit || position >= prevLimit) {
sl@0:             return;
sl@0:         }
sl@0:     } else {
sl@0:         if (position <= prevLimit || position >= nextLimit) {
sl@0:             return;
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     glyphPositionAdjustments->getExitPoint(position, exitPoint);
sl@0: }
sl@0: 
sl@0: void GlyphIterator::setCurrGlyphID(TTGlyphID glyphID)
sl@0: {
sl@0:     LEGlyphID glyph = glyphStorage[position];
sl@0: 
sl@0:     glyphStorage[position] = LE_SET_GLYPH(glyph, glyphID);
sl@0: }
sl@0: 
sl@0: void GlyphIterator::setCurrStreamPosition(le_int32 newPosition)
sl@0: {
sl@0:     if (direction < 0) {
sl@0:         if (newPosition >= prevLimit) {
sl@0:             position = prevLimit;
sl@0:             return;
sl@0:         }
sl@0: 
sl@0:         if (newPosition <= nextLimit) {
sl@0:             position = nextLimit;
sl@0:             return;
sl@0:         }
sl@0:     } else {
sl@0:         if (newPosition <= prevLimit) {
sl@0:             position = prevLimit;
sl@0:             return;
sl@0:         }
sl@0: 
sl@0:         if (newPosition >= nextLimit) {
sl@0:             position = nextLimit;
sl@0:             return;
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     position = newPosition - direction;
sl@0:     next();
sl@0: }
sl@0: 
sl@0: void GlyphIterator::setCurrGlyphBaseOffset(le_int32 baseOffset)
sl@0: {
sl@0:     if (direction < 0) {
sl@0:         if (position <= nextLimit || position >= prevLimit) {
sl@0:             return;
sl@0:         }
sl@0:     } else {
sl@0:         if (position <= prevLimit || position >= nextLimit) {
sl@0:             return;
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     glyphPositionAdjustments->setBaseOffset(position, baseOffset);
sl@0: }
sl@0: 
sl@0: void GlyphIterator::adjustCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust,
sl@0:                                                       float xAdvanceAdjust, float yAdvanceAdjust)
sl@0: {
sl@0:     if (direction < 0) {
sl@0:         if (position <= nextLimit || position >= prevLimit) {
sl@0:             return;
sl@0:         }
sl@0:     } else {
sl@0:         if (position <= prevLimit || position >= nextLimit) {
sl@0:             return;
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     glyphPositionAdjustments->adjustXPlacement(position, xPlacementAdjust);
sl@0:     glyphPositionAdjustments->adjustYPlacement(position, yPlacementAdjust);
sl@0:     glyphPositionAdjustments->adjustXAdvance(position, xAdvanceAdjust);
sl@0:     glyphPositionAdjustments->adjustYAdvance(position, yAdvanceAdjust);
sl@0: }
sl@0: 
sl@0: void GlyphIterator::setCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust,
sl@0:                                                       float xAdvanceAdjust, float yAdvanceAdjust)
sl@0: {
sl@0:     if (direction < 0) {
sl@0:         if (position <= nextLimit || position >= prevLimit) {
sl@0:             return;
sl@0:         }
sl@0:     } else {
sl@0:         if (position <= prevLimit || position >= nextLimit) {
sl@0:             return;
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     glyphPositionAdjustments->setXPlacement(position, xPlacementAdjust);
sl@0:     glyphPositionAdjustments->setYPlacement(position, yPlacementAdjust);
sl@0:     glyphPositionAdjustments->setXAdvance(position, xAdvanceAdjust);
sl@0:     glyphPositionAdjustments->setYAdvance(position, yAdvanceAdjust);
sl@0: }
sl@0: 
sl@0: void GlyphIterator::setCursiveEntryPoint(LEPoint &entryPoint)
sl@0: {
sl@0:     if (direction < 0) {
sl@0:         if (position <= nextLimit || position >= prevLimit) {
sl@0:             return;
sl@0:         }
sl@0:     } else {
sl@0:         if (position <= prevLimit || position >= nextLimit) {
sl@0:             return;
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     glyphPositionAdjustments->setEntryPoint(position, entryPoint, baselineIsLogicalEnd());
sl@0: }
sl@0: 
sl@0: void GlyphIterator::setCursiveExitPoint(LEPoint &exitPoint)
sl@0: {
sl@0:     if (direction < 0) {
sl@0:         if (position <= nextLimit || position >= prevLimit) {
sl@0:             return;
sl@0:         }
sl@0:     } else {
sl@0:         if (position <= prevLimit || position >= nextLimit) {
sl@0:             return;
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     glyphPositionAdjustments->setExitPoint(position, exitPoint, baselineIsLogicalEnd());
sl@0: }
sl@0: 
sl@0: void GlyphIterator::setCursiveGlyph()
sl@0: {
sl@0:     if (direction < 0) {
sl@0:         if (position <= nextLimit || position >= prevLimit) {
sl@0:             return;
sl@0:         }
sl@0:     } else {
sl@0:         if (position <= prevLimit || position >= nextLimit) {
sl@0:             return;
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     glyphPositionAdjustments->setCursiveGlyph(position, baselineIsLogicalEnd());
sl@0: }
sl@0: 
sl@0: le_bool GlyphIterator::filterGlyph(le_uint32 index) const
sl@0: {
sl@0:     LEGlyphID glyphID = glyphStorage[index];
sl@0:     le_int32 glyphClass = gcdNoGlyphClass;
sl@0: 
sl@0:     if (LE_GET_GLYPH(glyphID) >= 0xFFFE) {
sl@0:         return TRUE;
sl@0:     }
sl@0: 
sl@0:     if (glyphClassDefinitionTable != NULL) {
sl@0:         glyphClass = glyphClassDefinitionTable->getGlyphClass(glyphID);
sl@0:     }
sl@0: 
sl@0:     switch (glyphClass)
sl@0:     {
sl@0:     case gcdNoGlyphClass:
sl@0:         return FALSE;
sl@0: 
sl@0:     case gcdSimpleGlyph:
sl@0:         return (lookupFlags & lfIgnoreBaseGlyphs) != 0;
sl@0: 
sl@0:     case gcdLigatureGlyph:
sl@0:         return (lookupFlags & lfIgnoreLigatures) != 0;
sl@0: 
sl@0:     case gcdMarkGlyph:
sl@0:     {
sl@0:         if ((lookupFlags & lfIgnoreMarks) != 0) {
sl@0:             return TRUE;
sl@0:         }
sl@0: 
sl@0:         le_uint16 markAttachType = (lookupFlags & lfMarkAttachTypeMask) >> lfMarkAttachTypeShift;
sl@0: 
sl@0:         if ((markAttachType != 0) && (markAttachClassDefinitionTable != NULL)) {
sl@0:             return markAttachClassDefinitionTable->getGlyphClass(glyphID) != markAttachType;
sl@0:         }
sl@0: 
sl@0:         return FALSE;
sl@0:     }
sl@0: 
sl@0:     case gcdComponentGlyph:
sl@0:         return (lookupFlags & lfIgnoreBaseGlyphs) != 0;
sl@0: 
sl@0:     default:
sl@0:         return FALSE;
sl@0:     }
sl@0: }
sl@0: 
sl@0: static const LETag emptyTag = 0;
sl@0: static const LETag defaultTag = 0xFFFFFFFF;
sl@0: 
sl@0: le_bool GlyphIterator::hasFeatureTag() const
sl@0: {
sl@0:     if (featureTag == defaultTag || featureTag == emptyTag) {
sl@0:         return TRUE;
sl@0:     }
sl@0: 
sl@0:     LEErrorCode success = LE_NO_ERROR;
sl@0:     const LETag *tagList = (const LETag *) glyphStorage.getAuxData(position, success);
sl@0: 
sl@0:     if (tagList != NULL) {
sl@0:         for (le_int32 tag = 0; tagList[tag] != emptyTag; tag += 1) {
sl@0:             if (tagList[tag] == featureTag) {
sl@0:                 return TRUE;
sl@0:             }
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     return FALSE;
sl@0: }
sl@0: 
sl@0: le_bool GlyphIterator::findFeatureTag()
sl@0: {
sl@0:     while (nextInternal()) {
sl@0:         if (hasFeatureTag()) {
sl@0:             prevInternal();
sl@0:             return TRUE;
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     return FALSE;
sl@0: }
sl@0: 
sl@0: 
sl@0: le_bool GlyphIterator::nextInternal(le_uint32 delta)
sl@0: {
sl@0:     le_int32 newPosition = position;
sl@0: 
sl@0:     while (newPosition != nextLimit && delta > 0) {
sl@0:         do {
sl@0:             newPosition += direction;
sl@0:         } while (newPosition != nextLimit && filterGlyph(newPosition));
sl@0: 
sl@0:         delta -= 1;
sl@0:     }
sl@0: 
sl@0:     position = newPosition;
sl@0: 
sl@0:     return position != nextLimit;
sl@0: }
sl@0: 
sl@0: le_bool GlyphIterator::next(le_uint32 delta)
sl@0: {
sl@0:     return nextInternal(delta) && hasFeatureTag();
sl@0: }
sl@0: 
sl@0: le_bool GlyphIterator::prevInternal(le_uint32 delta)
sl@0: {
sl@0:     le_int32 newPosition = position;
sl@0: 
sl@0:     while (newPosition != prevLimit && delta > 0) {
sl@0:         do {
sl@0:             newPosition -= direction;
sl@0:         } while (newPosition != prevLimit && filterGlyph(newPosition));
sl@0: 
sl@0:         delta -= 1;
sl@0:     }
sl@0: 
sl@0:     position = newPosition;
sl@0: 
sl@0:     return position != prevLimit;
sl@0: }
sl@0: 
sl@0: le_bool GlyphIterator::prev(le_uint32 delta)
sl@0: {
sl@0:     return prevInternal(delta) && hasFeatureTag();
sl@0: }
sl@0: 
sl@0: le_int32 GlyphIterator::getMarkComponent(le_int32 markPosition) const
sl@0: {
sl@0:     le_int32 component = 0;
sl@0:     le_int32 posn;
sl@0: 
sl@0:     for (posn = position; posn != markPosition; posn += direction) {
sl@0:         if (glyphStorage[posn] == 0xFFFE) {
sl@0:             component += 1;
sl@0:         }
sl@0:     }
sl@0: 
sl@0:     return component;
sl@0: }
sl@0: 
sl@0: // This is basically prevInternal except that it
sl@0: // doesn't take a delta argument, and it doesn't
sl@0: // filter out 0xFFFE glyphs.
sl@0: le_bool GlyphIterator::findMark2Glyph()
sl@0: {
sl@0:     le_int32 newPosition = position;
sl@0: 
sl@0:     do {
sl@0:         newPosition -= direction;
sl@0:     } while (newPosition != prevLimit && glyphStorage[newPosition] != 0xFFFE && filterGlyph(newPosition));
sl@0: 
sl@0:     position = newPosition;
sl@0: 
sl@0:     return position != prevLimit;
sl@0: }
sl@0: 
sl@0: U_NAMESPACE_END