]> git.saurik.com Git - apple/icu.git/blob - icuSources/layout/ContextualSubstSubtables.cpp
ICU-491.11.1.tar.gz
[apple/icu.git] / icuSources / layout / ContextualSubstSubtables.cpp
1 /*
2 * (C) Copyright IBM Corp. 1998-2008 - 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 */
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
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
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
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 const CoverageTable *coverageTable = (const CoverageTable *) (offsetBase + coverageTableOffset);
132
133 if (! glyphIterator->next()) {
134 return FALSE;
135 }
136
137 if (coverageTable->getGlyphCoverage((LEGlyphID) glyphIterator->getCurrGlyphID()) < 0) {
138 return FALSE;
139 }
140
141 glyphCount -= 1;
142 glyph += direction;
143 }
144
145 return TRUE;
146 }
147
148 le_uint32 ContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor,
149 GlyphIterator *glyphIterator,
150 const LEFontInstance *fontInstance,
151 LEErrorCode& success) const
152 {
153 if (LE_FAILURE(success)) {
154 return 0;
155 }
156
157 switch(SWAPW(subtableFormat))
158 {
159 case 0:
160 return 0;
161
162 case 1:
163 {
164 const ContextualSubstitutionFormat1Subtable *subtable = (const ContextualSubstitutionFormat1Subtable *) this;
165 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
166 }
167
168 case 2:
169 {
170 const ContextualSubstitutionFormat2Subtable *subtable = (const ContextualSubstitutionFormat2Subtable *) this;
171 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
172 }
173
174 case 3:
175 {
176 const ContextualSubstitutionFormat3Subtable *subtable = (const ContextualSubstitutionFormat3Subtable *) this;
177 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
178 }
179
180 default:
181 return 0;
182 }
183 }
184
185 le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor,
186 GlyphIterator *glyphIterator,
187 const LEFontInstance *fontInstance,
188 LEErrorCode& success) const
189 {
190 if (LE_FAILURE(success)) {
191 return 0;
192 }
193
194 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
195 le_int32 coverageIndex = getGlyphCoverage(glyph);
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
219 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
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
234 le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor,
235 GlyphIterator *glyphIterator,
236 const LEFontInstance *fontInstance,
237 LEErrorCode& success) const
238 {
239 if (LE_FAILURE(success)) {
240 return 0;
241 }
242
243 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
244 le_int32 coverageIndex = getGlyphCoverage(glyph);
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
271 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
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
286 le_uint32 ContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor,
287 GlyphIterator *glyphIterator,
288 const LEFontInstance *fontInstance,
289 LEErrorCode& success)const
290 {
291 if (LE_FAILURE(success)) {
292 return 0;
293 }
294
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
309 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, subCount, glyphIterator, fontInstance, position, success);
310
311 return gCount + 1;
312 }
313
314 glyphIterator->setCurrStreamPosition(position);
315
316 return 0;
317 }
318
319 le_uint32 ChainingContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor,
320 GlyphIterator *glyphIterator,
321 const LEFontInstance *fontInstance,
322 LEErrorCode& success) const
323 {
324 if (LE_FAILURE(success)) {
325 return 0;
326 }
327
328 switch(SWAPW(subtableFormat))
329 {
330 case 0:
331 return 0;
332
333 case 1:
334 {
335 const ChainingContextualSubstitutionFormat1Subtable *subtable = (const ChainingContextualSubstitutionFormat1Subtable *) this;
336 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
337 }
338
339 case 2:
340 {
341 const ChainingContextualSubstitutionFormat2Subtable *subtable = (const ChainingContextualSubstitutionFormat2Subtable *) this;
342 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
343 }
344
345 case 3:
346 {
347 const ChainingContextualSubstitutionFormat3Subtable *subtable = (const ChainingContextualSubstitutionFormat3Subtable *) this;
348 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
349 }
350
351 default:
352 return 0;
353 }
354 }
355
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...
360 static const FeatureMask emptyFeatureList = 0x00000000UL;
361
362 le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor,
363 GlyphIterator *glyphIterator,
364 const LEFontInstance *fontInstance,
365 LEErrorCode& success) const
366 {
367 if (LE_FAILURE(success)) {
368 return 0;
369 }
370
371 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
372 le_int32 coverageIndex = getGlyphCoverage(glyph);
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();
383 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
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();
404 if (! matchGlyphIDs(chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) {
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
418 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
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
433 le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor,
434 GlyphIterator *glyphIterator,
435 const LEFontInstance *fontInstance,
436 LEErrorCode& success) const
437 {
438 if (LE_FAILURE(success)) {
439 return 0;
440 }
441
442 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
443 le_int32 coverageIndex = getGlyphCoverage(glyph);
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();
461 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
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);
469 le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1;
470 const le_uint16 *inputClassArray = &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1];
471 le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray[inputGlyphCount]);
472 const le_uint16 *lookaheadClassArray = &inputClassArray[inputGlyphCount + 1];
473 le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]);
474
475
476 tempIterator.setCurrStreamPosition(position);
477
478 if (! tempIterator.prev(backtrackGlyphCount)) {
479 continue;
480 }
481
482 tempIterator.prev();
483 if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount,
484 &tempIterator, backtrackClassDefinitionTable, TRUE)) {
485 continue;
486 }
487
488 tempIterator.setCurrStreamPosition(position);
489 tempIterator.next(inputGlyphCount);
490 if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) {
491 continue;
492 }
493
494 if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) {
495 const SubstitutionLookupRecord *substLookupRecordArray =
496 (const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1];
497
498 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
499
500 return inputGlyphCount + 1;
501 }
502
503 glyphIterator->setCurrStreamPosition(position);
504 }
505 }
506
507 // XXX If we get here, the table is mal-formed...
508 }
509
510 return 0;
511 }
512
513 le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor,
514 GlyphIterator *glyphIterator,
515 const LEFontInstance *fontInstance,
516 LEErrorCode & success) const
517 {
518 if (LE_FAILURE(success)) {
519 return 0;
520 }
521
522 le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount);
523 le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]);
524 const Offset *inputCoverageTableOffsetArray = &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1];
525 const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]);
526 const Offset *lookaheadCoverageTableOffsetArray = &inputCoverageTableOffsetArray[inputGlyphCount + 1];
527 le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]);
528 le_int32 position = glyphIterator->getCurrStreamPosition();
529 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
530
531 if (! tempIterator.prev(backtrkGlyphCount)) {
532 return 0;
533 }
534
535 tempIterator.prev();
536 if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray,
537 backtrkGlyphCount, &tempIterator, (const char *) this, TRUE)) {
538 return 0;
539 }
540
541 tempIterator.setCurrStreamPosition(position);
542 tempIterator.next(inputGlyphCount - 1);
543 if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray,
544 lookaheadGlyphCount, &tempIterator, (const char *) this)) {
545 return 0;
546 }
547
548 // Back up the glyph iterator so that we
549 // can call next() before the check, which
550 // will leave it pointing at the last glyph
551 // that matched when we're done.
552 glyphIterator->prev();
553
554 if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray,
555 inputGlyphCount, glyphIterator, (const char *) this)) {
556 const SubstitutionLookupRecord *substLookupRecordArray =
557 (const SubstitutionLookupRecord *) &lookaheadCoverageTableOffsetArray[lookaheadGlyphCount + 1];
558
559 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
560
561 return inputGlyphCount;
562 }
563
564 glyphIterator->setCurrStreamPosition(position);
565
566 return 0;
567 }
568
569 U_NAMESPACE_END