]> git.saurik.com Git - apple/icu.git/blame - icuSources/layout/ContextualSubstSubtables.cpp
ICU-59180.0.1.tar.gz
[apple/icu.git] / icuSources / layout / ContextualSubstSubtables.cpp
CommitLineData
b75a7d8f 1/*
b331163b 2 * (C) Copyright IBM Corp. 1998-2015 - All Rights Reserved
b75a7d8f
A
3 *
4 */
5
6#include "LETypes.h"
7#include "LEFontInstance.h"
8#include "OpenTypeTables.h"
9#include "GlyphSubstitutionTables.h"
10#include "ContextualSubstSubtables.h"
11#include "GlyphIterator.h"
12#include "LookupProcessor.h"
13#include "CoverageTables.h"
14#include "LESwaps.h"
15
16U_NAMESPACE_BEGIN
17
18/*
19 NOTE: This could be optimized somewhat by keeping track
20 of the previous sequenceIndex in the loop and doing next()
21 or prev() of the delta between that and the current
22 sequenceIndex instead of always resetting to the front.
23*/
24void ContextualSubstitutionBase::applySubstitutionLookups(
25 const LookupProcessor *lookupProcessor,
26 const SubstitutionLookupRecord *substLookupRecordArray,
27 le_uint16 substCount,
28 GlyphIterator *glyphIterator,
29 const LEFontInstance *fontInstance,
729e4ab9
A
30 le_int32 position,
31 LEErrorCode& success)
b75a7d8f 32{
729e4ab9
A
33 if (LE_FAILURE(success)) {
34 return;
35 }
36
b75a7d8f
A
37 GlyphIterator tempIterator(*glyphIterator);
38
729e4ab9 39 for (le_int16 subst = 0; subst < substCount && LE_SUCCESS(success); subst += 1) {
b75a7d8f
A
40 le_uint16 sequenceIndex = SWAPW(substLookupRecordArray[subst].sequenceIndex);
41 le_uint16 lookupListIndex = SWAPW(substLookupRecordArray[subst].lookupListIndex);
42
43 tempIterator.setCurrStreamPosition(position);
44 tempIterator.next(sequenceIndex);
45
729e4ab9 46 lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator, fontInstance, success);
b75a7d8f
A
47 }
48}
49
50le_bool ContextualSubstitutionBase::matchGlyphIDs(const TTGlyphID *glyphArray, le_uint16 glyphCount,
51 GlyphIterator *glyphIterator, le_bool backtrack)
52{
53 le_int32 direction = 1;
54 le_int32 match = 0;
55
56 if (backtrack) {
57 match = glyphCount -1;
58 direction = -1;
59 }
60
61 while (glyphCount > 0) {
62 if (! glyphIterator->next()) {
374ca955 63 return FALSE;
b75a7d8f
A
64 }
65
66 TTGlyphID glyph = (TTGlyphID) glyphIterator->getCurrGlyphID();
67
68 if (glyph != SWAPW(glyphArray[match])) {
374ca955 69 return FALSE;
b75a7d8f
A
70 }
71
72 glyphCount -= 1;
73 match += direction;
74 }
75
374ca955 76 return TRUE;
b75a7d8f
A
77}
78
79le_bool ContextualSubstitutionBase::matchGlyphClasses(const le_uint16 *classArray, le_uint16 glyphCount,
80 GlyphIterator *glyphIterator,
81 const ClassDefinitionTable *classDefinitionTable,
82 le_bool backtrack)
83{
84 le_int32 direction = 1;
85 le_int32 match = 0;
86
87 if (backtrack) {
88 match = glyphCount - 1;
89 direction = -1;
90 }
91
92 while (glyphCount > 0) {
93 if (! glyphIterator->next()) {
374ca955 94 return FALSE;
b75a7d8f
A
95 }
96
97 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
98 le_int32 glyphClass = classDefinitionTable->getGlyphClass(glyph);
99 le_int32 matchClass = SWAPW(classArray[match]);
100
101 if (glyphClass != matchClass) {
102 // Some fonts, e.g. Traditional Arabic, have classes
103 // in the class array which aren't in the class definition
104 // table. If we're looking for such a class, pretend that
105 // we found it.
106 if (classDefinitionTable->hasGlyphClass(matchClass)) {
374ca955 107 return FALSE;
b75a7d8f
A
108 }
109 }
110
111 glyphCount -= 1;
112 match += direction;
113 }
114
374ca955 115 return TRUE;
b75a7d8f
A
116}
117
118le_bool ContextualSubstitutionBase::matchGlyphCoverages(const Offset *coverageTableOffsetArray, le_uint16 glyphCount,
119 GlyphIterator *glyphIterator, const char *offsetBase, le_bool backtrack)
120{
121 le_int32 direction = 1;
122 le_int32 glyph = 0;
123
124 if (backtrack) {
125 glyph = glyphCount - 1;
126 direction = -1;
127 }
128
129 while (glyphCount > 0) {
130 Offset coverageTableOffset = SWAPW(coverageTableOffsetArray[glyph]);
131 const CoverageTable *coverageTable = (const CoverageTable *) (offsetBase + coverageTableOffset);
132
133 if (! glyphIterator->next()) {
374ca955 134 return FALSE;
b75a7d8f
A
135 }
136
137 if (coverageTable->getGlyphCoverage((LEGlyphID) glyphIterator->getCurrGlyphID()) < 0) {
374ca955 138 return FALSE;
b75a7d8f
A
139 }
140
141 glyphCount -= 1;
142 glyph += direction;
143 }
144
374ca955 145 return TRUE;
b75a7d8f
A
146}
147
729e4ab9
A
148le_uint32 ContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor,
149 GlyphIterator *glyphIterator,
150 const LEFontInstance *fontInstance,
151 LEErrorCode& success) const
b75a7d8f 152{
729e4ab9
A
153 if (LE_FAILURE(success)) {
154 return 0;
155 }
156
b75a7d8f
A
157 switch(SWAPW(subtableFormat))
158 {
159 case 0:
160 return 0;
161
162 case 1:
163 {
164 const ContextualSubstitutionFormat1Subtable *subtable = (const ContextualSubstitutionFormat1Subtable *) this;
729e4ab9 165 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
b75a7d8f
A
166 }
167
168 case 2:
169 {
170 const ContextualSubstitutionFormat2Subtable *subtable = (const ContextualSubstitutionFormat2Subtable *) this;
729e4ab9 171 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
b75a7d8f
A
172 }
173
174 case 3:
175 {
176 const ContextualSubstitutionFormat3Subtable *subtable = (const ContextualSubstitutionFormat3Subtable *) this;
729e4ab9 177 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
b75a7d8f
A
178 }
179
180 default:
181 return 0;
182 }
183}
184
729e4ab9
A
185le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor,
186 GlyphIterator *glyphIterator,
187 const LEFontInstance *fontInstance,
188 LEErrorCode& success) const
b75a7d8f 189{
729e4ab9
A
190 if (LE_FAILURE(success)) {
191 return 0;
192 }
193
b75a7d8f 194 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
57a6839d 195 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);
b75a7d8f
A
196
197 if (coverageIndex >= 0) {
198 le_uint16 srSetCount = SWAPW(subRuleSetCount);
199
200 if (coverageIndex < srSetCount) {
201 Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]);
202 const SubRuleSetTable *subRuleSetTable =
203 (const SubRuleSetTable *) ((char *) this + subRuleSetTableOffset);
204 le_uint16 subRuleCount = SWAPW(subRuleSetTable->subRuleCount);
205 le_int32 position = glyphIterator->getCurrStreamPosition();
206
207 for (le_uint16 subRule = 0; subRule < subRuleCount; subRule += 1) {
208 Offset subRuleTableOffset =
209 SWAPW(subRuleSetTable->subRuleTableOffsetArray[subRule]);
210 const SubRuleTable *subRuleTable =
211 (const SubRuleTable *) ((char *) subRuleSetTable + subRuleTableOffset);
212 le_uint16 matchCount = SWAPW(subRuleTable->glyphCount) - 1;
213 le_uint16 substCount = SWAPW(subRuleTable->substCount);
214
215 if (matchGlyphIDs(subRuleTable->inputGlyphArray, matchCount, glyphIterator)) {
216 const SubstitutionLookupRecord *substLookupRecordArray =
217 (const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount];
218
729e4ab9 219 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
b75a7d8f
A
220
221 return matchCount + 1;
222 }
223
224 glyphIterator->setCurrStreamPosition(position);
225 }
226 }
227
228 // XXX If we get here, the table is mal-formed...
229 }
230
231 return 0;
232}
233
729e4ab9
A
234le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor,
235 GlyphIterator *glyphIterator,
236 const LEFontInstance *fontInstance,
237 LEErrorCode& success) const
b75a7d8f 238{
729e4ab9
A
239 if (LE_FAILURE(success)) {
240 return 0;
241 }
242
b75a7d8f 243 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
57a6839d 244 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);
b75a7d8f
A
245
246 if (coverageIndex >= 0) {
247 const ClassDefinitionTable *classDefinitionTable =
248 (const ClassDefinitionTable *) ((char *) this + SWAPW(classDefTableOffset));
249 le_uint16 scSetCount = SWAPW(subClassSetCount);
250 le_int32 setClass = classDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID());
251
252 if (setClass < scSetCount && subClassSetTableOffsetArray[setClass] != 0) {
253 Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]);
254 const SubClassSetTable *subClassSetTable =
255 (const SubClassSetTable *) ((char *) this + subClassSetTableOffset);
256 le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount);
257 le_int32 position = glyphIterator->getCurrStreamPosition();
258
259 for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) {
260 Offset subClassRuleTableOffset =
261 SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]);
262 const SubClassRuleTable *subClassRuleTable =
263 (const SubClassRuleTable *) ((char *) subClassSetTable + subClassRuleTableOffset);
264 le_uint16 matchCount = SWAPW(subClassRuleTable->glyphCount) - 1;
265 le_uint16 substCount = SWAPW(subClassRuleTable->substCount);
266
267 if (matchGlyphClasses(subClassRuleTable->classArray, matchCount, glyphIterator, classDefinitionTable)) {
268 const SubstitutionLookupRecord *substLookupRecordArray =
269 (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount];
270
729e4ab9 271 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
b75a7d8f
A
272
273 return matchCount + 1;
274 }
275
276 glyphIterator->setCurrStreamPosition(position);
277 }
278 }
279
280 // XXX If we get here, the table is mal-formed...
281 }
282
283 return 0;
284}
285
729e4ab9
A
286le_uint32 ContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor,
287 GlyphIterator *glyphIterator,
288 const LEFontInstance *fontInstance,
289 LEErrorCode& success)const
b75a7d8f 290{
729e4ab9
A
291 if (LE_FAILURE(success)) {
292 return 0;
293 }
294
b75a7d8f
A
295 le_uint16 gCount = SWAPW(glyphCount);
296 le_uint16 subCount = SWAPW(substCount);
297 le_int32 position = glyphIterator->getCurrStreamPosition();
298
299 // Back up the glyph iterator so that we
300 // can call next() before the check, which
301 // will leave it pointing at the last glyph
302 // that matched when we're done.
303 glyphIterator->prev();
304
305 if (ContextualSubstitutionBase::matchGlyphCoverages(coverageTableOffsetArray, gCount, glyphIterator, (const char *) this)) {
306 const SubstitutionLookupRecord *substLookupRecordArray =
307 (const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount];
308
729e4ab9 309 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, subCount, glyphIterator, fontInstance, position, success);
b75a7d8f
A
310
311 return gCount + 1;
312 }
313
314 glyphIterator->setCurrStreamPosition(position);
315
316 return 0;
317}
318
729e4ab9
A
319le_uint32 ChainingContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor,
320 GlyphIterator *glyphIterator,
321 const LEFontInstance *fontInstance,
322 LEErrorCode& success) const
b75a7d8f 323{
729e4ab9
A
324 if (LE_FAILURE(success)) {
325 return 0;
326 }
327
b75a7d8f
A
328 switch(SWAPW(subtableFormat))
329 {
330 case 0:
331 return 0;
332
333 case 1:
334 {
335 const ChainingContextualSubstitutionFormat1Subtable *subtable = (const ChainingContextualSubstitutionFormat1Subtable *) this;
729e4ab9 336 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
b75a7d8f
A
337 }
338
339 case 2:
340 {
341 const ChainingContextualSubstitutionFormat2Subtable *subtable = (const ChainingContextualSubstitutionFormat2Subtable *) this;
729e4ab9 342 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
b75a7d8f
A
343 }
344
345 case 3:
346 {
347 const ChainingContextualSubstitutionFormat3Subtable *subtable = (const ChainingContextualSubstitutionFormat3Subtable *) this;
729e4ab9 348 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
b75a7d8f
A
349 }
350
351 default:
352 return 0;
353 }
354}
355
73c04bcf
A
356// NOTE: This could be a #define, but that seems to confuse
357// the Visual Studio .NET 2003 compiler on the calls to the
358// GlyphIterator constructor. It somehow can't decide if
359// emptyFeatureList matches an le_uint32 or an le_uint16...
360static const FeatureMask emptyFeatureList = 0x00000000UL;
b75a7d8f 361
729e4ab9
A
362le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor,
363 GlyphIterator *glyphIterator,
364 const LEFontInstance *fontInstance,
365 LEErrorCode& success) const
b75a7d8f 366{
729e4ab9
A
367 if (LE_FAILURE(success)) {
368 return 0;
369 }
370
b75a7d8f 371 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
57a6839d 372 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);
b75a7d8f
A
373
374 if (coverageIndex >= 0) {
375 le_uint16 srSetCount = SWAPW(chainSubRuleSetCount);
376
377 if (coverageIndex < srSetCount) {
378 Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]);
379 const ChainSubRuleSetTable *chainSubRuleSetTable =
380 (const ChainSubRuleSetTable *) ((char *) this + chainSubRuleSetTableOffset);
381 le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount);
382 le_int32 position = glyphIterator->getCurrStreamPosition();
73c04bcf 383 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
b75a7d8f
A
384
385 for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) {
386 Offset chainSubRuleTableOffset =
387 SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]);
388 const ChainSubRuleTable *chainSubRuleTable =
389 (const ChainSubRuleTable *) ((char *) chainSubRuleSetTable + chainSubRuleTableOffset);
390 le_uint16 backtrackGlyphCount = SWAPW(chainSubRuleTable->backtrackGlyphCount);
391 le_uint16 inputGlyphCount = (le_uint16) SWAPW(chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount]) - 1;
392 const TTGlyphID *inputGlyphArray = &chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount + 1];
393 le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputGlyphArray[inputGlyphCount]);
394 const TTGlyphID *lookaheadGlyphArray = &inputGlyphArray[inputGlyphCount + 1];
395 le_uint16 substCount = (le_uint16) SWAPW(lookaheadGlyphArray[lookaheadGlyphCount]);
396
397 tempIterator.setCurrStreamPosition(position);
398
399 if (! tempIterator.prev(backtrackGlyphCount)) {
400 continue;
401 }
402
403 tempIterator.prev();
374ca955 404 if (! matchGlyphIDs(chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) {
b75a7d8f
A
405 continue;
406 }
407
408 tempIterator.setCurrStreamPosition(position);
409 tempIterator.next(inputGlyphCount);
410 if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) {
411 continue;
412 }
413
414 if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) {
415 const SubstitutionLookupRecord *substLookupRecordArray =
416 (const SubstitutionLookupRecord *) &lookaheadGlyphArray[lookaheadGlyphCount + 1];
417
729e4ab9 418 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
b75a7d8f
A
419
420 return inputGlyphCount + 1;
421 }
422
423 glyphIterator->setCurrStreamPosition(position);
424 }
425 }
426
427 // XXX If we get here, the table is mal-formed...
428 }
429
430 return 0;
431}
432
729e4ab9
A
433le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor,
434 GlyphIterator *glyphIterator,
435 const LEFontInstance *fontInstance,
436 LEErrorCode& success) const
b75a7d8f 437{
729e4ab9
A
438 if (LE_FAILURE(success)) {
439 return 0;
440 }
441
b75a7d8f 442 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
57a6839d 443 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);
b75a7d8f
A
444
445 if (coverageIndex >= 0) {
446 const ClassDefinitionTable *backtrackClassDefinitionTable =
447 (const ClassDefinitionTable *) ((char *) this + SWAPW(backtrackClassDefTableOffset));
448 const ClassDefinitionTable *inputClassDefinitionTable =
449 (const ClassDefinitionTable *) ((char *) this + SWAPW(inputClassDefTableOffset));
450 const ClassDefinitionTable *lookaheadClassDefinitionTable =
451 (const ClassDefinitionTable *) ((char *) this + SWAPW(lookaheadClassDefTableOffset));
452 le_uint16 scSetCount = SWAPW(chainSubClassSetCount);
453 le_int32 setClass = inputClassDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID());
454
455 if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) {
456 Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]);
457 const ChainSubClassSetTable *chainSubClassSetTable =
458 (const ChainSubClassSetTable *) ((char *) this + chainSubClassSetTableOffset);
459 le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount);
460 le_int32 position = glyphIterator->getCurrStreamPosition();
73c04bcf 461 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
b75a7d8f
A
462
463 for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) {
464 Offset chainSubClassRuleTableOffset =
465 SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]);
466 const ChainSubClassRuleTable *chainSubClassRuleTable =
467 (const ChainSubClassRuleTable *) ((char *) chainSubClassSetTable + chainSubClassRuleTableOffset);
468 le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount);
b331163b
A
469
470 // TODO: Ticket #11557 - enable this check, originally from ticket #11525.
471 // Depends on other, more extensive, changes.
472 // LEReferenceToArrayOf<le_uint16> backtrackClassArray(base, success, chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount);
473 if( LE_FAILURE(success) ) { return 0; }
474
b75a7d8f
A
475 le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1;
476 const le_uint16 *inputClassArray = &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1];
477 le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray[inputGlyphCount]);
478 const le_uint16 *lookaheadClassArray = &inputClassArray[inputGlyphCount + 1];
479 le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]);
480
481
482 tempIterator.setCurrStreamPosition(position);
483
484 if (! tempIterator.prev(backtrackGlyphCount)) {
485 continue;
486 }
487
488 tempIterator.prev();
489 if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount,
374ca955 490 &tempIterator, backtrackClassDefinitionTable, TRUE)) {
b75a7d8f
A
491 continue;
492 }
493
494 tempIterator.setCurrStreamPosition(position);
495 tempIterator.next(inputGlyphCount);
496 if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) {
497 continue;
498 }
499
500 if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) {
501 const SubstitutionLookupRecord *substLookupRecordArray =
502 (const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1];
503
729e4ab9 504 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
b75a7d8f
A
505
506 return inputGlyphCount + 1;
507 }
508
509 glyphIterator->setCurrStreamPosition(position);
510 }
511 }
512
513 // XXX If we get here, the table is mal-formed...
514 }
515
516 return 0;
517}
518
729e4ab9
A
519le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor,
520 GlyphIterator *glyphIterator,
521 const LEFontInstance *fontInstance,
522 LEErrorCode & success) const
b75a7d8f 523{
729e4ab9
A
524 if (LE_FAILURE(success)) {
525 return 0;
526 }
527
b75a7d8f
A
528 le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount);
529 le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]);
530 const Offset *inputCoverageTableOffsetArray = &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1];
531 const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]);
532 const Offset *lookaheadCoverageTableOffsetArray = &inputCoverageTableOffsetArray[inputGlyphCount + 1];
533 le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]);
534 le_int32 position = glyphIterator->getCurrStreamPosition();
73c04bcf 535 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
b75a7d8f
A
536
537 if (! tempIterator.prev(backtrkGlyphCount)) {
538 return 0;
539 }
540
541 tempIterator.prev();
542 if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray,
374ca955 543 backtrkGlyphCount, &tempIterator, (const char *) this, TRUE)) {
b75a7d8f
A
544 return 0;
545 }
546
547 tempIterator.setCurrStreamPosition(position);
548 tempIterator.next(inputGlyphCount - 1);
549 if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray,
550 lookaheadGlyphCount, &tempIterator, (const char *) this)) {
551 return 0;
552 }
553
554 // Back up the glyph iterator so that we
555 // can call next() before the check, which
556 // will leave it pointing at the last glyph
557 // that matched when we're done.
558 glyphIterator->prev();
559
560 if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray,
561 inputGlyphCount, glyphIterator, (const char *) this)) {
562 const SubstitutionLookupRecord *substLookupRecordArray =
563 (const SubstitutionLookupRecord *) &lookaheadCoverageTableOffsetArray[lookaheadGlyphCount + 1];
564
729e4ab9 565 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
b75a7d8f
A
566
567 return inputGlyphCount;
568 }
569
570 glyphIterator->setCurrStreamPosition(position);
571
572 return 0;
573}
574
575U_NAMESPACE_END