]> git.saurik.com Git - apple/icu.git/blame - icuSources/layout/GlyphIterator.cpp
ICU-551.24.tar.gz
[apple/icu.git] / icuSources / layout / GlyphIterator.cpp
CommitLineData
b75a7d8f 1/*
b75a7d8f 2 *
57a6839d 3 * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved
b75a7d8f
A
4 *
5 */
6
7#include "LETypes.h"
8#include "OpenTypeTables.h"
9#include "GlyphDefinitionTables.h"
10#include "GlyphPositionAdjustments.h"
11#include "GlyphIterator.h"
374ca955 12#include "LEGlyphStorage.h"
b75a7d8f
A
13#include "Lookups.h"
14#include "LESwaps.h"
15
16U_NAMESPACE_BEGIN
17
73c04bcf 18GlyphIterator::GlyphIterator(LEGlyphStorage &theGlyphStorage, GlyphPositionAdjustments *theGlyphPositionAdjustments, le_bool rightToLeft, le_uint16 theLookupFlags,
57a6839d 19 FeatureMask theFeatureMask, const LEReferenceTo<GlyphDefinitionTableHeader> &theGlyphDefinitionTableHeader)
374ca955 20 : direction(1), position(-1), nextLimit(-1), prevLimit(-1),
374ca955 21 glyphStorage(theGlyphStorage), glyphPositionAdjustments(theGlyphPositionAdjustments),
46f4442e 22 srcIndex(-1), destIndex(-1), lookupFlags(theLookupFlags), featureMask(theFeatureMask), glyphGroup(0),
57a6839d 23 glyphClassDefinitionTable(), markAttachClassDefinitionTable()
b75a7d8f
A
24
25{
57a6839d 26 LEErrorCode success = LE_NO_ERROR; // TODO
374ca955
A
27 le_int32 glyphCount = glyphStorage.getGlyphCount();
28
57a6839d
A
29 if (theGlyphDefinitionTableHeader.isValid()) {
30 glyphClassDefinitionTable = theGlyphDefinitionTableHeader
31 -> getGlyphClassDefinitionTable(theGlyphDefinitionTableHeader, success);
32 markAttachClassDefinitionTable = theGlyphDefinitionTableHeader
33 ->getMarkAttachClassDefinitionTable(theGlyphDefinitionTableHeader, success);
b75a7d8f
A
34 }
35
374ca955
A
36 nextLimit = glyphCount;
37
b75a7d8f
A
38 if (rightToLeft) {
39 direction = -1;
374ca955 40 position = glyphCount;
b75a7d8f 41 nextLimit = -1;
374ca955 42 prevLimit = glyphCount;
b75a7d8f 43 }
57a6839d 44 filterResetCache();
b75a7d8f
A
45}
46
47GlyphIterator::GlyphIterator(GlyphIterator &that)
374ca955 48 : glyphStorage(that.glyphStorage)
b75a7d8f
A
49{
50 direction = that.direction;
51 position = that.position;
52 nextLimit = that.nextLimit;
53 prevLimit = that.prevLimit;
54
b75a7d8f 55 glyphPositionAdjustments = that.glyphPositionAdjustments;
374ca955
A
56 srcIndex = that.srcIndex;
57 destIndex = that.destIndex;
b75a7d8f 58 lookupFlags = that.lookupFlags;
73c04bcf 59 featureMask = that.featureMask;
46f4442e 60 glyphGroup = that.glyphGroup;
b75a7d8f
A
61 glyphClassDefinitionTable = that.glyphClassDefinitionTable;
62 markAttachClassDefinitionTable = that.markAttachClassDefinitionTable;
57a6839d 63 filterResetCache();
b75a7d8f
A
64}
65
73c04bcf 66GlyphIterator::GlyphIterator(GlyphIterator &that, FeatureMask newFeatureMask)
374ca955 67 : glyphStorage(that.glyphStorage)
b75a7d8f
A
68{
69 direction = that.direction;
70 position = that.position;
71 nextLimit = that.nextLimit;
72 prevLimit = that.prevLimit;
73
b75a7d8f 74 glyphPositionAdjustments = that.glyphPositionAdjustments;
374ca955
A
75 srcIndex = that.srcIndex;
76 destIndex = that.destIndex;
b75a7d8f 77 lookupFlags = that.lookupFlags;
73c04bcf 78 featureMask = newFeatureMask;
46f4442e 79 glyphGroup = 0;
b75a7d8f
A
80 glyphClassDefinitionTable = that.glyphClassDefinitionTable;
81 markAttachClassDefinitionTable = that.markAttachClassDefinitionTable;
57a6839d 82 filterResetCache();
b75a7d8f
A
83}
84
85GlyphIterator::GlyphIterator(GlyphIterator &that, le_uint16 newLookupFlags)
374ca955 86 : glyphStorage(that.glyphStorage)
b75a7d8f
A
87{
88 direction = that.direction;
89 position = that.position;
90 nextLimit = that.nextLimit;
91 prevLimit = that.prevLimit;
92
b75a7d8f 93 glyphPositionAdjustments = that.glyphPositionAdjustments;
374ca955
A
94 srcIndex = that.srcIndex;
95 destIndex = that.destIndex;
b75a7d8f 96 lookupFlags = newLookupFlags;
73c04bcf 97 featureMask = that.featureMask;
46f4442e 98 glyphGroup = that.glyphGroup;
b75a7d8f
A
99 glyphClassDefinitionTable = that.glyphClassDefinitionTable;
100 markAttachClassDefinitionTable = that.markAttachClassDefinitionTable;
57a6839d 101 filterResetCache();
b75a7d8f
A
102}
103
374ca955 104GlyphIterator::~GlyphIterator()
b75a7d8f 105{
374ca955
A
106 // nothing to do, right?
107}
b75a7d8f 108
73c04bcf 109void GlyphIterator::reset(le_uint16 newLookupFlags, FeatureMask newFeatureMask)
374ca955 110{
73c04bcf
A
111 position = prevLimit;
112 featureMask = newFeatureMask;
46f4442e 113 glyphGroup = 0;
73c04bcf 114 lookupFlags = newLookupFlags;
57a6839d 115 filterResetCache();
374ca955
A
116}
117
729e4ab9 118LEGlyphID *GlyphIterator::insertGlyphs(le_int32 count, LEErrorCode& success)
374ca955 119{
729e4ab9 120 return glyphStorage.insertGlyphs(position, count, success);
374ca955
A
121}
122
123le_int32 GlyphIterator::applyInsertions()
b75a7d8f 124{
374ca955
A
125 le_int32 newGlyphCount = glyphStorage.applyInsertions();
126
127 if (direction < 0) {
128 prevLimit = newGlyphCount;
129 } else {
130 nextLimit = newGlyphCount;
131 }
132
133 return newGlyphCount;
b75a7d8f
A
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
b75a7d8f
A
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
374ca955 168 return glyphStorage[position];
b75a7d8f
A
169}
170
73c04bcf 171void GlyphIterator::getCursiveEntryPoint(LEPoint &entryPoint) const
b75a7d8f
A
172{
173 if (direction < 0) {
73c04bcf 174 if (position <= nextLimit || position >= prevLimit) {
b75a7d8f
A
175 return;
176 }
177 } else {
178 if (position <= prevLimit || position >= nextLimit) {
179 return;
180 }
181 }
182
73c04bcf 183 glyphPositionAdjustments->getEntryPoint(position, entryPoint);
b75a7d8f
A
184}
185
73c04bcf 186void GlyphIterator::getCursiveExitPoint(LEPoint &exitPoint) const
b75a7d8f 187{
73c04bcf
A
188 if (direction < 0) {
189 if (position <= nextLimit || position >= prevLimit) {
b75a7d8f
A
190 return;
191 }
192 } else {
73c04bcf 193 if (position <= prevLimit || position >= nextLimit) {
b75a7d8f
A
194 return;
195 }
196 }
197
73c04bcf 198 glyphPositionAdjustments->getExitPoint(position, exitPoint);
b75a7d8f
A
199}
200
201void GlyphIterator::setCurrGlyphID(TTGlyphID glyphID)
202{
374ca955
A
203 LEGlyphID glyph = glyphStorage[position];
204
205 glyphStorage[position] = LE_SET_GLYPH(glyph, glyphID);
b75a7d8f
A
206}
207
208void GlyphIterator::setCurrStreamPosition(le_int32 newPosition)
209{
b75a7d8f
A
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
b75a7d8f
A
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
73c04bcf 248 glyphPositionAdjustments->setBaseOffset(position, baseOffset);
b75a7d8f
A
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
73c04bcf
A
264 glyphPositionAdjustments->adjustXPlacement(position, xPlacementAdjust);
265 glyphPositionAdjustments->adjustYPlacement(position, yPlacementAdjust);
266 glyphPositionAdjustments->adjustXAdvance(position, xAdvanceAdjust);
267 glyphPositionAdjustments->adjustYAdvance(position, yAdvanceAdjust);
b75a7d8f
A
268}
269
374ca955
A
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
73c04bcf
A
283 glyphPositionAdjustments->setXPlacement(position, xPlacementAdjust);
284 glyphPositionAdjustments->setYPlacement(position, yPlacementAdjust);
285 glyphPositionAdjustments->setXAdvance(position, xAdvanceAdjust);
286 glyphPositionAdjustments->setYAdvance(position, yAdvanceAdjust);
374ca955
A
287}
288
46f4442e
A
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
73c04bcf 319void GlyphIterator::setCursiveEntryPoint(LEPoint &entryPoint)
b75a7d8f
A
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
73c04bcf 331 glyphPositionAdjustments->setEntryPoint(position, entryPoint, baselineIsLogicalEnd());
b75a7d8f
A
332}
333
73c04bcf 334void GlyphIterator::setCursiveExitPoint(LEPoint &exitPoint)
b75a7d8f
A
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
73c04bcf 346 glyphPositionAdjustments->setExitPoint(position, exitPoint, baselineIsLogicalEnd());
b75a7d8f
A
347}
348
73c04bcf 349void GlyphIterator::setCursiveGlyph()
b75a7d8f
A
350{
351 if (direction < 0) {
73c04bcf 352 if (position <= nextLimit || position >= prevLimit) {
b75a7d8f
A
353 return;
354 }
355 } else {
73c04bcf 356 if (position <= prevLimit || position >= nextLimit) {
b75a7d8f
A
357 return;
358 }
359 }
360
73c04bcf 361 glyphPositionAdjustments->setCursiveGlyph(position, baselineIsLogicalEnd());
b75a7d8f
A
362}
363
57a6839d
A
364void GlyphIterator::filterResetCache(void) {
365 filterCacheValid = FALSE;
366}
367
368le_bool GlyphIterator::filterGlyph(le_uint32 index)
b75a7d8f 369{
374ca955 370 LEGlyphID glyphID = glyphStorage[index];
b75a7d8f 371
57a6839d
A
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);
b75a7d8f 384 }
57a6839d
A
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;
b75a7d8f 420 }
57a6839d
A
421 }
422 filterCacheValid = TRUE;
b75a7d8f 423 }
57a6839d
A
424
425 return filterCache.result;
b75a7d8f
A
426}
427
46f4442e 428le_bool GlyphIterator::hasFeatureTag(le_bool matchGroup) const
b75a7d8f 429{
73c04bcf 430 if (featureMask == 0) {
374ca955 431 return TRUE;
b75a7d8f
A
432 }
433
374ca955 434 LEErrorCode success = LE_NO_ERROR;
73c04bcf 435 FeatureMask fm = glyphStorage.getAuxData(position, success);
b75a7d8f 436
46f4442e 437 return ((fm & featureMask) == featureMask) && (!matchGroup || (le_int32)(fm & LE_GLYPH_GROUP_MASK) == glyphGroup);
b75a7d8f
A
438}
439
440le_bool GlyphIterator::findFeatureTag()
441{
46f4442e
A
442 //glyphGroup = 0;
443
b75a7d8f 444 while (nextInternal()) {
46f4442e
A
445 if (hasFeatureTag(FALSE)) {
446 LEErrorCode success = LE_NO_ERROR;
447
448 glyphGroup = (glyphStorage.getAuxData(position, success) & LE_GLYPH_GROUP_MASK);
374ca955 449 return TRUE;
b75a7d8f
A
450 }
451 }
452
374ca955 453 return FALSE;
b75a7d8f
A
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;
57a6839d 464 //fprintf(stderr,"%s:%d:%s: newPosition = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, newPosition, delta);
b75a7d8f
A
465 } while (newPosition != nextLimit && filterGlyph(newPosition));
466
467 delta -= 1;
468 }
469
470 position = newPosition;
471
57a6839d 472 //fprintf(stderr,"%s:%d:%s: exit position = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, position, delta);
b75a7d8f
A
473 return position != nextLimit;
474}
475
476le_bool GlyphIterator::next(le_uint32 delta)
477{
46f4442e 478 return nextInternal(delta) && hasFeatureTag(TRUE);
b75a7d8f
A
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;
57a6839d 488 //fprintf(stderr,"%s:%d:%s: newPosition = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, newPosition, delta);
b75a7d8f
A
489 } while (newPosition != prevLimit && filterGlyph(newPosition));
490
491 delta -= 1;
492 }
493
494 position = newPosition;
495
57a6839d 496 //fprintf(stderr,"%s:%d:%s: exit position = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, position, delta);
b75a7d8f
A
497 return position != prevLimit;
498}
499
500le_bool GlyphIterator::prev(le_uint32 delta)
501{
46f4442e 502 return prevInternal(delta) && hasFeatureTag(TRUE);
b75a7d8f
A
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) {
374ca955 511 if (glyphStorage[posn] == 0xFFFE) {
b75a7d8f
A
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;
374ca955 528 } while (newPosition != prevLimit && glyphStorage[newPosition] != 0xFFFE && filterGlyph(newPosition));
b75a7d8f
A
529
530 position = newPosition;
531
532 return position != prevLimit;
533}
534
535U_NAMESPACE_END