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
16U_NAMESPACE_BEGIN
17
18GlyphIterator::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
47GlyphIterator::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
66GlyphIterator::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
85GlyphIterator::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
104GlyphIterator::~GlyphIterator()
105{
106    // nothing to do, right?
107}
108
109void GlyphIterator::reset(le_uint16 newLookupFlags, FeatureMask newFeatureMask)
110{
111    position     = prevLimit;
112    featureMask  = newFeatureMask;
113    glyphGroup   = 0;
114    lookupFlags  = newLookupFlags;
115    filterResetCache();
116}
117
118LEGlyphID *GlyphIterator::insertGlyphs(le_int32 count, LEErrorCode& success)
119{
120    return glyphStorage.insertGlyphs(position, count, success);
121}
122
123le_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
136le_int32 GlyphIterator::getCurrStreamPosition() const
137{
138    return position;
139}
140
141le_bool GlyphIterator::isRightToLeft() const
142{
143    return direction < 0;
144}
145
146le_bool GlyphIterator::ignoresMarks() const
147{
148    return (lookupFlags & lfIgnoreMarks) != 0;
149}
150
151le_bool GlyphIterator::baselineIsLogicalEnd() const
152{
153    return (lookupFlags & lfBaselineIsLogicalEnd) != 0;
154}
155
156LEGlyphID 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
171void 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
186void 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
201void GlyphIterator::setCurrGlyphID(TTGlyphID glyphID)
202{
203    LEGlyphID glyph = glyphStorage[position];
204
205    glyphStorage[position] = LE_SET_GLYPH(glyph, glyphID);
206}
207
208void 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
236void 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
251void 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
270void 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
289void 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
304void 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
319void 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
334void 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
349void 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
364void GlyphIterator::filterResetCache(void) {
365  filterCacheValid = FALSE;
366}
367
368le_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
428le_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
440le_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
457le_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
476le_bool GlyphIterator::next(le_uint32 delta)
477{
478    return nextInternal(delta) && hasFeatureTag(TRUE);
479}
480
481le_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
500le_bool GlyphIterator::prev(le_uint32 delta)
501{
502    return prevInternal(delta) && hasFeatureTag(TRUE);
503}
504
505le_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.
522le_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
535U_NAMESPACE_END
536