Aric Stewart : usp10: Implement GSUB Context Substitution types 1 and 2.
Alexandre Julliard
julliard at winehq.org
Wed Jan 25 13:18:53 CST 2017
Module: wine
Branch: master
Commit: 5e6b2c0ed6c57fa98d1d6003bf234bebe049a34a
URL: http://source.winehq.org/git/wine.git/?a=commit;h=5e6b2c0ed6c57fa98d1d6003bf234bebe049a34a
Author: Aric Stewart <aric at codeweavers.com>
Date: Wed Jan 25 07:14:52 2017 -0600
usp10: Implement GSUB Context Substitution types 1 and 2.
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 | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 192 insertions(+)
diff --git a/dlls/usp10/opentype.c b/dlls/usp10/opentype.c
index d7afbe1..29ec503 100644
--- a/dlls/usp10/opentype.c
+++ b/dlls/usp10/opentype.c
@@ -238,6 +238,51 @@ typedef struct{
}GSUB_SubstLookupRecord;
typedef struct{
+ WORD SubstFormat;
+ WORD Coverage;
+ WORD SubRuleSetCount;
+ WORD SubRuleSet[1];
+}GSUB_ContextSubstFormat1;
+
+typedef struct{
+ WORD SubRuleCount;
+ WORD SubRule[1];
+}GSUB_SubRuleSet;
+
+typedef struct {
+ WORD GlyphCount;
+ WORD SubstCount;
+ WORD Input[1];
+}GSUB_SubRule_1;
+
+typedef struct {
+ GSUB_SubstLookupRecord SubstLookupRecord[1];
+}GSUB_SubRule_2;
+
+typedef struct {
+ WORD SubstFormat;
+ WORD Coverage;
+ WORD ClassDef;
+ WORD SubClassSetCnt;
+ WORD SubClassSet[1];
+}GSUB_ContextSubstFormat2;
+
+typedef struct {
+ WORD SubClassRuleCnt;
+ WORD SubClassRule[1];
+}GSUB_SubClassSet;
+
+typedef struct {
+ WORD GlyphCount;
+ WORD SubstCount;
+ WORD Class[1];
+}GSUB_SubClassRule_1;
+
+typedef struct {
+ GSUB_SubstLookupRecord SubstLookupRecord[1];
+}GSUB_SubClassRule_2;
+
+typedef struct{
WORD SubstFormat; /* = 1 */
WORD Coverage;
WORD ChainSubRuleSetCount;
@@ -940,6 +985,151 @@ static INT GSUB_apply_LigatureSubst(const OT_LookupTable *look, WORD *glyphs, IN
return GSUB_E_NOGLYPH;
}
+static INT GSUB_apply_ContextSubst(const OT_LookupList* lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+ int j;
+ TRACE("Context Substitution Subtable\n");
+ for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
+ {
+ const GSUB_ContextSubstFormat1 *csf1;
+
+ csf1 = (const GSUB_ContextSubstFormat1*)GSUB_get_subtable(look, j);
+ if (GET_BE_WORD(csf1->SubstFormat) == 1)
+ {
+ int offset, index;
+ TRACE("Context Substitution Subtable: Class 1\n");
+ offset = GET_BE_WORD(csf1->Coverage);
+ index = GSUB_is_glyph_covered((const BYTE*)csf1+offset, glyphs[glyph_index]);
+ TRACE(" Coverage index %i\n",index);
+ if (index != -1)
+ {
+ int k, count;
+ const GSUB_SubRuleSet *srs;
+ offset = GET_BE_WORD(csf1->SubRuleSet[index]);
+ srs = (const GSUB_SubRuleSet*)((const BYTE*)csf1+offset);
+ count = GET_BE_WORD(srs->SubRuleCount);
+ TRACE(" SubRuleSet has %i members\n",count);
+ for (k = 0; k < count; k++)
+ {
+ const GSUB_SubRule_1 *sr;
+ const GSUB_SubRule_2 *sr_2;
+ int g_count, l;
+ int newIndex = glyph_index;
+
+ offset = GET_BE_WORD(srs->SubRule[k]);
+ sr = (const GSUB_SubRule_1*)((const BYTE*)srs+offset);
+ g_count = GET_BE_WORD(sr->GlyphCount);
+ TRACE(" SubRule has %i glyphs\n",g_count);
+ for (l = 0; l < g_count-1; l++)
+ if (glyphs[glyph_index + (write_dir * (l+1))] != GET_BE_WORD(sr->Input[l])) break;
+
+ if (l < g_count-1)
+ {
+ TRACE(" Rule does not match\n");
+ continue;
+ }
+
+ TRACE(" Rule matches\n");
+ sr_2 = (const GSUB_SubRule_2*)((const BYTE*)sr+
+ FIELD_OFFSET(GSUB_SubRule_1, Input[g_count-1]));
+
+ for (l = 0; l < GET_BE_WORD(sr->SubstCount); l++)
+ {
+ int lookupIndex = GET_BE_WORD(sr_2->SubstLookupRecord[l].LookupListIndex);
+ int SequenceIndex = GET_BE_WORD(sr_2->SubstLookupRecord[l].SequenceIndex) * write_dir;
+
+ TRACE(" SUBST: %i -> %i %i\n",l, 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 if (GET_BE_WORD(csf1->SubstFormat) == 2)
+ {
+ const GSUB_ContextSubstFormat2 *csf2;
+ const void *glyph_class_table;
+ int offset, index;
+
+ csf2 = (const GSUB_ContextSubstFormat2*)csf1;
+ TRACE("Context Substitution Subtable: Class 2\n");
+ offset = GET_BE_WORD(csf2->Coverage);
+ index = GSUB_is_glyph_covered((const BYTE*)csf2+offset, glyphs[glyph_index]);
+ TRACE(" Coverage index %i\n",index);
+ if (index != -1)
+ {
+ int k, count, class;
+ const GSUB_SubClassSet *scs;
+
+ offset = GET_BE_WORD(csf2->ClassDef);
+ glyph_class_table = (const BYTE *)csf2 + offset;
+
+ class = OT_get_glyph_class(glyph_class_table,glyphs[glyph_index]);
+
+ offset = GET_BE_WORD(csf2->SubClassSet[class]);
+ if (offset == 0)
+ {
+ TRACE(" No class rule table for class %i\n",class);
+ continue;
+ }
+ scs = (const GSUB_SubClassSet*)((const BYTE*)csf2+offset);
+ count = GET_BE_WORD(scs->SubClassRuleCnt);
+ TRACE(" SubClassSet has %i members\n",count);
+ for (k = 0; k < count; k++)
+ {
+ const GSUB_SubClassRule_1 *sr;
+ const GSUB_SubClassRule_2 *sr_2;
+ int g_count, l;
+ int newIndex = glyph_index;
+
+ offset = GET_BE_WORD(scs->SubClassRule[k]);
+ sr = (const GSUB_SubClassRule_1*)((const BYTE*)scs+offset);
+ g_count = GET_BE_WORD(sr->GlyphCount);
+ TRACE(" SubClassRule has %i glyphs classes\n",g_count);
+ for (l = 0; l < g_count-1; l++)
+ {
+ int g_class = OT_get_glyph_class(glyph_class_table, glyphs[glyph_index + (write_dir * (l+1))]);
+ if (g_class != GET_BE_WORD(sr->Class[l])) break;
+ }
+
+ if (l < g_count-1)
+ {
+ TRACE(" Rule does not match\n");
+ continue;
+ }
+
+ TRACE(" Rule matches\n");
+ sr_2 = (const GSUB_SubClassRule_2*)((const BYTE*)sr+
+ FIELD_OFFSET(GSUB_SubClassRule_1, Class[g_count-1]));
+
+ for (l = 0; l < GET_BE_WORD(sr->SubstCount); l++)
+ {
+ int lookupIndex = GET_BE_WORD(sr_2->SubstLookupRecord[l].LookupListIndex);
+ int SequenceIndex = GET_BE_WORD(sr_2->SubstLookupRecord[l].SequenceIndex) * write_dir;
+
+ TRACE(" SUBST: %i -> %i %i\n",l, 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
+ FIXME("Unhandled Context Substitution Format %i\n", GET_BE_WORD(csf1->SubstFormat));
+ }
+ return GSUB_E_NOGLYPH;
+}
+
static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
{
int j;
@@ -1084,6 +1274,8 @@ static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD
return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
case 4:
return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
+ case 5:
+ return GSUB_apply_ContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
case 6:
return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
case 7:
More information about the wine-cvs
mailing list