usp10: Correct lookahead offset in Coverage-based Chaining Context Glyph Substitution.
[wine] / dlls / usp10 / shape.c
1 /*
2  * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
3  *
4  * Copyright 2010 CodeWeavers, Aric Stewart
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  */
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "usp10.h"
29 #include "winternl.h"
30
31 #include "usp10_internal.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
36
37 #define FIRST_ARABIC_CHAR 0x0600
38 #define LAST_ARABIC_CHAR  0x06ff
39
40 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
41                                       WCHAR*, INT, WORD*, INT*, INT, WORD*);
42
43 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
44 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46
47 extern const unsigned short wine_shaping_table[];
48 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
49
50 enum joining_types {
51     jtU,
52     jtT,
53     jtR,
54     jtL,
55     jtD,
56     jtC
57 };
58
59 enum joined_forms {
60     Xn=0,
61     Xr,
62     Xl,
63     Xm,
64     /* Syriac Alaph */
65     Afj,
66     Afn,
67     Afx
68 };
69
70 #ifdef WORDS_BIGENDIAN
71 #define GET_BE_WORD(x) (x)
72 #else
73 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
74 #endif
75
76 /* These are all structures needed for the GSUB table */
77 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
78 #define GSUB_E_NOFEATURE -2
79 #define GSUB_E_NOGLYPH -1
80
81 typedef struct {
82     DWORD version;
83     WORD ScriptList;
84     WORD FeatureList;
85     WORD LookupList;
86 } GSUB_Header;
87
88 typedef struct {
89     CHAR ScriptTag[4];
90     WORD Script;
91 } GSUB_ScriptRecord;
92
93 typedef struct {
94     WORD ScriptCount;
95     GSUB_ScriptRecord ScriptRecord[1];
96 } GSUB_ScriptList;
97
98 typedef struct {
99     CHAR LangSysTag[4];
100     WORD LangSys;
101 } GSUB_LangSysRecord;
102
103 typedef struct {
104     WORD DefaultLangSys;
105     WORD LangSysCount;
106     GSUB_LangSysRecord LangSysRecord[1];
107 } GSUB_Script;
108
109 typedef struct {
110     WORD LookupOrder; /* Reserved */
111     WORD ReqFeatureIndex;
112     WORD FeatureCount;
113     WORD FeatureIndex[1];
114 } GSUB_LangSys;
115
116 typedef struct {
117     CHAR FeatureTag[4];
118     WORD Feature;
119 } GSUB_FeatureRecord;
120
121 typedef struct {
122     WORD FeatureCount;
123     GSUB_FeatureRecord FeatureRecord[1];
124 } GSUB_FeatureList;
125
126 typedef struct {
127     WORD FeatureParams; /* Reserved */
128     WORD LookupCount;
129     WORD LookupListIndex[1];
130 } GSUB_Feature;
131
132 typedef struct {
133     WORD LookupCount;
134     WORD Lookup[1];
135 } GSUB_LookupList;
136
137 typedef struct {
138     WORD LookupType;
139     WORD LookupFlag;
140     WORD SubTableCount;
141     WORD SubTable[1];
142 } GSUB_LookupTable;
143
144 typedef struct {
145     WORD CoverageFormat;
146     WORD GlyphCount;
147     WORD GlyphArray[1];
148 } GSUB_CoverageFormat1;
149
150 typedef struct {
151     WORD Start;
152     WORD End;
153     WORD StartCoverageIndex;
154 } GSUB_RangeRecord;
155
156 typedef struct {
157     WORD CoverageFormat;
158     WORD RangeCount;
159     GSUB_RangeRecord RangeRecord[1];
160 } GSUB_CoverageFormat2;
161
162 typedef struct {
163     WORD SubstFormat; /* = 1 */
164     WORD Coverage;
165     WORD DeltaGlyphID;
166 } GSUB_SingleSubstFormat1;
167
168 typedef struct {
169     WORD SubstFormat; /* = 2 */
170     WORD Coverage;
171     WORD GlyphCount;
172     WORD Substitute[1];
173 }GSUB_SingleSubstFormat2;
174
175 typedef struct {
176     WORD SubstFormat; /* = 1 */
177     WORD Coverage;
178     WORD LigSetCount;
179     WORD LigatureSet[1];
180 }GSUB_LigatureSubstFormat1;
181
182 typedef struct {
183     WORD LigatureCount;
184     WORD Ligature[1];
185 }GSUB_LigatureSet;
186
187 typedef struct{
188     WORD LigGlyph;
189     WORD CompCount;
190     WORD Component[1];
191 }GSUB_Ligature;
192
193 typedef struct{
194     WORD SequenceIndex;
195     WORD LookupListIndex;
196
197 }GSUB_SubstLookupRecord;
198
199 typedef struct{
200     WORD SubstFormat; /* = 1 */
201     WORD Coverage;
202     WORD ChainSubRuleSetCount;
203     WORD ChainSubRuleSet[1];
204 }GSUB_ChainContextSubstFormat1;
205
206 typedef struct {
207     WORD SubstFormat; /* = 3 */
208     WORD BacktrackGlyphCount;
209     WORD Coverage[1];
210 }GSUB_ChainContextSubstFormat3_1;
211
212 typedef struct{
213     WORD InputGlyphCount;
214     WORD Coverage[1];
215 }GSUB_ChainContextSubstFormat3_2;
216
217 typedef struct{
218     WORD LookaheadGlyphCount;
219     WORD Coverage[1];
220 }GSUB_ChainContextSubstFormat3_3;
221
222 typedef struct{
223     WORD SubstCount;
224     GSUB_SubstLookupRecord SubstLookupRecord[1];
225 }GSUB_ChainContextSubstFormat3_4;
226
227 typedef struct {
228     WORD SubstFormat; /* = 1 */
229     WORD Coverage;
230     WORD AlternateSetCount;
231     WORD AlternateSet[1];
232 } GSUB_AlternateSubstFormat1;
233
234 typedef struct{
235     WORD GlyphCount;
236     WORD Alternate[1];
237 } GSUB_AlternateSet;
238
239 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
240
241 /* the orders of joined_forms and contextual_features need to line up */
242 static const char* contextual_features[] =
243 {
244     "isol",
245     "fina",
246     "init",
247     "medi",
248     /* Syriac Alaph */
249     "med2",
250     "fin2",
251     "fin3"
252 };
253
254 static OPENTYPE_FEATURE_RECORD standard_features[] =
255 {
256     { MS_MAKE_TAG('l','i','g','a'), 1},
257     { MS_MAKE_TAG('c','l','i','g'), 1},
258 };
259
260 static OPENTYPE_FEATURE_RECORD arabic_features[] =
261 {
262     { MS_MAKE_TAG('r','l','i','g'), 1},
263     { MS_MAKE_TAG('c','a','l','t'), 1},
264     { MS_MAKE_TAG('l','i','g','a'), 1},
265     { MS_MAKE_TAG('d','l','i','g'), 1},
266     { MS_MAKE_TAG('c','s','w','h'), 1},
267     { MS_MAKE_TAG('m','s','e','t'), 1},
268 };
269
270 static const char* required_arabic_features[] =
271 {
272     "fina",
273     "init",
274     "medi",
275     "rlig",
276     NULL
277 };
278
279 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
280 {
281     { MS_MAKE_TAG('d','l','i','g'), 1},
282 };
283
284 static OPENTYPE_FEATURE_RECORD syriac_features[] =
285 {
286     { MS_MAKE_TAG('r','l','i','g'), 1},
287     { MS_MAKE_TAG('c','a','l','t'), 1},
288     { MS_MAKE_TAG('l','i','g','a'), 1},
289     { MS_MAKE_TAG('d','l','i','g'), 1},
290 };
291
292 static const char* required_syriac_features[] =
293 {
294     "fina",
295     "fin2",
296     "fin3",
297     "init",
298     "medi",
299     "med2",
300     "rlig",
301     NULL
302 };
303
304 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
305 {
306     /* Base forms */
307     { MS_MAKE_TAG('a','k','h','n'), 1},
308     { MS_MAKE_TAG('r','p','h','f'), 1},
309     { MS_MAKE_TAG('v','a','t','u'), 1},
310     { MS_MAKE_TAG('p','s','t','f'), 1},
311     /* Presentation forms */
312     { MS_MAKE_TAG('b','l','w','s'), 1},
313     { MS_MAKE_TAG('a','b','v','s'), 1},
314     { MS_MAKE_TAG('p','s','t','s'), 1},
315 };
316
317 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
318 {
319     { MS_MAKE_TAG('a','b','v','s'), 1},
320     { MS_MAKE_TAG('b','l','w','s'), 1},
321 };
322
323 static OPENTYPE_FEATURE_RECORD thai_features[] =
324 {
325     { MS_MAKE_TAG('c','c','m','p'), 1},
326 };
327
328 static const char* required_lao_features[] =
329 {
330     "ccmp",
331     NULL
332 };
333
334 typedef struct ScriptShapeDataTag {
335     TEXTRANGE_PROPERTIES  defaultTextRange;
336     const char**          requiredFeatures;
337     CHAR                  otTag[5];
338     ContextualShapingProc contextProc;
339 } ScriptShapeData;
340
341 /* in order of scripts */
342 static const ScriptShapeData ShapingData[] =
343 {
344     {{ standard_features, 2}, NULL, "", NULL},
345     {{ standard_features, 2}, NULL, "latn", NULL},
346     {{ standard_features, 2}, NULL, "latn", NULL},
347     {{ standard_features, 2}, NULL, "latn", NULL},
348     {{ standard_features, 2}, NULL, "" , NULL},
349     {{ standard_features, 2}, NULL, "latn", NULL},
350     {{ arabic_features, 6}, required_arabic_features, "arab", ContextualShape_Arabic},
351     {{ arabic_features, 6}, required_arabic_features, "arab", ContextualShape_Arabic},
352     {{ hebrew_features, 1}, NULL, "hebr", NULL},
353     {{ syriac_features, 4}, required_syriac_features, "syrc", ContextualShape_Syriac},
354     {{ arabic_features, 6}, required_arabic_features, "arab", ContextualShape_Arabic},
355     {{ NULL, 0}, NULL, "thaa", NULL},
356     {{ standard_features, 2}, NULL, "grek", NULL},
357     {{ standard_features, 2}, NULL, "cyrl", NULL},
358     {{ standard_features, 2}, NULL, "armn", NULL},
359     {{ standard_features, 2}, NULL, "geor", NULL},
360     {{ sinhala_features, 7}, NULL, "sinh", NULL},
361     {{ tibetan_features, 2}, NULL, "tibt", NULL},
362     {{ tibetan_features, 2}, NULL, "tibt", NULL},
363     {{ tibetan_features, 2}, NULL, "phag", ContextualShape_Phags_pa},
364     {{ thai_features, 1}, NULL, "thai", NULL},
365     {{ thai_features, 1}, NULL, "thai", NULL},
366     {{ thai_features, 1}, required_lao_features, "lao", NULL},
367     {{ thai_features, 1}, required_lao_features, "lao", NULL},
368 };
369
370 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
371 {
372     const GSUB_CoverageFormat1* cf1;
373
374     cf1 = table;
375
376     if (GET_BE_WORD(cf1->CoverageFormat) == 1)
377     {
378         int count = GET_BE_WORD(cf1->GlyphCount);
379         int i;
380         TRACE("Coverage Format 1, %i glyphs\n",count);
381         for (i = 0; i < count; i++)
382             if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
383                 return i;
384         return -1;
385     }
386     else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
387     {
388         const GSUB_CoverageFormat2* cf2;
389         int i;
390         int count;
391         cf2 = (const GSUB_CoverageFormat2*)cf1;
392
393         count = GET_BE_WORD(cf2->RangeCount);
394         TRACE("Coverage Format 2, %i ranges\n",count);
395         for (i = 0; i < count; i++)
396         {
397             if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
398                 return -1;
399             if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
400                 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
401             {
402                 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
403                     glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
404             }
405         }
406         return -1;
407     }
408     else
409         ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
410
411     return -1;
412 }
413
414 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
415 {
416     const GSUB_ScriptList *script;
417     const GSUB_Script *deflt = NULL;
418     int i;
419     script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
420
421     TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
422     for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
423     {
424         const GSUB_Script *scr;
425         int offset;
426
427         offset = GET_BE_WORD(script->ScriptRecord[i].Script);
428         scr = (const GSUB_Script*)((const BYTE*)script + offset);
429
430         if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
431             return scr;
432         if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
433             deflt = scr;
434     }
435     return deflt;
436 }
437
438 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
439 {
440     int i;
441     int offset;
442     const GSUB_LangSys *Lang;
443
444     TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
445
446     for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
447     {
448         offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
449         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
450
451         if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
452             return Lang;
453     }
454     offset = GET_BE_WORD(script->DefaultLangSys);
455     if (offset)
456     {
457         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
458         return Lang;
459     }
460     return NULL;
461 }
462
463 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
464 {
465     int i;
466     const GSUB_FeatureList *feature;
467     feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
468
469     TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
470     for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
471     {
472         int index = GET_BE_WORD(lang->FeatureIndex[i]);
473         if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
474         {
475             const GSUB_Feature *feat;
476             feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
477             return feat;
478         }
479     }
480     return NULL;
481 }
482
483 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
484 {
485     int j;
486     TRACE("Single Substitution Subtable\n");
487
488     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
489     {
490         int offset;
491         const GSUB_SingleSubstFormat1 *ssf1;
492         offset = GET_BE_WORD(look->SubTable[j]);
493         ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
494         if (GET_BE_WORD(ssf1->SubstFormat) == 1)
495         {
496             int offset = GET_BE_WORD(ssf1->Coverage);
497             TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
498             if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
499             {
500                 TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
501                 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
502                 TRACE(" 0x%x\n",glyphs[glyph_index]);
503                 return glyph_index + 1;
504             }
505         }
506         else
507         {
508             const GSUB_SingleSubstFormat2 *ssf2;
509             INT index;
510             INT offset;
511
512             ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
513             offset = GET_BE_WORD(ssf1->Coverage);
514             TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
515             index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
516             TRACE("  Coverage index %i\n",index);
517             if (index != -1)
518             {
519                 TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
520                 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
521                 TRACE("0x%x\n",glyphs[glyph_index]);
522                 return glyph_index + 1;
523             }
524         }
525     }
526     return GSUB_E_NOGLYPH;
527 }
528
529 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
530 {
531     int j;
532     TRACE("Alternate Substitution Subtable\n");
533
534     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
535     {
536         int offset;
537         const GSUB_AlternateSubstFormat1 *asf1;
538         INT index;
539
540         offset = GET_BE_WORD(look->SubTable[j]);
541         asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
542         offset = GET_BE_WORD(asf1->Coverage);
543
544         index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
545         if (index != -1)
546         {
547             const GSUB_AlternateSet *as;
548             offset =  GET_BE_WORD(asf1->AlternateSet[index]);
549             as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
550             FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
551
552             TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
553             glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
554             TRACE(" 0x%x\n",glyphs[glyph_index]);
555             return glyph_index + 1;
556         }
557     }
558     return GSUB_E_NOGLYPH;
559 }
560
561 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
562 {
563     int j;
564
565     TRACE("Ligature Substitution Subtable\n");
566     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
567     {
568         const GSUB_LigatureSubstFormat1 *lsf1;
569         int offset,index;
570
571         offset = GET_BE_WORD(look->SubTable[j]);
572         lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
573         offset = GET_BE_WORD(lsf1->Coverage);
574         index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
575         TRACE("  Coverage index %i\n",index);
576         if (index != -1)
577         {
578             const GSUB_LigatureSet *ls;
579             int k, count;
580
581             offset = GET_BE_WORD(lsf1->LigatureSet[index]);
582             ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
583             count = GET_BE_WORD(ls->LigatureCount);
584             TRACE("  LigatureSet has %i members\n",count);
585             for (k = 0; k < count; k++)
586             {
587                 const GSUB_Ligature *lig;
588                 int CompCount,l,CompIndex;
589
590                 offset = GET_BE_WORD(ls->Ligature[k]);
591                 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
592                 CompCount = GET_BE_WORD(lig->CompCount) - 1;
593                 CompIndex = glyph_index+write_dir;
594                 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
595                 {
596                     int CompGlyph;
597                     CompGlyph = GET_BE_WORD(lig->Component[l]);
598                     if (CompGlyph != glyphs[CompIndex])
599                         break;
600                     CompIndex += write_dir;
601                 }
602                 if (l == CompCount)
603                 {
604                     int replaceIdx = glyph_index;
605                     if (write_dir < 0)
606                         replaceIdx = glyph_index - CompCount;
607
608                     TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
609                     glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
610                     TRACE("0x%x\n",glyphs[replaceIdx]);
611                     if (CompCount > 0)
612                     {
613                         int j;
614                         for (j = replaceIdx + 1; j < *glyph_count; j++)
615                             glyphs[j] =glyphs[j+CompCount];
616                         *glyph_count = *glyph_count - CompCount;
617                     }
618                     return replaceIdx + 1;
619                 }
620             }
621         }
622     }
623     return GSUB_E_NOGLYPH;
624 }
625
626 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
627 {
628     int j;
629     BOOL done = FALSE;
630
631     TRACE("Chaining Contextual Substitution Subtable\n");
632     for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
633     {
634         const GSUB_ChainContextSubstFormat1 *ccsf1;
635         int offset;
636         int dirLookahead = write_dir;
637         int dirBacktrack = -1 * write_dir;
638
639         offset = GET_BE_WORD(look->SubTable[j]);
640         ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
641         if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
642         {
643             FIXME("  TODO: subtype 1 (Simple context glyph substitution)\n");
644             return -1;
645         }
646         else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
647         {
648             FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
649             return -1;
650         }
651         else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
652         {
653             int k;
654             int indexGlyphs;
655             const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
656             const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
657             const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
658             const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
659             int newIndex = glyph_index;
660
661             ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
662
663             TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
664
665             for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
666             {
667                 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
668                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
669                     break;
670             }
671             if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
672                 return -1;
673             TRACE("Matched Backtrack\n");
674
675             ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
676
677             indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
678             for (k = 0; k < indexGlyphs; k++)
679             {
680                 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
681                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
682                     break;
683             }
684             if (k != indexGlyphs)
685                 return -1;
686             TRACE("Matched IndexGlyphs\n");
687
688             ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
689
690             for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
691             {
692                 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
693                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
694                     break;
695             }
696             if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
697                 return -1;
698             TRACE("Matched LookAhead\n");
699
700             ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
701
702             for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
703             {
704                 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
705                 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
706
707                 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
708                 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
709                 if (newIndex == -1)
710                 {
711                     ERR("Chain failed to generate a glyph\n");
712                     return -1;
713                 }
714             }
715             return newIndex + 1;
716         }
717     }
718     return -1;
719 }
720
721 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
722 {
723     int offset;
724     const GSUB_LookupTable *look;
725
726     offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
727     look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
728     TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
729     switch(GET_BE_WORD(look->LookupType))
730     {
731         case 1:
732             return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
733         case 3:
734             return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
735         case 4:
736             return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
737         case 6:
738             return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
739         default:
740             FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
741     }
742     return GSUB_E_NOGLYPH;
743 }
744
745 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
746 {
747     int i;
748     int out_index = GSUB_E_NOGLYPH;
749     const GSUB_LookupList *lookup;
750
751     lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
752
753     TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
754     for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
755     {
756         out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
757         if (out_index != GSUB_E_NOGLYPH)
758             break;
759     }
760     if (out_index == GSUB_E_NOGLYPH)
761         TRACE("lookups found no glyphs\n");
762     return out_index;
763 }
764
765 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc)
766 {
767     UINT charset;
768
769     if (psc->userScript != 0)
770         return (char*)&psc->userScript;
771
772     if (ShapingData[psa->eScript].otTag[0] != 0)
773         return ShapingData[psa->eScript].otTag;
774
775     /*
776      * fall back to the font charset
777      */
778     charset = GetTextCharsetInfo(hdc, NULL, 0x0);
779     switch (charset)
780     {
781         case ANSI_CHARSET: return "latn";
782         case BALTIC_CHARSET: return "latn"; /* ?? */
783         case CHINESEBIG5_CHARSET: return "hani";
784         case EASTEUROPE_CHARSET: return "latn"; /* ?? */
785         case GB2312_CHARSET: return "hani";
786         case GREEK_CHARSET: return "grek";
787         case HANGUL_CHARSET: return "hang";
788         case RUSSIAN_CHARSET: return "cyrl";
789         case SHIFTJIS_CHARSET: return "kana";
790         case TURKISH_CHARSET: return "latn"; /* ?? */
791         case VIETNAMESE_CHARSET: return "latn";
792         case JOHAB_CHARSET: return "latn"; /* ?? */
793         case ARABIC_CHARSET: return "arab";
794         case HEBREW_CHARSET: return "hebr";
795         case THAI_CHARSET: return "thai";
796         default: return "latn";
797     }
798 }
799
800 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
801 {
802     const GSUB_Feature *feature;
803     int i;
804
805     for (i = 0; i <  psc->feature_count; i++)
806         if (strncmp(psc->features[i].tag,feat,4)==0)
807             return psc->features[i].feature;
808
809     feature = NULL;
810
811     if (psc->GSUB_Table)
812     {
813         const GSUB_Script *script;
814         const GSUB_LangSys *language;
815
816         script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc));
817         if (script)
818         {
819             if (psc->userLang != 0)
820                 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
821             else
822                 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
823             if (language)
824                 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
825         }
826
827         /* try in the default (latin) table */
828         if (!feature)
829         {
830             script = GSUB_get_script_table(psc->GSUB_Table, "latn");
831             if (script)
832             {
833                 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
834                 if (language)
835                     feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
836             }
837         }
838     }
839
840     TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
841
842     psc->feature_count++;
843
844     if (psc->features)
845         psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
846     else
847         psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
848
849     lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
850     psc->features[psc->feature_count - 1].feature = feature;
851     return feature;
852 }
853
854 static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *glyphs, INT index, INT write_dir, INT* glyph_count, const char* feat)
855 {
856     const GSUB_Feature *feature;
857
858     feature = load_GSUB_feature(hdc, psa, psc, feat);
859     if (!feature)
860         return GSUB_E_NOFEATURE;
861
862     TRACE("applying feature %s\n",feat);
863     return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
864 }
865
866 static VOID *load_gsub_table(HDC hdc)
867 {
868     VOID* GSUB_Table = NULL;
869     int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
870     if (length != GDI_ERROR)
871     {
872         GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
873         GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
874         TRACE("Loaded GSUB table of %i bytes\n",length);
875     }
876     return GSUB_Table;
877 }
878
879 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
880 {
881     if (changeCount == 0)
882         return;
883     else
884     {
885         int i;
886         int target_glyph = nextIndex - 1;
887         int target_index = -1;
888         int replacing_glyph = -1;
889         int changed = 0;
890
891         if (write_dir > 0)
892             for (i = 0; i < chars; i++)
893             {
894                 if (pwLogClust[i] == target_glyph)
895                 {
896                     target_index = i;
897                     break;
898                 }
899             }
900         else
901             for (i = chars - 1; i >= 0; i--)
902             {
903                 if (pwLogClust[i] == target_glyph)
904                 {
905                     target_index = i;
906                     break;
907                 }
908             }
909         if (target_index == -1)
910         {
911             ERR("Unable to find target glyph\n");
912             return;
913         }
914
915         if (changeCount < 0)
916         {
917             /* merge glyphs */
918             for(i = target_index; i < chars && i >= 0; i+=write_dir)
919             {
920                 if (pwLogClust[i] == target_glyph)
921                     continue;
922                 if(pwLogClust[i] == replacing_glyph)
923                     pwLogClust[i] = target_glyph;
924                 else
925                 {
926                     changed--;
927                     if (changed >= changeCount)
928                     {
929                         replacing_glyph = pwLogClust[i];
930                         pwLogClust[i] = target_glyph;
931                     }
932                     else
933                         break;
934                 }
935             }
936         }
937
938         /* renumber trailing indexes*/
939         for(i = target_index; i < chars && i >= 0; i+=write_dir)
940         {
941             if (pwLogClust[i] != target_glyph)
942                 pwLogClust[i] += changeCount;
943         }
944     }
945 }
946
947 static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *pwOutGlyphs, int write_dir, INT* pcGlyphs, INT cChars, const char* feat, WORD *pwLogClust )
948 {
949     int i;
950
951     if (psc->GSUB_Table)
952     {
953         const GSUB_Feature *feature;
954
955         feature = load_GSUB_feature(hdc, psa, psc, feat);
956         if (!feature)
957             return GSUB_E_NOFEATURE;
958
959         i = 0;
960         TRACE("applying feature %s\n",debugstr_an(feat,4));
961         while(i < *pcGlyphs)
962         {
963                 INT nextIndex;
964                 INT prevCount = *pcGlyphs;
965                 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
966                 if (nextIndex > GSUB_E_NOGLYPH)
967                 {
968                     UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
969                     i = nextIndex;
970                 }
971                 else
972                     i++;
973         }
974         return *pcGlyphs;
975     }
976     return GSUB_E_NOFEATURE;
977 }
978
979 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
980 {
981     if (i + delta < 0)
982         return 0;
983     if ( i+ delta >= cchLen)
984         return 0;
985
986     i += delta;
987
988     return chars[i];
989 }
990
991 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
992 {
993     if (i + delta < 0)
994     {
995         if (psa->fLinkBefore)
996             return jtR;
997         else
998             return jtU;
999     }
1000     if ( i+ delta >= cchLen)
1001     {
1002         if (psa->fLinkAfter)
1003             return jtL;
1004         else
1005             return jtU;
1006     }
1007
1008     i += delta;
1009
1010     if (context_type[i] == jtT)
1011         return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1012     else
1013         return context_type[i];
1014 }
1015
1016 static inline BOOL right_join_causing(CHAR joining_type)
1017 {
1018     return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1019 }
1020
1021 static inline BOOL left_join_causing(CHAR joining_type)
1022 {
1023     return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1024 }
1025
1026 static inline BOOL word_break_causing(WCHAR chr)
1027 {
1028     /* we are working within a string of characters already guareented to
1029        be within one script, Syriac, so we do not worry about any characers
1030        other than the space character outside of that range */
1031     return (chr == 0 || chr == 0x20 );
1032 }
1033
1034 /*
1035  * ContextualShape_Arabic
1036  */
1037 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1038 {
1039     CHAR *context_type;
1040     INT *context_shape;
1041     INT dirR, dirL;
1042     int i;
1043
1044     if (*pcGlyphs != cChars)
1045     {
1046         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1047         return;
1048     }
1049
1050     if (!psa->fLogicalOrder && psa->fRTL)
1051     {
1052         dirR = 1;
1053         dirL = -1;
1054     }
1055     else
1056     {
1057         dirR = -1;
1058         dirL = 1;
1059     }
1060
1061     if (!psc->GSUB_Table)
1062         psc->GSUB_Table = load_gsub_table(hdc);
1063
1064     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1065     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1066
1067     for (i = 0; i < cChars; i++)
1068         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1069
1070     for (i = 0; i < cChars; i++)
1071     {
1072         if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1073             context_shape[i] = Xr;
1074         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1075             context_shape[i] = Xl;
1076         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)) && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1077             context_shape[i] = Xm;
1078         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1079             context_shape[i] = Xr;
1080         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1081             context_shape[i] = Xl;
1082         else
1083             context_shape[i] = Xn;
1084     }
1085
1086     /* Contextual Shaping */
1087     i = 0;
1088     while(i < *pcGlyphs)
1089     {
1090         BOOL shaped = FALSE;
1091
1092         if (psc->GSUB_Table)
1093         {
1094             INT nextIndex;
1095             INT prevCount = *pcGlyphs;
1096             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1097             if (nextIndex > GSUB_E_NOGLYPH)
1098             {
1099                 i = nextIndex;
1100                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1101             }
1102             shaped = (nextIndex > GSUB_E_NOGLYPH);
1103         }
1104
1105         if (!shaped)
1106         {
1107             WORD newGlyph = pwOutGlyphs[i];
1108             if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1109             {
1110                 /* fall back to presentation form B */
1111                 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1112                 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1113                     pwOutGlyphs[i] = newGlyph;
1114             }
1115             i++;
1116         }
1117     }
1118
1119     HeapFree(GetProcessHeap(),0,context_shape);
1120     HeapFree(GetProcessHeap(),0,context_type);
1121 }
1122
1123 /*
1124  * ContextualShape_Syriac
1125  */
1126
1127 #define ALAPH 0x710
1128 #define DALATH 0x715
1129 #define RISH 0x72A
1130
1131 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1132 {
1133     CHAR *context_type;
1134     INT *context_shape;
1135     INT dirR, dirL;
1136     int i;
1137
1138     if (*pcGlyphs != cChars)
1139     {
1140         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1141         return;
1142     }
1143
1144     if (!psa->fLogicalOrder && psa->fRTL)
1145     {
1146         dirR = 1;
1147         dirL = -1;
1148     }
1149     else
1150     {
1151         dirR = -1;
1152         dirL = 1;
1153     }
1154
1155     if (!psc->GSUB_Table)
1156         psc->GSUB_Table = load_gsub_table(hdc);
1157
1158     if (!psc->GSUB_Table)
1159         return;
1160
1161     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1162     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1163
1164     for (i = 0; i < cChars; i++)
1165         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1166
1167     for (i = 0; i < cChars; i++)
1168     {
1169         if (pwcChars[i] == ALAPH)
1170         {
1171             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1172
1173             if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1174             context_shape[i] = Afj;
1175             else if ( rchar != DALATH && rchar != RISH &&
1176 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1177 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1178             context_shape[i] = Afn;
1179             else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1180             context_shape[i] = Afx;
1181             else
1182             context_shape[i] = Xn;
1183         }
1184         else if (context_type[i] == jtR &&
1185 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1186             context_shape[i] = Xr;
1187         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1188             context_shape[i] = Xl;
1189         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)) && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1190             context_shape[i] = Xm;
1191         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1192             context_shape[i] = Xr;
1193         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1194             context_shape[i] = Xl;
1195         else
1196             context_shape[i] = Xn;
1197     }
1198
1199     /* Contextual Shaping */
1200     i = 0;
1201     while(i < *pcGlyphs)
1202     {
1203         INT nextIndex;
1204         INT prevCount = *pcGlyphs;
1205         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1206         if (nextIndex > GSUB_E_NOGLYPH)
1207         {
1208             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1209             i = nextIndex;
1210         }
1211         else
1212             i++;
1213     }
1214
1215     HeapFree(GetProcessHeap(),0,context_shape);
1216     HeapFree(GetProcessHeap(),0,context_type);
1217 }
1218
1219 /*
1220  * ContextualShape_Phags_pa
1221  */
1222
1223 #define phags_pa_CANDRABINDU  0xA873
1224 #define phags_pa_START 0xA840
1225 #define phags_pa_END  0xA87F
1226
1227 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1228 {
1229     INT *context_shape;
1230     INT dirR, dirL;
1231     int i;
1232
1233     if (*pcGlyphs != cChars)
1234     {
1235         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1236         return;
1237     }
1238
1239     if (!psa->fLogicalOrder && psa->fRTL)
1240     {
1241         dirR = 1;
1242         dirL = -1;
1243     }
1244     else
1245     {
1246         dirR = -1;
1247         dirL = 1;
1248     }
1249
1250     if (!psc->GSUB_Table)
1251         psc->GSUB_Table = load_gsub_table(hdc);
1252
1253     if (!psc->GSUB_Table)
1254         return;
1255
1256     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1257
1258     for (i = 0; i < cChars; i++)
1259     {
1260         if (pwcChars[i] >= phags_pa_START && pwcChars[i] <=  phags_pa_END)
1261         {
1262             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1263             WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1264             BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <=  phags_pa_END);
1265             BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <=  phags_pa_END);
1266
1267             if (jrchar && jlchar)
1268                 context_shape[i] = Xm;
1269             else if (jrchar)
1270                 context_shape[i] = Xr;
1271             else if (jlchar)
1272                 context_shape[i] = Xl;
1273             else
1274                 context_shape[i] = Xn;
1275         }
1276         else
1277             context_shape[i] = -1;
1278     }
1279
1280     /* Contextual Shaping */
1281     i = 0;
1282     while(i < *pcGlyphs)
1283     {
1284         if (context_shape[i] >= 0)
1285         {
1286             INT nextIndex;
1287             INT prevCount = *pcGlyphs;
1288             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1289             if (nextIndex > GSUB_E_NOGLYPH)
1290             {
1291                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1292                 i = nextIndex;
1293             }
1294             else
1295                 i++;
1296         }
1297         else
1298             i++;
1299     }
1300
1301     HeapFree(GetProcessHeap(),0,context_shape);
1302 }
1303
1304 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1305 {
1306     if (ShapingData[psa->eScript].contextProc)
1307         ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
1308 }
1309
1310 static void SHAPE_ApplyOpenTypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, const TEXTRANGE_PROPERTIES *rpRangeProperties, WORD *pwLogClust)
1311 {
1312     int i;
1313     INT dirL;
1314
1315     if (!rpRangeProperties)
1316         return;
1317
1318     if (!psc->GSUB_Table)
1319         psc->GSUB_Table = load_gsub_table(hdc);
1320
1321     if (!psc->GSUB_Table)
1322         return;
1323
1324     if (!psa->fLogicalOrder && psa->fRTL)
1325         dirL = -1;
1326     else
1327         dirL = 1;
1328
1329     for (i = 0; i < rpRangeProperties->cotfRecords; i++)
1330     {
1331         if (rpRangeProperties->potfRecords[i].lParameter > 0)
1332         apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
1333     }
1334 }
1335
1336 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
1337 {
1338 const TEXTRANGE_PROPERTIES *rpRangeProperties;
1339 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
1340
1341     SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
1342 }
1343
1344 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
1345 {
1346     const GSUB_Feature *feature;
1347     int i;
1348
1349     if (!ShapingData[psa->eScript].requiredFeatures)
1350         return S_OK;
1351
1352     if (!psc->GSUB_Table)
1353         psc->GSUB_Table = load_gsub_table(hdc);
1354
1355     /* we need to have at least one of the required features */
1356     i = 0;
1357     while (ShapingData[psa->eScript].requiredFeatures[i])
1358     {
1359         feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
1360         if (feature)
1361             return S_OK;
1362         i++;
1363     }
1364
1365     return USP_E_SCRIPT_NOT_IN_FONT;
1366 }