1 /*
2 * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved
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
16 U_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 */
applySubstitutionLookups(const LookupProcessor * lookupProcessor,const SubstitutionLookupRecord * substLookupRecordArray,le_uint16 substCount,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,le_int32 position,LEErrorCode & success)24 void ContextualSubstitutionBase::applySubstitutionLookups(
25 const LookupProcessor *lookupProcessor,
26 const SubstitutionLookupRecord *substLookupRecordArray,
27 le_uint16 substCount,
28 GlyphIterator *glyphIterator,
29 const LEFontInstance *fontInstance,
30 le_int32 position,
31 LEErrorCode& success)
32 {
33 if (LE_FAILURE(success)) {
34 return;
35 }
36
37 GlyphIterator tempIterator(*glyphIterator);
38
39 for (le_int16 subst = 0; subst < substCount && LE_SUCCESS(success); subst += 1) {
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
46 lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator, fontInstance, success);
47 }
48 }
49
matchGlyphIDs(const TTGlyphID * glyphArray,le_uint16 glyphCount,GlyphIterator * glyphIterator,le_bool backtrack)50 le_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()) {
63 return FALSE;
64 }
65
66 TTGlyphID glyph = (TTGlyphID) glyphIterator->getCurrGlyphID();
67
68 if (glyph != SWAPW(glyphArray[match])) {
69 return FALSE;
70 }
71
72 glyphCount -= 1;
73 match += direction;
74 }
75
76 return TRUE;
77 }
78
matchGlyphClasses(const le_uint16 * classArray,le_uint16 glyphCount,GlyphIterator * glyphIterator,const ClassDefinitionTable * classDefinitionTable,le_bool backtrack)79 le_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()) {
94 return FALSE;
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)) {
107 return FALSE;
108 }
109 }
110
111 glyphCount -= 1;
112 match += direction;
113 }
114
115 return TRUE;
116 }
117
matchGlyphCoverages(const Offset * coverageTableOffsetArray,le_uint16 glyphCount,GlyphIterator * glyphIterator,const char * offsetBase,le_bool backtrack)118 le_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 /* Google patch: Behdad says: Unsafe dereference follows. */
132 const CoverageTable *coverageTable = (const CoverageTable *) (offsetBase + coverageTableOffset);
133
134 if (! glyphIterator->next()) {
135 return FALSE;
136 }
137
138 if (coverageTable->getGlyphCoverage((LEGlyphID) glyphIterator->getCurrGlyphID()) < 0) {
139 return FALSE;
140 }
141
142 glyphCount -= 1;
143 glyph += direction;
144 }
145
146 return TRUE;
147 }
148
process(const LookupProcessor * lookupProcessor,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const149 le_uint32 ContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor,
150 GlyphIterator *glyphIterator,
151 const LEFontInstance *fontInstance,
152 LEErrorCode& success) const
153 {
154 if (LE_FAILURE(success)) {
155 return 0;
156 }
157
158 switch(SWAPW(subtableFormat))
159 {
160 case 0:
161 return 0;
162
163 /* Google patch: Behdad says: Unsafe downcasts follow. */
164
165 case 1:
166 {
167 const ContextualSubstitutionFormat1Subtable *subtable = (const ContextualSubstitutionFormat1Subtable *) this;
168 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
169 }
170
171 case 2:
172 {
173 const ContextualSubstitutionFormat2Subtable *subtable = (const ContextualSubstitutionFormat2Subtable *) this;
174 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
175 }
176
177 case 3:
178 {
179 const ContextualSubstitutionFormat3Subtable *subtable = (const ContextualSubstitutionFormat3Subtable *) this;
180 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
181 }
182
183 default:
184 return 0;
185 }
186 }
187
process(const LookupProcessor * lookupProcessor,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const188 le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor,
189 GlyphIterator *glyphIterator,
190 const LEFontInstance *fontInstance,
191 LEErrorCode& success) const
192 {
193 if (LE_FAILURE(success)) {
194 return 0;
195 }
196
197 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
198 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);
199
200 if (coverageIndex >= 0) {
201 le_uint16 srSetCount = SWAPW(subRuleSetCount);
202
203 if (coverageIndex < srSetCount) {
204 Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]);
205 /* Google patch: Behdad says: Unsafe dereference follows. */
206 const SubRuleSetTable *subRuleSetTable =
207 (const SubRuleSetTable *) ((char *) this + subRuleSetTableOffset);
208 le_uint16 subRuleCount = SWAPW(subRuleSetTable->subRuleCount);
209 le_int32 position = glyphIterator->getCurrStreamPosition();
210
211 for (le_uint16 subRule = 0; subRule < subRuleCount; subRule += 1) {
212 Offset subRuleTableOffset =
213 SWAPW(subRuleSetTable->subRuleTableOffsetArray[subRule]);
214 const SubRuleTable *subRuleTable =
215 (const SubRuleTable *) ((char *) subRuleSetTable + subRuleTableOffset);
216 le_uint16 matchCount = SWAPW(subRuleTable->glyphCount) - 1;
217 le_uint16 substCount = SWAPW(subRuleTable->substCount);
218
219 if (matchGlyphIDs(subRuleTable->inputGlyphArray, matchCount, glyphIterator)) {
220 const SubstitutionLookupRecord *substLookupRecordArray =
221 (const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount];
222
223 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
224
225 return matchCount + 1;
226 }
227
228 glyphIterator->setCurrStreamPosition(position);
229 }
230 }
231
232 // XXX If we get here, the table is mal-formed...
233 }
234
235 return 0;
236 }
237
process(const LookupProcessor * lookupProcessor,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const238 le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor,
239 GlyphIterator *glyphIterator,
240 const LEFontInstance *fontInstance,
241 LEErrorCode& success) const
242 {
243 if (LE_FAILURE(success)) {
244 return 0;
245 }
246
247 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
248 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);
249
250 if (coverageIndex >= 0) {
251 /* Google patch: Behdad says: Unsafe dereference follows. */
252 const ClassDefinitionTable *classDefinitionTable =
253 (const ClassDefinitionTable *) ((char *) this + SWAPW(classDefTableOffset));
254 le_uint16 scSetCount = SWAPW(subClassSetCount);
255 le_int32 setClass = classDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID());
256
257 if (setClass < scSetCount && subClassSetTableOffsetArray[setClass] != 0) {
258 Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]);
259 /* Google patch: Behdad says: Unsafe dereference follows. */
260 const SubClassSetTable *subClassSetTable =
261 (const SubClassSetTable *) ((char *) this + subClassSetTableOffset);
262 le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount);
263 le_int32 position = glyphIterator->getCurrStreamPosition();
264
265 for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) {
266 Offset subClassRuleTableOffset =
267 SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]);
268 const SubClassRuleTable *subClassRuleTable =
269 (const SubClassRuleTable *) ((char *) subClassSetTable + subClassRuleTableOffset);
270 le_uint16 matchCount = SWAPW(subClassRuleTable->glyphCount) - 1;
271 le_uint16 substCount = SWAPW(subClassRuleTable->substCount);
272
273 if (matchGlyphClasses(subClassRuleTable->classArray, matchCount, glyphIterator, classDefinitionTable)) {
274 const SubstitutionLookupRecord *substLookupRecordArray =
275 (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount];
276
277 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
278
279 return matchCount + 1;
280 }
281
282 glyphIterator->setCurrStreamPosition(position);
283 }
284 }
285
286 // XXX If we get here, the table is mal-formed...
287 }
288
289 return 0;
290 }
291
process(const LookupProcessor * lookupProcessor,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const292 le_uint32 ContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor,
293 GlyphIterator *glyphIterator,
294 const LEFontInstance *fontInstance,
295 LEErrorCode& success)const
296 {
297 if (LE_FAILURE(success)) {
298 return 0;
299 }
300
301 le_uint16 gCount = SWAPW(glyphCount);
302 le_uint16 subCount = SWAPW(substCount);
303 le_int32 position = glyphIterator->getCurrStreamPosition();
304
305 // Back up the glyph iterator so that we
306 // can call next() before the check, which
307 // will leave it pointing at the last glyph
308 // that matched when we're done.
309 glyphIterator->prev();
310
311 if (ContextualSubstitutionBase::matchGlyphCoverages(coverageTableOffsetArray, gCount, glyphIterator, (const char *) this)) {
312 const SubstitutionLookupRecord *substLookupRecordArray =
313 (const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount];
314
315 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, subCount, glyphIterator, fontInstance, position, success);
316
317 return gCount + 1;
318 }
319
320 glyphIterator->setCurrStreamPosition(position);
321
322 return 0;
323 }
324
process(const LookupProcessor * lookupProcessor,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const325 le_uint32 ChainingContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor,
326 GlyphIterator *glyphIterator,
327 const LEFontInstance *fontInstance,
328 LEErrorCode& success) const
329 {
330 if (LE_FAILURE(success)) {
331 return 0;
332 }
333
334 switch(SWAPW(subtableFormat))
335 {
336 case 0:
337 return 0;
338
339 /* Google patch: Behdad says: Unsafe downcasts follow. */
340
341 case 1:
342 {
343 const ChainingContextualSubstitutionFormat1Subtable *subtable = (const ChainingContextualSubstitutionFormat1Subtable *) this;
344 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
345 }
346
347 case 2:
348 {
349 const ChainingContextualSubstitutionFormat2Subtable *subtable = (const ChainingContextualSubstitutionFormat2Subtable *) this;
350 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
351 }
352
353 case 3:
354 {
355 const ChainingContextualSubstitutionFormat3Subtable *subtable = (const ChainingContextualSubstitutionFormat3Subtable *) this;
356 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
357 }
358
359 default:
360 return 0;
361 }
362 }
363
364 // NOTE: This could be a #define, but that seems to confuse
365 // the Visual Studio .NET 2003 compiler on the calls to the
366 // GlyphIterator constructor. It somehow can't decide if
367 // emptyFeatureList matches an le_uint32 or an le_uint16...
368 static const FeatureMask emptyFeatureList = 0x00000000UL;
369
process(const LookupProcessor * lookupProcessor,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const370 le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor,
371 GlyphIterator *glyphIterator,
372 const LEFontInstance *fontInstance,
373 LEErrorCode& success) const
374 {
375 if (LE_FAILURE(success)) {
376 return 0;
377 }
378
379 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
380 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);
381
382 if (coverageIndex >= 0) {
383 le_uint16 srSetCount = SWAPW(chainSubRuleSetCount);
384
385 if (coverageIndex < srSetCount) {
386 Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]);
387 /* Google patch: Behdad says: Unsafe dereference follows. */
388 const ChainSubRuleSetTable *chainSubRuleSetTable =
389 (const ChainSubRuleSetTable *) ((char *) this + chainSubRuleSetTableOffset);
390 le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount);
391 le_int32 position = glyphIterator->getCurrStreamPosition();
392 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
393
394 for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) {
395 Offset chainSubRuleTableOffset =
396 SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]);
397 const ChainSubRuleTable *chainSubRuleTable =
398 (const ChainSubRuleTable *) ((char *) chainSubRuleSetTable + chainSubRuleTableOffset);
399 le_uint16 backtrackGlyphCount = SWAPW(chainSubRuleTable->backtrackGlyphCount);
400 le_uint16 inputGlyphCount = (le_uint16) SWAPW(chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount]) - 1;
401 const TTGlyphID *inputGlyphArray = &chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount + 1];
402 le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputGlyphArray[inputGlyphCount]);
403 const TTGlyphID *lookaheadGlyphArray = &inputGlyphArray[inputGlyphCount + 1];
404 le_uint16 substCount = (le_uint16) SWAPW(lookaheadGlyphArray[lookaheadGlyphCount]);
405
406 tempIterator.setCurrStreamPosition(position);
407
408 if (! tempIterator.prev(backtrackGlyphCount)) {
409 continue;
410 }
411
412 tempIterator.prev();
413 if (! matchGlyphIDs(chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) {
414 continue;
415 }
416
417 tempIterator.setCurrStreamPosition(position);
418 tempIterator.next(inputGlyphCount);
419 if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) {
420 continue;
421 }
422
423 if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) {
424 const SubstitutionLookupRecord *substLookupRecordArray =
425 (const SubstitutionLookupRecord *) &lookaheadGlyphArray[lookaheadGlyphCount + 1];
426
427 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
428
429 return inputGlyphCount + 1;
430 }
431
432 glyphIterator->setCurrStreamPosition(position);
433 }
434 }
435
436 // XXX If we get here, the table is mal-formed...
437 }
438
439 return 0;
440 }
441
process(const LookupProcessor * lookupProcessor,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const442 le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor,
443 GlyphIterator *glyphIterator,
444 const LEFontInstance *fontInstance,
445 LEErrorCode& success) const
446 {
447 if (LE_FAILURE(success)) {
448 return 0;
449 }
450
451 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
452 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);
453
454 if (coverageIndex >= 0) {
455 /* Google patch: Behdad says: Unsafe dereferences follow. */
456 const ClassDefinitionTable *backtrackClassDefinitionTable =
457 (const ClassDefinitionTable *) ((char *) this + SWAPW(backtrackClassDefTableOffset));
458 const ClassDefinitionTable *inputClassDefinitionTable =
459 (const ClassDefinitionTable *) ((char *) this + SWAPW(inputClassDefTableOffset));
460 const ClassDefinitionTable *lookaheadClassDefinitionTable =
461 (const ClassDefinitionTable *) ((char *) this + SWAPW(lookaheadClassDefTableOffset));
462 le_uint16 scSetCount = SWAPW(chainSubClassSetCount);
463 le_int32 setClass = inputClassDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID());
464
465 if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) {
466 Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]);
467 /* Google patch: Behdad says: Unsafe dereference follows. */
468 const ChainSubClassSetTable *chainSubClassSetTable =
469 (const ChainSubClassSetTable *) ((char *) this + chainSubClassSetTableOffset);
470 le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount);
471 le_int32 position = glyphIterator->getCurrStreamPosition();
472 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
473
474 for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) {
475 Offset chainSubClassRuleTableOffset =
476 SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]);
477 const ChainSubClassRuleTable *chainSubClassRuleTable =
478 (const ChainSubClassRuleTable *) ((char *) chainSubClassSetTable + chainSubClassRuleTableOffset);
479 le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount);
480 le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1;
481 const le_uint16 *inputClassArray = &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1];
482 le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray[inputGlyphCount]);
483 const le_uint16 *lookaheadClassArray = &inputClassArray[inputGlyphCount + 1];
484 le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]);
485
486
487 tempIterator.setCurrStreamPosition(position);
488
489 if (! tempIterator.prev(backtrackGlyphCount)) {
490 continue;
491 }
492
493 tempIterator.prev();
494 if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount,
495 &tempIterator, backtrackClassDefinitionTable, TRUE)) {
496 continue;
497 }
498
499 tempIterator.setCurrStreamPosition(position);
500 tempIterator.next(inputGlyphCount);
501 if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) {
502 continue;
503 }
504
505 if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) {
506 const SubstitutionLookupRecord *substLookupRecordArray =
507 (const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1];
508
509 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
510
511 return inputGlyphCount + 1;
512 }
513
514 glyphIterator->setCurrStreamPosition(position);
515 }
516 }
517
518 // XXX If we get here, the table is mal-formed...
519 }
520
521 return 0;
522 }
523
process(const LookupProcessor * lookupProcessor,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const524 le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor,
525 GlyphIterator *glyphIterator,
526 const LEFontInstance *fontInstance,
527 LEErrorCode & success) const
528 {
529 if (LE_FAILURE(success)) {
530 return 0;
531 }
532
533 le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount);
534 le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]);
535 const Offset *inputCoverageTableOffsetArray = &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1];
536 const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]);
537 const Offset *lookaheadCoverageTableOffsetArray = &inputCoverageTableOffsetArray[inputGlyphCount + 1];
538 le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]);
539 le_int32 position = glyphIterator->getCurrStreamPosition();
540 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
541
542 if (! tempIterator.prev(backtrkGlyphCount)) {
543 return 0;
544 }
545
546 tempIterator.prev();
547 if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray,
548 backtrkGlyphCount, &tempIterator, (const char *) this, TRUE)) {
549 return 0;
550 }
551
552 tempIterator.setCurrStreamPosition(position);
553 tempIterator.next(inputGlyphCount - 1);
554 if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray,
555 lookaheadGlyphCount, &tempIterator, (const char *) this)) {
556 return 0;
557 }
558
559 // Back up the glyph iterator so that we
560 // can call next() before the check, which
561 // will leave it pointing at the last glyph
562 // that matched when we're done.
563 glyphIterator->prev();
564
565 if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray,
566 inputGlyphCount, glyphIterator, (const char *) this)) {
567 const SubstitutionLookupRecord *substLookupRecordArray =
568 (const SubstitutionLookupRecord *) &lookaheadCoverageTableOffsetArray[lookaheadGlyphCount + 1];
569
570 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
571
572 return inputGlyphCount;
573 }
574
575 glyphIterator->setCurrStreamPosition(position);
576
577 return 0;
578 }
579
580 U_NAMESPACE_END
581