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