[USP10] Sync with Wine Staging 2.2. CORE-12823
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 19 Mar 2017 16:53:04 +0000 (16:53 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 19 Mar 2017 16:53:04 +0000 (16:53 +0000)
d00f731 usp10: Itemise ZWSP like ZWNJ and ZWJ.
721fbf6 usp10: Explicitly check for zero-width control characters in ScriptShapeOpenType().
7e6a4b2 usp10: Fix LB27 rule that should check for prefix, not suffix.
c4626bb usp10: Fixed LB30 condition, breaking after CP class.
0c14195 usp10: Apply 'ccmp' before Arabic contextual shaping.
e2d4cf9 usp10: Fix next index for RTL MultipleSubst.
0401bdf usp10: Change GSUB_E_NOGLYPH value.
10e9adf usp10: Fix Contextual Shaping for Languages with RTL write order.
961e1e6 usp10: Fix ScriptRecordDigitSubstitution spec file entry.
aae5a83 usp10: Implement Chaining Context Substitution Format 2: Class-based Chaining Context Glyph Substitution.
b98a70a usp10: Implement Contextual Positioning Subtable: Format 2.
5e6b2c0 usp10: Implement GSUB Context Substitution types 1 and 2.
c705eca usp10: A spelling fix in a comment.

svn path=/trunk/; revision=74193

reactos/dll/win32/usp10/breaking.c
reactos/dll/win32/usp10/opentype.c
reactos/dll/win32/usp10/shape.c
reactos/dll/win32/usp10/usp10.c
reactos/dll/win32/usp10/usp10.spec
reactos/dll/win32/usp10/usp10_internal.h
reactos/media/doc/README.WINE

index 641dff4..a46b1e3 100644 (file)
@@ -371,7 +371,7 @@ void BREAK_line(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT
                     if (break_class[i+1] == b_IN || break_class[i+1] == b_PO)
                         else_break(&break_before[i+1],b_x);
             }
-            if (break_class[i] == b_PO)
+            if (break_class[i] == b_PR)
             {
                 switch (break_class[i+1])
                 {
@@ -401,7 +401,7 @@ void BREAK_line(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT
                  break_class[i+1] == b_OP)
                 else_break(&break_before[i+1],b_x);
             if (break_class[i] == b_CP &&
-                (break_class[i+1] == b_AL || break_class[i] == b_HL || break_class[i] == b_NU))
+                (break_class[i+1] == b_AL || break_class[i+1] == b_HL || break_class[i+1] == b_NU))
                 else_break(&break_before[i+1],b_x);
 
             /* LB30a */
index 83f0ffc..b836803 100644 (file)
@@ -227,6 +227,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;
@@ -234,6 +279,41 @@ typedef struct{
     WORD ChainSubRuleSet[1];
 }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;
@@ -454,6 +534,29 @@ typedef struct {
     WORD LookupListIndex;
 } GPOS_PosLookupRecord;
 
+typedef struct {
+    WORD PosFormat;
+    WORD Coverage;
+    WORD ClassDef;
+    WORD PosClassSetCnt;
+    WORD PosClassSet[1];
+} GPOS_ContextPosFormat2;
+
+typedef struct {
+    WORD PosClassRuleCnt;
+    WORD PosClassRule[1];
+} GPOS_PosClassSet;
+
+typedef struct {
+    WORD GlyphCount;
+    WORD PosCount;
+    WORD Class[1];
+} GPOS_PosClassRule_1;
+
+typedef struct {
+    GPOS_PosLookupRecord PosLookupRecord[1];
+} GPOS_PosClassRule_2;
+
 typedef struct {
     WORD PosFormat;
     WORD BacktrackGlyphCount;
@@ -827,7 +930,10 @@ static INT GSUB_apply_MultipleSubst(const OT_LookupTable *look, WORD *glyphs, IN
                 TRACE("\n");
             }
 
-            return glyph_index + (sub_count * write_dir);
+            if (write_dir > 0)
+                return glyph_index + sub_count;
+            else
+                return glyph_index - 1;
         }
     }
     return GSUB_E_NOGLYPH;
@@ -930,6 +1036,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 == GSUB_E_NOGLYPH)
+                        {
+                            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 == GSUB_E_NOGLYPH)
+                        {
+                            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;
@@ -952,10 +1203,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 == GSUB_E_NOGLYPH)
+                        {
+                            ERR("Chain failed to generate a glyph\n");
+                            continue;
+                        }
+                    }
+                    return newIndex;
+                }
+                else return GSUB_E_NOGLYPH;
+            }
         }
         else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
         {
@@ -1020,7 +1383,7 @@ static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_Lo
 
                     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)
+                    if (newIndex == GSUB_E_NOGLYPH)
                     {
                         ERR("Chain failed to generate a glyph\n");
                         continue;
@@ -1031,7 +1394,7 @@ static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_Lo
             else return GSUB_E_NOGLYPH;
         }
     }
-    return -1;
+    return GSUB_E_NOGLYPH;
 }
 
 static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
@@ -1074,6 +1437,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:
@@ -1667,6 +2032,109 @@ static BOOL GPOS_apply_MarkToMark(const OT_LookupTable *look, const SCRIPT_ANALY
     return rc;
 }
 
+static INT GPOS_apply_ContextPos(ScriptCache *psc, LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, const SCRIPT_ANALYSIS *analysis, INT* piAdvance,
+                                      const OT_LookupList *lookup, const OT_LookupTable *look, const WORD *glyphs, INT glyph_index,
+                                      INT glyph_count, INT ppem, GOFFSET *pGoffset)
+{
+    int j;
+    int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
+
+    TRACE("Contextual Positioning Subtable\n");
+
+    for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
+    {
+        const GPOS_ContextPosFormat2 *cpf2 = (GPOS_ContextPosFormat2*)GPOS_get_subtable(look, j);
+
+        if (GET_BE_WORD(cpf2->PosFormat) == 1)
+        {
+            static int once;
+            if (!once++)
+                FIXME("  TODO: subtype 1\n");
+            continue;
+        }
+        else if (GET_BE_WORD(cpf2->PosFormat) == 2)
+        {
+            WORD offset = GET_BE_WORD(cpf2->Coverage);
+            int index;
+
+            TRACE("Contextual Positioning Subtable: Format 2\n");
+
+            index = GSUB_is_glyph_covered((const BYTE*)cpf2+offset, glyphs[glyph_index]);
+            TRACE("Coverage index %i\n",index);
+            if (index != -1)
+            {
+                int k, count, class;
+                const GPOS_PosClassSet *pcs;
+                const void *glyph_class_table = NULL;
+
+                offset = GET_BE_WORD(cpf2->ClassDef);
+                glyph_class_table = (const BYTE *)cpf2 + offset;
+
+                class = OT_get_glyph_class(glyph_class_table,glyphs[glyph_index]);
+
+                offset = GET_BE_WORD(cpf2->PosClassSet[class]);
+                if (offset == 0)
+                {
+                    TRACE("No class rule table for class %i\n",class);
+                    continue;
+                }
+                pcs = (const GPOS_PosClassSet*)((const BYTE*)cpf2+offset);
+                count = GET_BE_WORD(pcs->PosClassRuleCnt);
+                TRACE("PosClassSet has %i members\n",count);
+                for (k = 0; k < count; k++)
+                {
+                    const GPOS_PosClassRule_1 *pr;
+                    const GPOS_PosClassRule_2 *pr_2;
+                    int g_count, l;
+
+                    offset = GET_BE_WORD(pcs->PosClassRule[k]);
+                    pr = (const GPOS_PosClassRule_1*)((const BYTE*)pcs+offset);
+                    g_count = GET_BE_WORD(pr->GlyphCount);
+                    TRACE("PosClassRule 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(pr->Class[l])) break;
+                    }
+
+                    if (l < g_count-1)
+                    {
+                        TRACE("Rule does not match\n");
+                        continue;
+                    }
+
+                    TRACE("Rule matches\n");
+                    pr_2 = (const GPOS_PosClassRule_2*)((const BYTE*)pr+
+                        FIELD_OFFSET(GPOS_PosClassRule_1, Class[g_count-1]));
+
+                    for (l = 0; l < GET_BE_WORD(pr->PosCount); l++)
+                    {
+                        int lookupIndex = GET_BE_WORD(pr_2->PosLookupRecord[l].LookupListIndex);
+                        int SequenceIndex = GET_BE_WORD(pr_2->PosLookupRecord[l].SequenceIndex) * write_dir;
+
+                        TRACE("Position: %i -> %i %i\n",l, SequenceIndex, lookupIndex);
+                        GPOS_apply_lookup(psc, lpotm, lplogfont, analysis, piAdvance, lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, glyph_count, pGoffset);
+                    }
+                    return glyph_index + 1;
+                }
+            }
+
+            TRACE("Not covered\n");
+            continue;
+        }
+        else if (GET_BE_WORD(cpf2->PosFormat) == 3)
+        {
+            static int once;
+            if (!once++)
+                FIXME("  TODO: subtype 3\n");
+            continue;
+        }
+        else
+            FIXME("Unhandled Contextual Positioning Format %i\n",GET_BE_WORD(cpf2->PosFormat));
+    }
+    return glyph_index + 1;
+}
+
 static INT GPOS_apply_ChainContextPos(ScriptCache *psc, LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, const SCRIPT_ANALYSIS *analysis, INT* piAdvance,
                                       const OT_LookupList *lookup, const OT_LookupTable *look, const WORD *glyphs, INT glyph_index,
                                       INT glyph_count, INT ppem, GOFFSET *pGoffset)
@@ -1915,6 +2383,8 @@ static INT GPOS_apply_lookup(ScriptCache *psc, LPOUTLINETEXTMETRICW lpotm, LPLOG
             }
             break;
         }
+        case 7:
+            return GPOS_apply_ContextPos(psc, lpotm, lplogfont, analysis, piAdvance, lookup, look, glyphs, glyph_index, glyph_count, ppem, pGoffset);
         case 8:
         {
             return GPOS_apply_ChainContextPos(psc, lpotm, lplogfont, analysis, piAdvance, lookup, look, glyphs, glyph_index, glyph_count, ppem, pGoffset);
index ab4d583..74c7a38 100644 (file)
@@ -1060,6 +1060,8 @@ static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p
     INT *context_shape;
     INT dirR, dirL;
     int i;
+    int char_index;
+    int glyph_index;
 
     if (*pcGlyphs != cChars)
     {
@@ -1103,38 +1105,63 @@ static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p
     }
 
     /* Contextual Shaping */
-    i = 0;
-    while(i < *pcGlyphs)
+    if (dirL > 0)
+        char_index = glyph_index = 0;
+    else
+        char_index = glyph_index = cChars-1;
+
+    while(char_index < cChars && char_index >= 0)
     {
         BOOL shaped = FALSE;
 
         if (psc->GSUB_Table)
         {
-            INT nextIndex;
+            INT nextIndex, offset = 0;
             INT prevCount = *pcGlyphs;
-            nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
+
+            /* Apply CCMP first */
+            apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
+
+            if (prevCount != *pcGlyphs)
+            {
+                offset = *pcGlyphs - prevCount;
+                if (dirL < 0)
+                    glyph_index -= offset * dirL;
+            }
+
+            /* Apply the contextual feature */
+            nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
+
             if (nextIndex > GSUB_E_NOGLYPH)
             {
-                i = nextIndex;
-                UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
+                UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
+                char_index += dirL;
+                if (!offset)
+                    glyph_index = nextIndex;
+                else
+                {
+                    offset = *pcGlyphs - prevCount;
+                    glyph_index += dirL * (offset + 1);
+                }
             }
             shaped = (nextIndex > GSUB_E_NOGLYPH);
         }
 
         if (!shaped)
         {
-            if (context_shape[i] == Xn)
+            if (context_shape[char_index] == Xn)
             {
-                WORD newGlyph = pwOutGlyphs[i];
-                if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
+                WORD newGlyph = pwOutGlyphs[glyph_index];
+                if (pwcChars[char_index] >= FIRST_ARABIC_CHAR && pwcChars[char_index] <= LAST_ARABIC_CHAR)
                 {
                     /* fall back to presentation form B */
-                    WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
-                    if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
-                        pwOutGlyphs[i] = newGlyph;
+                    WCHAR context_char = wine_shaping_forms[pwcChars[char_index] - FIRST_ARABIC_CHAR][context_shape[char_index]];
+                    if (context_char != pwcChars[char_index] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
+                        pwOutGlyphs[glyph_index] = newGlyph;
                 }
             }
-            i++;
+            char_index += dirL;
+            glyph_index += dirL;
         }
     }
 
@@ -1281,6 +1308,8 @@ static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p
     INT *context_shape;
     INT dirR, dirL;
     int i;
+    int char_index;
+    int glyph_index;
 
     if (*pcGlyphs != cChars)
     {
@@ -1343,19 +1372,45 @@ right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
     }
 
     /* Contextual Shaping */
-    i = 0;
-    while(i < *pcGlyphs)
+    if (dirL > 0)
+        char_index = glyph_index = 0;
+    else
+        char_index = glyph_index = cChars-1;
+
+    while(char_index < cChars && char_index >= 0)
     {
-        INT nextIndex;
+        INT nextIndex, offset = 0;
         INT prevCount = *pcGlyphs;
-        nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
+
+        /* Apply CCMP first */
+        apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
+
+        if (prevCount != *pcGlyphs)
+        {
+            offset = *pcGlyphs - prevCount;
+            if (dirL < 0)
+                glyph_index -= offset * dirL;
+        }
+
+        /* Apply the contextual feature */
+        nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
         if (nextIndex > GSUB_E_NOGLYPH)
         {
             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
-            i = nextIndex;
+            char_index += dirL;
+            if (!offset)
+                glyph_index = nextIndex;
+            else
+            {
+                offset = *pcGlyphs - prevCount;
+                glyph_index += dirL * (offset + 1);
+            }
         }
         else
-            i++;
+        {
+            char_index += dirL;
+            glyph_index += dirL;
+        }
     }
 
     HeapFree(GetProcessHeap(),0,context_shape);
@@ -1415,6 +1470,8 @@ static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     INT *context_shape;
     INT dirR, dirL;
     int i;
+    int char_index;
+    int glyph_index;
 
     if (*pcGlyphs != cChars)
     {
@@ -1463,24 +1520,36 @@ static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     }
 
     /* Contextual Shaping */
-    i = 0;
-    while(i < *pcGlyphs)
+    if (dirL > 0)
+        char_index = glyph_index = 0;
+    else
+        char_index = glyph_index = cChars-1;
+
+    while(char_index < cChars && char_index >= 0)
     {
-        if (context_shape[i] >= 0)
+        if (context_shape[char_index] >= 0)
         {
             INT nextIndex;
             INT prevCount = *pcGlyphs;
-            nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
+            nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
+
             if (nextIndex > GSUB_E_NOGLYPH)
             {
                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
-                i = nextIndex;
+                glyph_index = nextIndex;
+                char_index += dirL;
             }
             else
-                i++;
+            {
+                char_index += dirL;
+                glyph_index += dirL;
+            }
         }
         else
-            i++;
+        {
+            char_index += dirL;
+            glyph_index += dirL;
+        }
     }
 
     HeapFree(GetProcessHeap(),0,context_shape);
@@ -2143,7 +2212,7 @@ static inline int unicode_lex(WCHAR c)
     switch( type )
     {
         case 0x0d07: /* Unknown */
-        case 0x0e07: /* Unknwon */
+        case 0x0e07: /* Unknown */
         default: return lex_Generic;
         case 0x0001:
         case 0x0002:
@@ -2757,6 +2826,8 @@ static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     INT *context_shape;
     INT dirL;
     int i;
+    int char_index;
+    int glyph_index;
 
     if (*pcGlyphs != cChars)
     {
@@ -2793,19 +2864,28 @@ static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     }
 
     /* Contextual Shaping */
-    i = 0;
-    while(i < *pcGlyphs)
+    if (dirL > 0)
+        char_index = glyph_index = 0;
+    else
+        char_index = glyph_index = cChars-1;
+
+    while(char_index < cChars && char_index >= 0)
     {
         INT nextIndex;
         INT prevCount = *pcGlyphs;
-        nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
+        nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
+
         if (nextIndex > GSUB_E_NOGLYPH)
         {
             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
-            i = nextIndex;
+            glyph_index = nextIndex;
+            char_index += dirL;
         }
         else
-            i++;
+        {
+            char_index += dirL;
+            glyph_index += dirL;
+        }
     }
 
     HeapFree(GetProcessHeap(),0,context_shape);
index aa839d6..f56d2a0 100644 (file)
@@ -1352,7 +1352,7 @@ static HRESULT _ItemizeInternal(const WCHAR *pwcInChars, int cInChars,
     for (i = 0; i < cInChars; i++)
     {
         /* Joiners get merged preferencially right */
-        if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ))
+        if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
         {
             int j;
             if (i+1 == cInChars)
@@ -1361,7 +1361,8 @@ static HRESULT _ItemizeInternal(const WCHAR *pwcInChars, int cInChars,
             {
                 for (j = i+1; j < cInChars; j++)
                 {
-                    if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ && pwcInChars[j] != Numeric_space)
+                    if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
+                            && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
                     {
                         scripts[i] = scripts[j];
                         break;
@@ -1486,14 +1487,15 @@ static HRESULT _ItemizeInternal(const WCHAR *pwcInChars, int cInChars,
                 }
 
                 /* Joiners get merged preferencially right */
-                if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ))
+                if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
                 {
                     int j;
                     if (i+1 == cInChars && levels[i-1] == levels[i])
                         strength[i] = strength[i-1];
                     else
                         for (j = i+1; j < cInChars && levels[i] == levels[j]; j++)
-                            if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ && pwcInChars[j] != Numeric_space)
+                            if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
+                                    && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
                             {
                                 strength[i] = strength[j];
                                 break;
@@ -3112,9 +3114,6 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
                         chInput = mirror_char(pwcChars[idx]);
                     else
                         chInput = pwcChars[idx];
-                    /* special case for tabs */
-                    if (chInput == 0x0009)
-                        chInput = 0x0020;
                     rChars[i] = chInput;
                 }
                 else
@@ -3154,6 +3153,20 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
         SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
         SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
         SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
+
+        for (i = 0; i < cChars; ++i)
+        {
+            /* Special case for tabs and joiners. As control characters, ZWNJ
+             * and ZWJ would in principle get handled by the corresponding
+             * shaping functions. However, since ZWNJ and ZWJ can get merged
+             * into adjoining runs during itemisation, these don't generally
+             * get classified as Script_Control. */
+            if (pwcChars[i] == 0x0009 || pwcChars[i] == ZWSP || pwcChars[i] == ZWNJ || pwcChars[i] == ZWJ)
+            {
+                pwOutGlyphs[pwLogClust[i]] = ((ScriptCache *)*psc)->sfp.wgBlank;
+                pOutGlyphProps[pwLogClust[i]].sva.fZeroWidth = 1;
+            }
+        }
         heap_free(rChars);
     }
     else
@@ -3178,7 +3191,8 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
                     pOutGlyphProps[i].sva.fZeroWidth = 1;
                 }
             }
-            else if (psa->eScript == Script_Control)
+            else if (psa->eScript == Script_Control || pwcChars[idx] == ZWSP
+                    || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
             {
                 if (pwcChars[idx] == 0x0009 || pwcChars[idx] == 0x000A ||
                     pwcChars[idx] == 0x000D || pwcChars[idx] >= 0x001C)
index 36a712c..7ffef41 100644 (file)
@@ -22,7 +22,7 @@
 @ stdcall ScriptPlace(ptr ptr ptr long ptr ptr ptr ptr ptr)
 @ stdcall ScriptPlaceOpenType(ptr ptr ptr long long ptr ptr long wstr ptr ptr long ptr ptr long ptr ptr ptr)
 @ stub ScriptPositionSingleGlyph
-@ stdcall ScriptRecordDigitSubstitution(ptr ptr)
+@ stdcall ScriptRecordDigitSubstitution(long ptr)
 @ stdcall ScriptShape(ptr ptr ptr long long ptr ptr ptr ptr ptr)
 @ stdcall ScriptShapeOpenType(ptr ptr ptr long long ptr ptr long wstr long long ptr ptr ptr ptr ptr)
 @ stdcall ScriptStringAnalyse(ptr ptr long long long long long ptr ptr ptr ptr ptr ptr)
index 242e47a..fa14e51 100644 (file)
 
 #define NUM_PAGES         17
 
-#define GSUB_E_NOFEATURE -2
-#define GSUB_E_NOGLYPH -1
+#define GSUB_E_NOFEATURE -20
+#define GSUB_E_NOGLYPH -10
 
 #define FEATURE_ALL_TABLES 0
 #define FEATURE_GSUB_TABLE 1
index 5706f3c..fa28505 100644 (file)
@@ -189,7 +189,7 @@ reactos/dll/win32/twain_32            # Synced to WineStaging-1.9.11
 reactos/dll/win32/updspapi            # Synced to WineStaging-1.9.11
 reactos/dll/win32/url                 # Synced to WineStaging-1.9.11
 reactos/dll/win32/urlmon              # Synced to WineStaging-1.9.23
-reactos/dll/win32/usp10               # Synced to WineStaging-1.9.23
+reactos/dll/win32/usp10               # Synced to WineStaging-2.2
 reactos/dll/win32/uxtheme             # Forked
 reactos/dll/win32/vbscript            # Synced to WineStaging-1.9.23
 reactos/dll/win32/version             # Synced to WineStaging-1.9.11