Module: wine Branch: master Commit: aae5a831e2e76e39b76464ba921dded7c2fbf9e2 URL: http://source.winehq.org/git/wine.git/?a=commit;h=aae5a831e2e76e39b76464ba92...
Author: Aric Stewart aric@codeweavers.com Date: Wed Jan 25 07:17:38 2017 -0600
usp10: Implement Chaining Context Substitution Format 2: Class-based Chaining Context Glyph Substitution.
Used by the font Noto Nastaliq Urdu.
Signed-off-by: Aric Stewart aric@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/usp10/opentype.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 151 insertions(+), 4 deletions(-)
diff --git a/dlls/usp10/opentype.c b/dlls/usp10/opentype.c index 90df479..d2eb749 100644 --- a/dlls/usp10/opentype.c +++ b/dlls/usp10/opentype.c @@ -290,6 +290,41 @@ typedef struct{ }GSUB_ChainContextSubstFormat1;
typedef struct { + WORD SubstFormat; /* = 2 */ + WORD Coverage; + WORD BacktrackClassDef; + WORD InputClassDef; + WORD LookaheadClassDef; + WORD ChainSubClassSetCnt; + WORD ChainSubClassSet[1]; +}GSUB_ChainContextSubstFormat2; + +typedef struct { + WORD ChainSubClassRuleCnt; + WORD ChainSubClassRule[1]; +}GSUB_ChainSubClassSet; + +typedef struct { + WORD BacktrackGlyphCount; + WORD Backtrack[1]; +}GSUB_ChainSubClassRule_1; + +typedef struct { + WORD InputGlyphCount; + WORD Input[1]; +}GSUB_ChainSubClassRule_2; + +typedef struct { + WORD LookaheadGlyphCount; + WORD LookAhead[1]; +}GSUB_ChainSubClassRule_3; + +typedef struct { + WORD SubstCount; + GSUB_SubstLookupRecord SubstLookupRecord[1]; +}GSUB_ChainSubClassRule_4; + +typedef struct { WORD SubstFormat; /* = 3 */ WORD BacktrackGlyphCount; WORD Coverage[1]; @@ -1175,10 +1210,122 @@ static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_Lo } else if (GET_BE_WORD(ccsf1->SubstFormat) == 2) { - static int once; - if (!once++) - FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n"); - continue; + int newIndex = glyph_index; + WORD offset, count; + const void *backtrack_class_table; + const void *input_class_table; + const void *lookahead_class_table; + int i; + WORD class; + + const GSUB_ChainContextSubstFormat2 *ccsf2 = (const GSUB_ChainContextSubstFormat2*)ccsf1; + const GSUB_ChainSubClassSet *csc; + + TRACE(" subtype 2 (Class-based Chaining Context Glyph Substitution)\n"); + + offset = GET_BE_WORD(ccsf2->Coverage); + + if (GSUB_is_glyph_covered((const BYTE*)ccsf2+offset, glyphs[glyph_index]) == -1) + { + TRACE("Glyph not covered\n"); + continue; + } + offset = GET_BE_WORD(ccsf2->BacktrackClassDef); + backtrack_class_table = (const BYTE*)ccsf2+offset; + offset = GET_BE_WORD(ccsf2->InputClassDef); + input_class_table = (const BYTE*)ccsf2+offset; + offset = GET_BE_WORD(ccsf2->LookaheadClassDef); + lookahead_class_table = (const BYTE*)ccsf2+offset; + count = GET_BE_WORD(ccsf2->ChainSubClassSetCnt); + + class = OT_get_glyph_class(input_class_table, glyphs[glyph_index]); + offset = GET_BE_WORD(ccsf2->ChainSubClassSet[class]); + + if (offset == 0) + { + TRACE("No rules for class\n"); + continue; + } + + csc = (const GSUB_ChainSubClassSet*)((BYTE*)ccsf2+offset); + count = GET_BE_WORD(csc->ChainSubClassRuleCnt); + + TRACE("%i rules to check\n",count); + + for (i = 0; i < count; i++) + { + int k; + int indexGlyphs; + const GSUB_ChainSubClassRule_1 *cscr_1; + const GSUB_ChainSubClassRule_2 *cscr_2; + const GSUB_ChainSubClassRule_3 *cscr_3; + const GSUB_ChainSubClassRule_4 *cscr_4; + + offset = GET_BE_WORD(csc->ChainSubClassRule[i]); + cscr_1 = (const GSUB_ChainSubClassRule_1*)((BYTE*)csc+offset); + + for (k = 0; k < GET_BE_WORD(cscr_1->BacktrackGlyphCount); k++) + { + WORD target_class = GET_BE_WORD(cscr_1->Backtrack[k]); + WORD glyph_class = OT_get_glyph_class(backtrack_class_table, glyphs[glyph_index + (dirBacktrack * (k+1))]); + if (target_class != glyph_class) + break; + } + if (k != GET_BE_WORD(cscr_1->BacktrackGlyphCount)) + continue; + TRACE("Matched Backtrack\n"); + + cscr_2 = (const GSUB_ChainSubClassRule_2*)((BYTE *)cscr_1 + + FIELD_OFFSET(GSUB_ChainSubClassRule_1, Backtrack[GET_BE_WORD(cscr_1->BacktrackGlyphCount)])); + + indexGlyphs = GET_BE_WORD(cscr_2->InputGlyphCount); + for (k = 0; k < indexGlyphs - 1; k++) + { + WORD target_class = GET_BE_WORD(cscr_2->Input[k]); + WORD glyph_class = OT_get_glyph_class(input_class_table, glyphs[glyph_index + (write_dir * (k+1))]); + if (target_class != glyph_class) + break; + } + if (k != indexGlyphs-1) + continue; + TRACE("Matched IndexGlyphs\n"); + + cscr_3 = (const GSUB_ChainSubClassRule_3*)((BYTE *)cscr_2 + + FIELD_OFFSET(GSUB_ChainSubClassRule_2, Input[GET_BE_WORD(cscr_2->InputGlyphCount)-1])); + + for (k = 0; k < GET_BE_WORD(cscr_3->LookaheadGlyphCount); k++) + { + WORD target_class = GET_BE_WORD(cscr_3->LookAhead[k]); + WORD glyph_class = OT_get_glyph_class(lookahead_class_table, glyphs[glyph_index + (dirLookahead * (indexGlyphs+k))]); + if (target_class != glyph_class) + break; + } + if (k != GET_BE_WORD(cscr_3->LookaheadGlyphCount)) + continue; + TRACE("Matched LookAhead\n"); + + cscr_4 = (const GSUB_ChainSubClassRule_4*)((BYTE *)cscr_3 + + FIELD_OFFSET(GSUB_ChainSubClassRule_3, LookAhead[GET_BE_WORD(cscr_3->LookaheadGlyphCount)])); + + if (GET_BE_WORD(cscr_4->SubstCount)) + { + for (k = 0; k < GET_BE_WORD(cscr_4->SubstCount); k++) + { + int lookupIndex = GET_BE_WORD(cscr_4->SubstLookupRecord[k].LookupListIndex); + int SequenceIndex = GET_BE_WORD(cscr_4->SubstLookupRecord[k].SequenceIndex) * write_dir; + + TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex); + newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count); + if (newIndex == -1) + { + ERR("Chain failed to generate a glyph\n"); + continue; + } + } + return newIndex; + } + else return GSUB_E_NOGLYPH; + } } else if (GET_BE_WORD(ccsf1->SubstFormat) == 3) {