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