]>
Commit | Line | Data |
---|---|---|
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 | ||
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, | |
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 | ||
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()) { | |
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 | ||
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()) { | |
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 | ||
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()) { | |
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 |
148 | le_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 |
185 | le_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 |
234 | le_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 |
286 | le_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 |
319 | le_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... | |
360 | static const FeatureMask emptyFeatureList = 0x00000000UL; | |
b75a7d8f | 361 | |
729e4ab9 A |
362 | le_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 |
433 | le_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 |
519 | le_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 | ||
575 | U_NAMESPACE_END |