Aric Stewart : usp10: Implement Chaining Context Substitution Format 2: Class-based Chaining Context Glyph Substitution.
Alexandre Julliard
julliard at winehq.org
Wed Jan 25 13:18:53 CST 2017
Module: wine
Branch: master
Commit: aae5a831e2e76e39b76464ba921dded7c2fbf9e2
URL: http://source.winehq.org/git/wine.git/?a=commit;h=aae5a831e2e76e39b76464ba921dded7c2fbf9e2
Author: Aric Stewart <aric at 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 at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at 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)
{
More information about the wine-cvs
mailing list