Home | History | Annotate | Download | only in layout
      1 /*
      2  *
      3  * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved
      4  *
      5  */
      6 
      7 #include "LETypes.h"
      8 #include "OpenTypeTables.h"
      9 #include "GlyphDefinitionTables.h"
     10 #include "GlyphPositionAdjustments.h"
     11 #include "GlyphIterator.h"
     12 #include "LEGlyphStorage.h"
     13 #include "Lookups.h"
     14 #include "LESwaps.h"
     15 
     16 U_NAMESPACE_BEGIN
     17 
     18 GlyphIterator::GlyphIterator(LEGlyphStorage &theGlyphStorage, GlyphPositionAdjustments *theGlyphPositionAdjustments, le_bool rightToLeft, le_uint16 theLookupFlags,
     19                              FeatureMask theFeatureMask, const LEReferenceTo<GlyphDefinitionTableHeader> &theGlyphDefinitionTableHeader)
     20   : direction(1), position(-1), nextLimit(-1), prevLimit(-1),
     21     glyphStorage(theGlyphStorage), glyphPositionAdjustments(theGlyphPositionAdjustments),
     22     srcIndex(-1), destIndex(-1), lookupFlags(theLookupFlags), featureMask(theFeatureMask), glyphGroup(0),
     23     glyphClassDefinitionTable(), markAttachClassDefinitionTable()
     24 
     25 {
     26   LEErrorCode success = LE_NO_ERROR; // TODO
     27     le_int32 glyphCount = glyphStorage.getGlyphCount();
     28 
     29     if (theGlyphDefinitionTableHeader.isValid()) {
     30       glyphClassDefinitionTable = theGlyphDefinitionTableHeader
     31         -> getGlyphClassDefinitionTable(theGlyphDefinitionTableHeader, success);
     32       markAttachClassDefinitionTable = theGlyphDefinitionTableHeader
     33         ->getMarkAttachClassDefinitionTable(theGlyphDefinitionTableHeader, success);
     34     }
     35 
     36     nextLimit = glyphCount;
     37 
     38     if (rightToLeft) {
     39         direction = -1;
     40         position = glyphCount;
     41         nextLimit = -1;
     42         prevLimit = glyphCount;
     43     }
     44     filterResetCache();
     45 }
     46 
     47 GlyphIterator::GlyphIterator(GlyphIterator &that)
     48   : glyphStorage(that.glyphStorage)
     49 {
     50     direction    = that.direction;
     51     position     = that.position;
     52     nextLimit    = that.nextLimit;
     53     prevLimit    = that.prevLimit;
     54 
     55     glyphPositionAdjustments = that.glyphPositionAdjustments;
     56     srcIndex = that.srcIndex;
     57     destIndex = that.destIndex;
     58     lookupFlags = that.lookupFlags;
     59     featureMask = that.featureMask;
     60     glyphGroup  = that.glyphGroup;
     61     glyphClassDefinitionTable = that.glyphClassDefinitionTable;
     62     markAttachClassDefinitionTable = that.markAttachClassDefinitionTable;
     63     filterResetCache();
     64 }
     65 
     66 GlyphIterator::GlyphIterator(GlyphIterator &that, FeatureMask newFeatureMask)
     67   : glyphStorage(that.glyphStorage)
     68 {
     69     direction    = that.direction;
     70     position     = that.position;
     71     nextLimit    = that.nextLimit;
     72     prevLimit    = that.prevLimit;
     73 
     74     glyphPositionAdjustments = that.glyphPositionAdjustments;
     75     srcIndex = that.srcIndex;
     76     destIndex = that.destIndex;
     77     lookupFlags = that.lookupFlags;
     78     featureMask = newFeatureMask;
     79     glyphGroup  = 0;
     80     glyphClassDefinitionTable = that.glyphClassDefinitionTable;
     81     markAttachClassDefinitionTable = that.markAttachClassDefinitionTable;
     82     filterResetCache();
     83 }
     84 
     85 GlyphIterator::GlyphIterator(GlyphIterator &that, le_uint16 newLookupFlags)
     86   : glyphStorage(that.glyphStorage)
     87 {
     88     direction    = that.direction;
     89     position     = that.position;
     90     nextLimit    = that.nextLimit;
     91     prevLimit    = that.prevLimit;
     92 
     93     glyphPositionAdjustments = that.glyphPositionAdjustments;
     94     srcIndex = that.srcIndex;
     95     destIndex = that.destIndex;
     96     lookupFlags = newLookupFlags;
     97     featureMask = that.featureMask;
     98     glyphGroup  = that.glyphGroup;
     99     glyphClassDefinitionTable = that.glyphClassDefinitionTable;
    100     markAttachClassDefinitionTable = that.markAttachClassDefinitionTable;
    101     filterResetCache();
    102 }
    103 
    104 GlyphIterator::~GlyphIterator()
    105 {
    106     // nothing to do, right?
    107 }
    108 
    109 void GlyphIterator::reset(le_uint16 newLookupFlags, FeatureMask newFeatureMask)
    110 {
    111     position     = prevLimit;
    112     featureMask  = newFeatureMask;
    113     glyphGroup   = 0;
    114     lookupFlags  = newLookupFlags;
    115     filterResetCache();
    116 }
    117 
    118 LEGlyphID *GlyphIterator::insertGlyphs(le_int32 count, LEErrorCode& success)
    119 {
    120     return glyphStorage.insertGlyphs(position, count, success);
    121 }
    122 
    123 le_int32 GlyphIterator::applyInsertions()
    124 {
    125     le_int32 newGlyphCount = glyphStorage.applyInsertions();
    126 
    127     if (direction < 0) {
    128         prevLimit = newGlyphCount;
    129     } else {
    130         nextLimit = newGlyphCount;
    131     }
    132 
    133     return newGlyphCount;
    134 }
    135 
    136 le_int32 GlyphIterator::getCurrStreamPosition() const
    137 {
    138     return position;
    139 }
    140 
    141 le_bool GlyphIterator::isRightToLeft() const
    142 {
    143     return direction < 0;
    144 }
    145 
    146 le_bool GlyphIterator::ignoresMarks() const
    147 {
    148     return (lookupFlags & lfIgnoreMarks) != 0;
    149 }
    150 
    151 le_bool GlyphIterator::baselineIsLogicalEnd() const
    152 {
    153     return (lookupFlags & lfBaselineIsLogicalEnd) != 0;
    154 }
    155 
    156 LEGlyphID GlyphIterator::getCurrGlyphID() const
    157 {
    158     if (direction < 0) {
    159         if (position <= nextLimit || position >= prevLimit) {
    160             return 0xFFFF;
    161         }
    162     } else {
    163         if (position <= prevLimit || position >= nextLimit) {
    164             return 0xFFFF;
    165         }
    166     }
    167 
    168     return glyphStorage[position];
    169 }
    170 
    171 void GlyphIterator::getCursiveEntryPoint(LEPoint &entryPoint) const
    172 {
    173     if (direction < 0) {
    174         if (position <= nextLimit || position >= prevLimit) {
    175             return;
    176         }
    177     } else {
    178         if (position <= prevLimit || position >= nextLimit) {
    179             return;
    180         }
    181     }
    182 
    183     glyphPositionAdjustments->getEntryPoint(position, entryPoint);
    184 }
    185 
    186 void GlyphIterator::getCursiveExitPoint(LEPoint &exitPoint) const
    187 {
    188     if (direction < 0) {
    189         if (position <= nextLimit || position >= prevLimit) {
    190             return;
    191         }
    192     } else {
    193         if (position <= prevLimit || position >= nextLimit) {
    194             return;
    195         }
    196     }
    197 
    198     glyphPositionAdjustments->getExitPoint(position, exitPoint);
    199 }
    200 
    201 void GlyphIterator::setCurrGlyphID(TTGlyphID glyphID)
    202 {
    203     LEGlyphID glyph = glyphStorage[position];
    204 
    205     glyphStorage[position] = LE_SET_GLYPH(glyph, glyphID);
    206 }
    207 
    208 void GlyphIterator::setCurrStreamPosition(le_int32 newPosition)
    209 {
    210     if (direction < 0) {
    211         if (newPosition >= prevLimit) {
    212             position = prevLimit;
    213             return;
    214         }
    215 
    216         if (newPosition <= nextLimit) {
    217             position = nextLimit;
    218             return;
    219         }
    220     } else {
    221         if (newPosition <= prevLimit) {
    222             position = prevLimit;
    223             return;
    224         }
    225 
    226         if (newPosition >= nextLimit) {
    227             position = nextLimit;
    228             return;
    229         }
    230     }
    231 
    232     position = newPosition - direction;
    233     next();
    234 }
    235 
    236 void GlyphIterator::setCurrGlyphBaseOffset(le_int32 baseOffset)
    237 {
    238     if (direction < 0) {
    239         if (position <= nextLimit || position >= prevLimit) {
    240             return;
    241         }
    242     } else {
    243         if (position <= prevLimit || position >= nextLimit) {
    244             return;
    245         }
    246     }
    247 
    248     glyphPositionAdjustments->setBaseOffset(position, baseOffset);
    249 }
    250 
    251 void GlyphIterator::adjustCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust,
    252                                                       float xAdvanceAdjust, float yAdvanceAdjust)
    253 {
    254     if (direction < 0) {
    255         if (position <= nextLimit || position >= prevLimit) {
    256             return;
    257         }
    258     } else {
    259         if (position <= prevLimit || position >= nextLimit) {
    260             return;
    261         }
    262     }
    263 
    264     glyphPositionAdjustments->adjustXPlacement(position, xPlacementAdjust);
    265     glyphPositionAdjustments->adjustYPlacement(position, yPlacementAdjust);
    266     glyphPositionAdjustments->adjustXAdvance(position, xAdvanceAdjust);
    267     glyphPositionAdjustments->adjustYAdvance(position, yAdvanceAdjust);
    268 }
    269 
    270 void GlyphIterator::setCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust,
    271                                                       float xAdvanceAdjust, float yAdvanceAdjust)
    272 {
    273     if (direction < 0) {
    274         if (position <= nextLimit || position >= prevLimit) {
    275             return;
    276         }
    277     } else {
    278         if (position <= prevLimit || position >= nextLimit) {
    279             return;
    280         }
    281     }
    282 
    283     glyphPositionAdjustments->setXPlacement(position, xPlacementAdjust);
    284     glyphPositionAdjustments->setYPlacement(position, yPlacementAdjust);
    285     glyphPositionAdjustments->setXAdvance(position, xAdvanceAdjust);
    286     glyphPositionAdjustments->setYAdvance(position, yAdvanceAdjust);
    287 }
    288 
    289 void GlyphIterator::clearCursiveEntryPoint()
    290 {
    291     if (direction < 0) {
    292         if (position <= nextLimit || position >= prevLimit) {
    293             return;
    294         }
    295     } else {
    296         if (position <= prevLimit || position >= nextLimit) {
    297             return;
    298         }
    299     }
    300 
    301     glyphPositionAdjustments->clearEntryPoint(position);
    302 }
    303 
    304 void GlyphIterator::clearCursiveExitPoint()
    305 {
    306     if (direction < 0) {
    307         if (position <= nextLimit || position >= prevLimit) {
    308             return;
    309         }
    310     } else {
    311         if (position <= prevLimit || position >= nextLimit) {
    312             return;
    313         }
    314     }
    315 
    316     glyphPositionAdjustments->clearExitPoint(position);
    317 }
    318 
    319 void GlyphIterator::setCursiveEntryPoint(LEPoint &entryPoint)
    320 {
    321     if (direction < 0) {
    322         if (position <= nextLimit || position >= prevLimit) {
    323             return;
    324         }
    325     } else {
    326         if (position <= prevLimit || position >= nextLimit) {
    327             return;
    328         }
    329     }
    330 
    331     glyphPositionAdjustments->setEntryPoint(position, entryPoint, baselineIsLogicalEnd());
    332 }
    333 
    334 void GlyphIterator::setCursiveExitPoint(LEPoint &exitPoint)
    335 {
    336     if (direction < 0) {
    337         if (position <= nextLimit || position >= prevLimit) {
    338             return;
    339         }
    340     } else {
    341         if (position <= prevLimit || position >= nextLimit) {
    342             return;
    343         }
    344     }
    345 
    346     glyphPositionAdjustments->setExitPoint(position, exitPoint, baselineIsLogicalEnd());
    347 }
    348 
    349 void GlyphIterator::setCursiveGlyph()
    350 {
    351     if (direction < 0) {
    352         if (position <= nextLimit || position >= prevLimit) {
    353             return;
    354         }
    355     } else {
    356         if (position <= prevLimit || position >= nextLimit) {
    357             return;
    358         }
    359     }
    360 
    361     glyphPositionAdjustments->setCursiveGlyph(position, baselineIsLogicalEnd());
    362 }
    363 
    364 void GlyphIterator::filterResetCache(void) {
    365   filterCacheValid = FALSE;
    366 }
    367 
    368 le_bool GlyphIterator::filterGlyph(le_uint32 index)
    369 {
    370     LEGlyphID glyphID = glyphStorage[index];
    371 
    372     if (!filterCacheValid || filterCache.id != glyphID) {
    373       filterCache.id = glyphID;
    374 
    375       le_bool &filterResult = filterCache.result;  // NB: Making this a reference to accept the updated value, in case
    376                                                // we want more fancy cacheing in the future.
    377       if (LE_GET_GLYPH(glyphID) >= 0xFFFE) {
    378         filterResult = TRUE;
    379       } else {
    380         LEErrorCode success = LE_NO_ERROR;
    381         le_int32 glyphClass = gcdNoGlyphClass;
    382         if (glyphClassDefinitionTable.isValid()) {
    383           glyphClass = glyphClassDefinitionTable->getGlyphClass(glyphClassDefinitionTable, glyphID, success);
    384         }
    385         switch (glyphClass) {
    386         case gcdNoGlyphClass:
    387           filterResult = FALSE;
    388           break;
    389 
    390         case gcdSimpleGlyph:
    391           filterResult = (lookupFlags & lfIgnoreBaseGlyphs) != 0;
    392           break;
    393 
    394         case gcdLigatureGlyph:
    395           filterResult = (lookupFlags & lfIgnoreLigatures) != 0;
    396           break;
    397 
    398         case gcdMarkGlyph:
    399           if ((lookupFlags & lfIgnoreMarks) != 0) {
    400             filterResult = TRUE;
    401           } else {
    402             le_uint16 markAttachType = (lookupFlags & lfMarkAttachTypeMask) >> lfMarkAttachTypeShift;
    403 
    404             if ((markAttachType != 0) && (markAttachClassDefinitionTable.isValid())) {
    405               filterResult = (markAttachClassDefinitionTable
    406                           -> getGlyphClass(markAttachClassDefinitionTable, glyphID, success) != markAttachType);
    407             } else {
    408               filterResult = FALSE;
    409             }
    410           }
    411           break;
    412 
    413         case gcdComponentGlyph:
    414           filterResult = ((lookupFlags & lfIgnoreBaseGlyphs) != 0);
    415           break;
    416 
    417         default:
    418           filterResult = FALSE;
    419           break;
    420         }
    421       }
    422       filterCacheValid = TRUE;
    423     }
    424 
    425     return filterCache.result;
    426 }
    427 
    428 le_bool GlyphIterator::hasFeatureTag(le_bool matchGroup) const
    429 {
    430     if (featureMask == 0) {
    431         return TRUE;
    432     }
    433 
    434     LEErrorCode success = LE_NO_ERROR;
    435     FeatureMask fm = glyphStorage.getAuxData(position, success);
    436 
    437     return ((fm & featureMask) == featureMask) && (!matchGroup || (le_int32)(fm & LE_GLYPH_GROUP_MASK) == glyphGroup);
    438 }
    439 
    440 le_bool GlyphIterator::findFeatureTag()
    441 {
    442   //glyphGroup = 0;
    443 
    444     while (nextInternal()) {
    445         if (hasFeatureTag(FALSE)) {
    446             LEErrorCode success = LE_NO_ERROR;
    447 
    448             glyphGroup = (glyphStorage.getAuxData(position, success) & LE_GLYPH_GROUP_MASK);
    449             return TRUE;
    450         }
    451     }
    452 
    453     return FALSE;
    454 }
    455 
    456 
    457 le_bool GlyphIterator::nextInternal(le_uint32 delta)
    458 {
    459     le_int32 newPosition = position;
    460 
    461     while (newPosition != nextLimit && delta > 0) {
    462         do {
    463             newPosition += direction;
    464             //fprintf(stderr,"%s:%d:%s: newPosition = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, newPosition, delta);
    465         } while (newPosition != nextLimit && filterGlyph(newPosition));
    466 
    467         delta -= 1;
    468     }
    469 
    470     position = newPosition;
    471 
    472     //fprintf(stderr,"%s:%d:%s: exit position = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, position, delta);
    473     return position != nextLimit;
    474 }
    475 
    476 le_bool GlyphIterator::next(le_uint32 delta)
    477 {
    478     return nextInternal(delta) && hasFeatureTag(TRUE);
    479 }
    480 
    481 le_bool GlyphIterator::prevInternal(le_uint32 delta)
    482 {
    483     le_int32 newPosition = position;
    484 
    485     while (newPosition != prevLimit && delta > 0) {
    486         do {
    487             newPosition -= direction;
    488             //fprintf(stderr,"%s:%d:%s: newPosition = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, newPosition, delta);
    489         } while (newPosition != prevLimit && filterGlyph(newPosition));
    490 
    491         delta -= 1;
    492     }
    493 
    494     position = newPosition;
    495 
    496     //fprintf(stderr,"%s:%d:%s: exit position = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, position, delta);
    497     return position != prevLimit;
    498 }
    499 
    500 le_bool GlyphIterator::prev(le_uint32 delta)
    501 {
    502     return prevInternal(delta) && hasFeatureTag(TRUE);
    503 }
    504 
    505 le_int32 GlyphIterator::getMarkComponent(le_int32 markPosition) const
    506 {
    507     le_int32 component = 0;
    508     le_int32 posn;
    509 
    510     for (posn = position; posn != markPosition; posn += direction) {
    511         if (glyphStorage[posn] == 0xFFFE) {
    512             component += 1;
    513         }
    514     }
    515 
    516     return component;
    517 }
    518 
    519 // This is basically prevInternal except that it
    520 // doesn't take a delta argument, and it doesn't
    521 // filter out 0xFFFE glyphs.
    522 le_bool GlyphIterator::findMark2Glyph()
    523 {
    524     le_int32 newPosition = position;
    525 
    526     do {
    527         newPosition -= direction;
    528     } while (newPosition != prevLimit && glyphStorage[newPosition] != 0xFFFE && filterGlyph(newPosition));
    529 
    530     position = newPosition;
    531 
    532     return position != prevLimit;
    533 }
    534 
    535 U_NAMESPACE_END
    536