usp10: Determine glyph properties after shaping for scripts with no justification.
[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
48 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
49
50 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
51 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
52 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
53 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
54
55 extern const unsigned short wine_shaping_table[];
56 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
57
58 enum joining_types {
59     jtU,
60     jtT,
61     jtR,
62     jtL,
63     jtD,
64     jtC
65 };
66
67 enum joined_forms {
68     Xn=0,
69     Xr,
70     Xl,
71     Xm,
72     /* Syriac Alaph */
73     Afj,
74     Afn,
75     Afx
76 };
77
78 #ifdef WORDS_BIGENDIAN
79 #define GET_BE_WORD(x) (x)
80 #else
81 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
82 #endif
83
84 /* These are all structures needed for the GSUB table */
85 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
86 #define GSUB_E_NOFEATURE -2
87 #define GSUB_E_NOGLYPH -1
88
89 typedef struct {
90     DWORD version;
91     WORD ScriptList;
92     WORD FeatureList;
93     WORD LookupList;
94 } GSUB_Header;
95
96 typedef struct {
97     CHAR ScriptTag[4];
98     WORD Script;
99 } GSUB_ScriptRecord;
100
101 typedef struct {
102     WORD ScriptCount;
103     GSUB_ScriptRecord ScriptRecord[1];
104 } GSUB_ScriptList;
105
106 typedef struct {
107     CHAR LangSysTag[4];
108     WORD LangSys;
109 } GSUB_LangSysRecord;
110
111 typedef struct {
112     WORD DefaultLangSys;
113     WORD LangSysCount;
114     GSUB_LangSysRecord LangSysRecord[1];
115 } GSUB_Script;
116
117 typedef struct {
118     WORD LookupOrder; /* Reserved */
119     WORD ReqFeatureIndex;
120     WORD FeatureCount;
121     WORD FeatureIndex[1];
122 } GSUB_LangSys;
123
124 typedef struct {
125     CHAR FeatureTag[4];
126     WORD Feature;
127 } GSUB_FeatureRecord;
128
129 typedef struct {
130     WORD FeatureCount;
131     GSUB_FeatureRecord FeatureRecord[1];
132 } GSUB_FeatureList;
133
134 typedef struct {
135     WORD FeatureParams; /* Reserved */
136     WORD LookupCount;
137     WORD LookupListIndex[1];
138 } GSUB_Feature;
139
140 typedef struct {
141     WORD LookupCount;
142     WORD Lookup[1];
143 } GSUB_LookupList;
144
145 typedef struct {
146     WORD LookupType;
147     WORD LookupFlag;
148     WORD SubTableCount;
149     WORD SubTable[1];
150 } GSUB_LookupTable;
151
152 typedef struct {
153     WORD CoverageFormat;
154     WORD GlyphCount;
155     WORD GlyphArray[1];
156 } GSUB_CoverageFormat1;
157
158 typedef struct {
159     WORD Start;
160     WORD End;
161     WORD StartCoverageIndex;
162 } GSUB_RangeRecord;
163
164 typedef struct {
165     WORD CoverageFormat;
166     WORD RangeCount;
167     GSUB_RangeRecord RangeRecord[1];
168 } GSUB_CoverageFormat2;
169
170 typedef struct {
171     WORD SubstFormat; /* = 1 */
172     WORD Coverage;
173     WORD DeltaGlyphID;
174 } GSUB_SingleSubstFormat1;
175
176 typedef struct {
177     WORD SubstFormat; /* = 2 */
178     WORD Coverage;
179     WORD GlyphCount;
180     WORD Substitute[1];
181 }GSUB_SingleSubstFormat2;
182
183 typedef struct {
184     WORD SubstFormat; /* = 1 */
185     WORD Coverage;
186     WORD LigSetCount;
187     WORD LigatureSet[1];
188 }GSUB_LigatureSubstFormat1;
189
190 typedef struct {
191     WORD LigatureCount;
192     WORD Ligature[1];
193 }GSUB_LigatureSet;
194
195 typedef struct{
196     WORD LigGlyph;
197     WORD CompCount;
198     WORD Component[1];
199 }GSUB_Ligature;
200
201 typedef struct{
202     WORD SequenceIndex;
203     WORD LookupListIndex;
204
205 }GSUB_SubstLookupRecord;
206
207 typedef struct{
208     WORD SubstFormat; /* = 1 */
209     WORD Coverage;
210     WORD ChainSubRuleSetCount;
211     WORD ChainSubRuleSet[1];
212 }GSUB_ChainContextSubstFormat1;
213
214 typedef struct {
215     WORD SubstFormat; /* = 3 */
216     WORD BacktrackGlyphCount;
217     WORD Coverage[1];
218 }GSUB_ChainContextSubstFormat3_1;
219
220 typedef struct{
221     WORD InputGlyphCount;
222     WORD Coverage[1];
223 }GSUB_ChainContextSubstFormat3_2;
224
225 typedef struct{
226     WORD LookaheadGlyphCount;
227     WORD Coverage[1];
228 }GSUB_ChainContextSubstFormat3_3;
229
230 typedef struct{
231     WORD SubstCount;
232     GSUB_SubstLookupRecord SubstLookupRecord[1];
233 }GSUB_ChainContextSubstFormat3_4;
234
235 typedef struct {
236     WORD SubstFormat; /* = 1 */
237     WORD Coverage;
238     WORD AlternateSetCount;
239     WORD AlternateSet[1];
240 } GSUB_AlternateSubstFormat1;
241
242 typedef struct{
243     WORD GlyphCount;
244     WORD Alternate[1];
245 } GSUB_AlternateSet;
246
247 /* These are all structures needed for the GDEF table */
248 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
249
250 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
251
252 typedef struct {
253     DWORD Version;
254     WORD GlyphClassDef;
255     WORD AttachList;
256     WORD LigCaretList;
257     WORD MarkAttachClassDef;
258 } GDEF_Header;
259
260 typedef struct {
261     WORD ClassFormat;
262     WORD StartGlyph;
263     WORD GlyphCount;
264     WORD ClassValueArray[1];
265 } GDEF_ClassDefFormat1;
266
267 typedef struct {
268     WORD Start;
269     WORD End;
270     WORD Class;
271 } GDEF_ClassRangeRecord;
272
273 typedef struct {
274     WORD ClassFormat;
275     WORD ClassRangeCount;
276     GDEF_ClassRangeRecord ClassRangeRecord[1];
277 } GDEF_ClassDefFormat2;
278
279 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
280
281 /* the orders of joined_forms and contextual_features need to line up */
282 static const char* contextual_features[] =
283 {
284     "isol",
285     "fina",
286     "init",
287     "medi",
288     /* Syriac Alaph */
289     "med2",
290     "fin2",
291     "fin3"
292 };
293
294 static OPENTYPE_FEATURE_RECORD standard_features[] =
295 {
296     { MS_MAKE_TAG('l','i','g','a'), 1},
297     { MS_MAKE_TAG('c','l','i','g'), 1},
298 };
299
300 static OPENTYPE_FEATURE_RECORD arabic_features[] =
301 {
302     { MS_MAKE_TAG('r','l','i','g'), 1},
303     { MS_MAKE_TAG('c','a','l','t'), 1},
304     { MS_MAKE_TAG('l','i','g','a'), 1},
305     { MS_MAKE_TAG('d','l','i','g'), 1},
306     { MS_MAKE_TAG('c','s','w','h'), 1},
307     { MS_MAKE_TAG('m','s','e','t'), 1},
308 };
309
310 static const char* required_arabic_features[] =
311 {
312     "fina",
313     "init",
314     "medi",
315     "rlig",
316     NULL
317 };
318
319 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
320 {
321     { MS_MAKE_TAG('d','l','i','g'), 1},
322 };
323
324 static OPENTYPE_FEATURE_RECORD syriac_features[] =
325 {
326     { MS_MAKE_TAG('r','l','i','g'), 1},
327     { MS_MAKE_TAG('c','a','l','t'), 1},
328     { MS_MAKE_TAG('l','i','g','a'), 1},
329     { MS_MAKE_TAG('d','l','i','g'), 1},
330 };
331
332 static const char* required_syriac_features[] =
333 {
334     "fina",
335     "fin2",
336     "fin3",
337     "init",
338     "medi",
339     "med2",
340     "rlig",
341     NULL
342 };
343
344 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
345 {
346     /* Base forms */
347     { MS_MAKE_TAG('a','k','h','n'), 1},
348     { MS_MAKE_TAG('r','p','h','f'), 1},
349     { MS_MAKE_TAG('v','a','t','u'), 1},
350     { MS_MAKE_TAG('p','s','t','f'), 1},
351     /* Presentation forms */
352     { MS_MAKE_TAG('b','l','w','s'), 1},
353     { MS_MAKE_TAG('a','b','v','s'), 1},
354     { MS_MAKE_TAG('p','s','t','s'), 1},
355 };
356
357 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
358 {
359     { MS_MAKE_TAG('a','b','v','s'), 1},
360     { MS_MAKE_TAG('b','l','w','s'), 1},
361 };
362
363 static OPENTYPE_FEATURE_RECORD thai_features[] =
364 {
365     { MS_MAKE_TAG('c','c','m','p'), 1},
366 };
367
368 static const char* required_lao_features[] =
369 {
370     "ccmp",
371     NULL
372 };
373
374 typedef struct ScriptShapeDataTag {
375     TEXTRANGE_PROPERTIES   defaultTextRange;
376     const char**           requiredFeatures;
377     CHAR                   otTag[5];
378     ContextualShapingProc  contextProc;
379     ShapeCharGlyphPropProc charGlyphPropProc;
380 } ScriptShapeData;
381
382 /* in order of scripts */
383 static const ScriptShapeData ShapingData[] =
384 {
385     {{ standard_features, 2}, NULL, "", NULL, NULL},
386     {{ standard_features, 2}, NULL, "latn", NULL, NULL},
387     {{ standard_features, 2}, NULL, "latn", NULL, NULL},
388     {{ standard_features, 2}, NULL, "latn", NULL, NULL},
389     {{ standard_features, 2}, NULL, "" , NULL, NULL},
390     {{ standard_features, 2}, NULL, "latn", NULL, NULL},
391     {{ arabic_features, 6}, required_arabic_features, "arab", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
392     {{ arabic_features, 6}, required_arabic_features, "arab", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
393     {{ hebrew_features, 1}, NULL, "hebr", NULL, NULL},
394     {{ syriac_features, 4}, required_syriac_features, "syrc", ContextualShape_Syriac, ShapeCharGlyphProp_None},
395     {{ arabic_features, 6}, required_arabic_features, "arab", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
396     {{ NULL, 0}, NULL, "thaa", NULL, ShapeCharGlyphProp_None},
397     {{ standard_features, 2}, NULL, "grek", NULL, NULL},
398     {{ standard_features, 2}, NULL, "cyrl", NULL, NULL},
399     {{ standard_features, 2}, NULL, "armn", NULL, NULL},
400     {{ standard_features, 2}, NULL, "geor", NULL, NULL},
401     {{ sinhala_features, 7}, NULL, "sinh", NULL, NULL},
402     {{ tibetan_features, 2}, NULL, "tibt", NULL, ShapeCharGlyphProp_None},
403     {{ tibetan_features, 2}, NULL, "tibt", NULL, ShapeCharGlyphProp_None},
404     {{ tibetan_features, 2}, NULL, "phag", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
405     {{ thai_features, 1}, NULL, "thai", NULL, ShapeCharGlyphProp_Thai},
406     {{ thai_features, 1}, NULL, "thai", NULL, ShapeCharGlyphProp_Thai},
407     {{ thai_features, 1}, required_lao_features, "lao", NULL, ShapeCharGlyphProp_Thai},
408     {{ thai_features, 1}, required_lao_features, "lao", NULL, ShapeCharGlyphProp_Thai},
409 };
410
411 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
412 {
413     const GSUB_CoverageFormat1* cf1;
414
415     cf1 = table;
416
417     if (GET_BE_WORD(cf1->CoverageFormat) == 1)
418     {
419         int count = GET_BE_WORD(cf1->GlyphCount);
420         int i;
421         TRACE("Coverage Format 1, %i glyphs\n",count);
422         for (i = 0; i < count; i++)
423             if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
424                 return i;
425         return -1;
426     }
427     else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
428     {
429         const GSUB_CoverageFormat2* cf2;
430         int i;
431         int count;
432         cf2 = (const GSUB_CoverageFormat2*)cf1;
433
434         count = GET_BE_WORD(cf2->RangeCount);
435         TRACE("Coverage Format 2, %i ranges\n",count);
436         for (i = 0; i < count; i++)
437         {
438             if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
439                 return -1;
440             if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
441                 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
442             {
443                 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
444                     glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
445             }
446         }
447         return -1;
448     }
449     else
450         ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
451
452     return -1;
453 }
454
455 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
456 {
457     const GSUB_ScriptList *script;
458     const GSUB_Script *deflt = NULL;
459     int i;
460     script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
461
462     TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
463     for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
464     {
465         const GSUB_Script *scr;
466         int offset;
467
468         offset = GET_BE_WORD(script->ScriptRecord[i].Script);
469         scr = (const GSUB_Script*)((const BYTE*)script + offset);
470
471         if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
472             return scr;
473         if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
474             deflt = scr;
475     }
476     return deflt;
477 }
478
479 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
480 {
481     int i;
482     int offset;
483     const GSUB_LangSys *Lang;
484
485     TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
486
487     for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
488     {
489         offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
490         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
491
492         if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
493             return Lang;
494     }
495     offset = GET_BE_WORD(script->DefaultLangSys);
496     if (offset)
497     {
498         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
499         return Lang;
500     }
501     return NULL;
502 }
503
504 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
505 {
506     int i;
507     const GSUB_FeatureList *feature;
508     feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
509
510     TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
511     for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
512     {
513         int index = GET_BE_WORD(lang->FeatureIndex[i]);
514         if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
515         {
516             const GSUB_Feature *feat;
517             feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
518             return feat;
519         }
520     }
521     return NULL;
522 }
523
524 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
525 {
526     int j;
527     TRACE("Single Substitution Subtable\n");
528
529     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
530     {
531         int offset;
532         const GSUB_SingleSubstFormat1 *ssf1;
533         offset = GET_BE_WORD(look->SubTable[j]);
534         ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
535         if (GET_BE_WORD(ssf1->SubstFormat) == 1)
536         {
537             int offset = GET_BE_WORD(ssf1->Coverage);
538             TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
539             if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
540             {
541                 TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
542                 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
543                 TRACE(" 0x%x\n",glyphs[glyph_index]);
544                 return glyph_index + 1;
545             }
546         }
547         else
548         {
549             const GSUB_SingleSubstFormat2 *ssf2;
550             INT index;
551             INT offset;
552
553             ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
554             offset = GET_BE_WORD(ssf1->Coverage);
555             TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
556             index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
557             TRACE("  Coverage index %i\n",index);
558             if (index != -1)
559             {
560                 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
561                     return GSUB_E_NOGLYPH;
562
563                 TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
564                 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
565                 TRACE("0x%x\n",glyphs[glyph_index]);
566                 return glyph_index + 1;
567             }
568         }
569     }
570     return GSUB_E_NOGLYPH;
571 }
572
573 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
574 {
575     int j;
576     TRACE("Alternate Substitution Subtable\n");
577
578     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
579     {
580         int offset;
581         const GSUB_AlternateSubstFormat1 *asf1;
582         INT index;
583
584         offset = GET_BE_WORD(look->SubTable[j]);
585         asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
586         offset = GET_BE_WORD(asf1->Coverage);
587
588         index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
589         if (index != -1)
590         {
591             const GSUB_AlternateSet *as;
592             offset =  GET_BE_WORD(asf1->AlternateSet[index]);
593             as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
594             FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
595             if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
596                 return GSUB_E_NOGLYPH;
597
598             TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
599             glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
600             TRACE(" 0x%x\n",glyphs[glyph_index]);
601             return glyph_index + 1;
602         }
603     }
604     return GSUB_E_NOGLYPH;
605 }
606
607 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
608 {
609     int j;
610
611     TRACE("Ligature Substitution Subtable\n");
612     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
613     {
614         const GSUB_LigatureSubstFormat1 *lsf1;
615         int offset,index;
616
617         offset = GET_BE_WORD(look->SubTable[j]);
618         lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
619         offset = GET_BE_WORD(lsf1->Coverage);
620         index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
621         TRACE("  Coverage index %i\n",index);
622         if (index != -1)
623         {
624             const GSUB_LigatureSet *ls;
625             int k, count;
626
627             offset = GET_BE_WORD(lsf1->LigatureSet[index]);
628             ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
629             count = GET_BE_WORD(ls->LigatureCount);
630             TRACE("  LigatureSet has %i members\n",count);
631             for (k = 0; k < count; k++)
632             {
633                 const GSUB_Ligature *lig;
634                 int CompCount,l,CompIndex;
635
636                 offset = GET_BE_WORD(ls->Ligature[k]);
637                 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
638                 CompCount = GET_BE_WORD(lig->CompCount) - 1;
639                 CompIndex = glyph_index+write_dir;
640                 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
641                 {
642                     int CompGlyph;
643                     CompGlyph = GET_BE_WORD(lig->Component[l]);
644                     if (CompGlyph != glyphs[CompIndex])
645                         break;
646                     CompIndex += write_dir;
647                 }
648                 if (l == CompCount)
649                 {
650                     int replaceIdx = glyph_index;
651                     if (write_dir < 0)
652                         replaceIdx = glyph_index - CompCount;
653
654                     TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
655                     glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
656                     TRACE("0x%x\n",glyphs[replaceIdx]);
657                     if (CompCount > 0)
658                     {
659                         int j;
660                         for (j = replaceIdx + 1; j < *glyph_count; j++)
661                             glyphs[j] =glyphs[j+CompCount];
662                         *glyph_count = *glyph_count - CompCount;
663                     }
664                     return replaceIdx + 1;
665                 }
666             }
667         }
668     }
669     return GSUB_E_NOGLYPH;
670 }
671
672 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
673 {
674     int j;
675     BOOL done = FALSE;
676
677     TRACE("Chaining Contextual Substitution Subtable\n");
678     for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
679     {
680         const GSUB_ChainContextSubstFormat1 *ccsf1;
681         int offset;
682         int dirLookahead = write_dir;
683         int dirBacktrack = -1 * write_dir;
684
685         offset = GET_BE_WORD(look->SubTable[j]);
686         ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
687         if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
688         {
689             FIXME("  TODO: subtype 1 (Simple context glyph substitution)\n");
690             return -1;
691         }
692         else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
693         {
694             FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
695             return -1;
696         }
697         else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
698         {
699             int k;
700             int indexGlyphs;
701             const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
702             const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
703             const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
704             const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
705             int newIndex = glyph_index;
706
707             ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
708
709             TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
710
711             for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
712             {
713                 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
714                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
715                     break;
716             }
717             if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
718                 return -1;
719             TRACE("Matched Backtrack\n");
720
721             ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
722
723             indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
724             for (k = 0; k < indexGlyphs; k++)
725             {
726                 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
727                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
728                     break;
729             }
730             if (k != indexGlyphs)
731                 return -1;
732             TRACE("Matched IndexGlyphs\n");
733
734             ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
735
736             for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
737             {
738                 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
739                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
740                     break;
741             }
742             if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
743                 return -1;
744             TRACE("Matched LookAhead\n");
745
746             ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
747
748             for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
749             {
750                 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
751                 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
752
753                 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
754                 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
755                 if (newIndex == -1)
756                 {
757                     ERR("Chain failed to generate a glyph\n");
758                     return -1;
759                 }
760             }
761             return newIndex + 1;
762         }
763     }
764     return -1;
765 }
766
767 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
768 {
769     int offset;
770     const GSUB_LookupTable *look;
771
772     offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
773     look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
774     TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
775     switch(GET_BE_WORD(look->LookupType))
776     {
777         case 1:
778             return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
779         case 3:
780             return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
781         case 4:
782             return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
783         case 6:
784             return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
785         default:
786             FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
787     }
788     return GSUB_E_NOGLYPH;
789 }
790
791 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
792 {
793     int i;
794     int out_index = GSUB_E_NOGLYPH;
795     const GSUB_LookupList *lookup;
796
797     lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
798
799     TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
800     for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
801     {
802         out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
803         if (out_index != GSUB_E_NOGLYPH)
804             break;
805     }
806     if (out_index == GSUB_E_NOGLYPH)
807         TRACE("lookups found no glyphs\n");
808     else
809     {
810         int out2;
811         out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
812         if (out2!=GSUB_E_NOGLYPH)
813             out_index = out2;
814     }
815     return out_index;
816 }
817
818 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc)
819 {
820     UINT charset;
821
822     if (psc->userScript != 0)
823         return (char*)&psc->userScript;
824
825     if (ShapingData[psa->eScript].otTag[0] != 0)
826         return ShapingData[psa->eScript].otTag;
827
828     /*
829      * fall back to the font charset
830      */
831     charset = GetTextCharsetInfo(hdc, NULL, 0x0);
832     switch (charset)
833     {
834         case ANSI_CHARSET: return "latn";
835         case BALTIC_CHARSET: return "latn"; /* ?? */
836         case CHINESEBIG5_CHARSET: return "hani";
837         case EASTEUROPE_CHARSET: return "latn"; /* ?? */
838         case GB2312_CHARSET: return "hani";
839         case GREEK_CHARSET: return "grek";
840         case HANGUL_CHARSET: return "hang";
841         case RUSSIAN_CHARSET: return "cyrl";
842         case SHIFTJIS_CHARSET: return "kana";
843         case TURKISH_CHARSET: return "latn"; /* ?? */
844         case VIETNAMESE_CHARSET: return "latn";
845         case JOHAB_CHARSET: return "latn"; /* ?? */
846         case ARABIC_CHARSET: return "arab";
847         case HEBREW_CHARSET: return "hebr";
848         case THAI_CHARSET: return "thai";
849         default: return "latn";
850     }
851 }
852
853 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
854 {
855     const GSUB_Feature *feature;
856     int i;
857
858     for (i = 0; i <  psc->feature_count; i++)
859         if (strncmp(psc->features[i].tag,feat,4)==0)
860             return psc->features[i].feature;
861
862     feature = NULL;
863
864     if (psc->GSUB_Table)
865     {
866         const GSUB_Script *script;
867         const GSUB_LangSys *language;
868
869         script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc));
870         if (script)
871         {
872             if (psc->userLang != 0)
873                 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
874             else
875                 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
876             if (language)
877                 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
878         }
879
880         /* try in the default (latin) table */
881         if (!feature)
882         {
883             script = GSUB_get_script_table(psc->GSUB_Table, "latn");
884             if (script)
885             {
886                 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
887                 if (language)
888                     feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
889             }
890         }
891     }
892
893     TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
894
895     psc->feature_count++;
896
897     if (psc->features)
898         psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
899     else
900         psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
901
902     lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
903     psc->features[psc->feature_count - 1].feature = feature;
904     return feature;
905 }
906
907 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)
908 {
909     const GSUB_Feature *feature;
910
911     feature = load_GSUB_feature(hdc, psa, psc, feat);
912     if (!feature)
913         return GSUB_E_NOFEATURE;
914
915     TRACE("applying feature %s\n",feat);
916     return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
917 }
918
919 static VOID *load_gsub_table(HDC hdc)
920 {
921     VOID* GSUB_Table = NULL;
922     int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
923     if (length != GDI_ERROR)
924     {
925         GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
926         GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
927         TRACE("Loaded GSUB table of %i bytes\n",length);
928     }
929     return GSUB_Table;
930 }
931
932 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
933 {
934     int offset;
935     WORD class = 0;
936     const GDEF_ClassDefFormat1 *cf1;
937
938     if (!header)
939         return 0;
940
941     offset = GET_BE_WORD(header->GlyphClassDef);
942     if (!offset)
943         return 0;
944
945     cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
946     if (GET_BE_WORD(cf1->ClassFormat) == 1)
947     {
948         if (glyph >= GET_BE_WORD(cf1->StartGlyph))
949         {
950             int index = glyph - GET_BE_WORD(cf1->StartGlyph);
951             if (index < GET_BE_WORD(cf1->GlyphCount))
952                 class = GET_BE_WORD(cf1->ClassValueArray[index]);
953         }
954     }
955     else if (GET_BE_WORD(cf1->ClassFormat) == 2)
956     {
957         const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
958         int i, top;
959         top = GET_BE_WORD(cf2->ClassRangeCount);
960         for (i = 0; i < top; i++)
961         {
962             if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
963                 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
964             {
965                 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
966                 break;
967             }
968         }
969     }
970     else
971         ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
972
973     return class;
974 }
975
976 static VOID *load_gdef_table(HDC hdc)
977 {
978     VOID* GDEF_Table = NULL;
979     int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
980     if (length != GDI_ERROR)
981     {
982         GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
983         GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
984         TRACE("Loaded GDEF table of %i bytes\n",length);
985     }
986     return GDEF_Table;
987 }
988
989 static void GDEF_UpdateGlyphProps(HDC hdc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
990 {
991     VOID* header = load_gdef_table(hdc);
992     int i;
993
994     for (i = 0; i < cGlyphs; i++)
995     {
996         WORD class;
997
998         class = GDEF_get_glyph_class(header, pwGlyphs[i]);
999
1000         switch (class)
1001         {
1002             case 0:
1003             case BaseGlyph:
1004                 pGlyphProp[i].sva.fClusterStart = 1;
1005                 pGlyphProp[i].sva.fDiacritic = 0;
1006                 pGlyphProp[i].sva.fZeroWidth = 0;
1007                 break;
1008             case LigatureGlyph:
1009                 pGlyphProp[i].sva.fClusterStart = 1;
1010                 pGlyphProp[i].sva.fDiacritic = 0;
1011                 pGlyphProp[i].sva.fZeroWidth = 0;
1012                 break;
1013             case MarkGlyph:
1014                 pGlyphProp[i].sva.fClusterStart = 0;
1015                 pGlyphProp[i].sva.fDiacritic = 1;
1016                 pGlyphProp[i].sva.fZeroWidth = 1;
1017                 break;
1018             case ComponentGlyph:
1019                 pGlyphProp[i].sva.fClusterStart = 0;
1020                 pGlyphProp[i].sva.fDiacritic = 0;
1021                 pGlyphProp[i].sva.fZeroWidth = 0;
1022                 break;
1023             default:
1024                 ERR("Unknown glyph class %i\n",class);
1025                 pGlyphProp[i].sva.fClusterStart = 1;
1026                 pGlyphProp[i].sva.fDiacritic = 0;
1027                 pGlyphProp[i].sva.fZeroWidth = 0;
1028         }
1029     }
1030 }
1031
1032 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1033 {
1034     int i;
1035
1036     for (i = 0; i < cGlyphs; i++)
1037     {
1038         if (!pGlyphProp[i].sva.fClusterStart)
1039         {
1040             int j;
1041             for (j = 0; j < cChars; j++)
1042             {
1043                 if (pwLogClust[j] == i)
1044                 {
1045                     int k = j;
1046                     while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1047                         k-=1;
1048                     if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1049                         pwLogClust[j] = pwLogClust[k];
1050                 }
1051             }
1052         }
1053     }
1054 }
1055
1056 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1057 {
1058     if (changeCount == 0)
1059         return;
1060     else
1061     {
1062         int i;
1063         int target_glyph = nextIndex - 1;
1064         int target_index = -1;
1065         int replacing_glyph = -1;
1066         int changed = 0;
1067
1068         if (write_dir > 0)
1069             for (i = 0; i < chars; i++)
1070             {
1071                 if (pwLogClust[i] == target_glyph)
1072                 {
1073                     target_index = i;
1074                     break;
1075                 }
1076             }
1077         else
1078             for (i = chars - 1; i >= 0; i--)
1079             {
1080                 if (pwLogClust[i] == target_glyph)
1081                 {
1082                     target_index = i;
1083                     break;
1084                 }
1085             }
1086         if (target_index == -1)
1087         {
1088             ERR("Unable to find target glyph\n");
1089             return;
1090         }
1091
1092         if (changeCount < 0)
1093         {
1094             /* merge glyphs */
1095             for(i = target_index; i < chars && i >= 0; i+=write_dir)
1096             {
1097                 if (pwLogClust[i] == target_glyph)
1098                     continue;
1099                 if(pwLogClust[i] == replacing_glyph)
1100                     pwLogClust[i] = target_glyph;
1101                 else
1102                 {
1103                     changed--;
1104                     if (changed >= changeCount)
1105                     {
1106                         replacing_glyph = pwLogClust[i];
1107                         pwLogClust[i] = target_glyph;
1108                     }
1109                     else
1110                         break;
1111                 }
1112             }
1113         }
1114
1115         /* renumber trailing indexes*/
1116         for(i = target_index; i < chars && i >= 0; i+=write_dir)
1117         {
1118             if (pwLogClust[i] != target_glyph)
1119                 pwLogClust[i] += changeCount;
1120         }
1121     }
1122 }
1123
1124 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 )
1125 {
1126     int i;
1127
1128     if (psc->GSUB_Table)
1129     {
1130         const GSUB_Feature *feature;
1131
1132         feature = load_GSUB_feature(hdc, psa, psc, feat);
1133         if (!feature)
1134             return GSUB_E_NOFEATURE;
1135
1136         i = 0;
1137         TRACE("applying feature %s\n",debugstr_an(feat,4));
1138         while(i < *pcGlyphs)
1139         {
1140                 INT nextIndex;
1141                 INT prevCount = *pcGlyphs;
1142                 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1143                 if (nextIndex > GSUB_E_NOGLYPH)
1144                 {
1145                     UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1146                     i = nextIndex;
1147                 }
1148                 else
1149                     i++;
1150         }
1151         return *pcGlyphs;
1152     }
1153     return GSUB_E_NOFEATURE;
1154 }
1155
1156 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1157 {
1158     if (i + delta < 0)
1159         return 0;
1160     if ( i+ delta >= cchLen)
1161         return 0;
1162
1163     i += delta;
1164
1165     return chars[i];
1166 }
1167
1168 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1169 {
1170     if (i + delta < 0)
1171     {
1172         if (psa->fLinkBefore)
1173             return jtR;
1174         else
1175             return jtU;
1176     }
1177     if ( i+ delta >= cchLen)
1178     {
1179         if (psa->fLinkAfter)
1180             return jtL;
1181         else
1182             return jtU;
1183     }
1184
1185     i += delta;
1186
1187     if (context_type[i] == jtT)
1188         return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1189     else
1190         return context_type[i];
1191 }
1192
1193 static inline BOOL right_join_causing(CHAR joining_type)
1194 {
1195     return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1196 }
1197
1198 static inline BOOL left_join_causing(CHAR joining_type)
1199 {
1200     return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1201 }
1202
1203 static inline BOOL word_break_causing(WCHAR chr)
1204 {
1205     /* we are working within a string of characters already guareented to
1206        be within one script, Syriac, so we do not worry about any characers
1207        other than the space character outside of that range */
1208     return (chr == 0 || chr == 0x20 );
1209 }
1210
1211 /*
1212  * ContextualShape_Arabic
1213  */
1214 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1215 {
1216     CHAR *context_type;
1217     INT *context_shape;
1218     INT dirR, dirL;
1219     int i;
1220
1221     if (*pcGlyphs != cChars)
1222     {
1223         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1224         return;
1225     }
1226
1227     if (!psa->fLogicalOrder && psa->fRTL)
1228     {
1229         dirR = 1;
1230         dirL = -1;
1231     }
1232     else
1233     {
1234         dirR = -1;
1235         dirL = 1;
1236     }
1237
1238     if (!psc->GSUB_Table)
1239         psc->GSUB_Table = load_gsub_table(hdc);
1240
1241     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1242     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1243
1244     for (i = 0; i < cChars; i++)
1245         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1246
1247     for (i = 0; i < cChars; i++)
1248     {
1249         if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1250             context_shape[i] = Xr;
1251         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1252             context_shape[i] = Xl;
1253         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)))
1254             context_shape[i] = Xm;
1255         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1256             context_shape[i] = Xr;
1257         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1258             context_shape[i] = Xl;
1259         else
1260             context_shape[i] = Xn;
1261     }
1262
1263     /* Contextual Shaping */
1264     i = 0;
1265     while(i < *pcGlyphs)
1266     {
1267         BOOL shaped = FALSE;
1268
1269         if (psc->GSUB_Table)
1270         {
1271             INT nextIndex;
1272             INT prevCount = *pcGlyphs;
1273             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1274             if (nextIndex > GSUB_E_NOGLYPH)
1275             {
1276                 i = nextIndex;
1277                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1278             }
1279             shaped = (nextIndex > GSUB_E_NOGLYPH);
1280         }
1281
1282         if (!shaped)
1283         {
1284             WORD newGlyph = pwOutGlyphs[i];
1285             if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1286             {
1287                 /* fall back to presentation form B */
1288                 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1289                 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1290                     pwOutGlyphs[i] = newGlyph;
1291             }
1292             i++;
1293         }
1294     }
1295
1296     HeapFree(GetProcessHeap(),0,context_shape);
1297     HeapFree(GetProcessHeap(),0,context_type);
1298 }
1299
1300 /*
1301  * ContextualShape_Syriac
1302  */
1303
1304 #define ALAPH 0x710
1305 #define DALATH 0x715
1306 #define RISH 0x72A
1307
1308 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1309 {
1310     CHAR *context_type;
1311     INT *context_shape;
1312     INT dirR, dirL;
1313     int i;
1314
1315     if (*pcGlyphs != cChars)
1316     {
1317         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1318         return;
1319     }
1320
1321     if (!psa->fLogicalOrder && psa->fRTL)
1322     {
1323         dirR = 1;
1324         dirL = -1;
1325     }
1326     else
1327     {
1328         dirR = -1;
1329         dirL = 1;
1330     }
1331
1332     if (!psc->GSUB_Table)
1333         psc->GSUB_Table = load_gsub_table(hdc);
1334
1335     if (!psc->GSUB_Table)
1336         return;
1337
1338     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1339     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1340
1341     for (i = 0; i < cChars; i++)
1342         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1343
1344     for (i = 0; i < cChars; i++)
1345     {
1346         if (pwcChars[i] == ALAPH)
1347         {
1348             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1349
1350             if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1351             context_shape[i] = Afj;
1352             else if ( rchar != DALATH && rchar != RISH &&
1353 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1354 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1355             context_shape[i] = Afn;
1356             else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1357             context_shape[i] = Afx;
1358             else
1359             context_shape[i] = Xn;
1360         }
1361         else if (context_type[i] == jtR &&
1362 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1363             context_shape[i] = Xr;
1364         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1365             context_shape[i] = Xl;
1366         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)))
1367             context_shape[i] = Xm;
1368         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1369             context_shape[i] = Xr;
1370         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1371             context_shape[i] = Xl;
1372         else
1373             context_shape[i] = Xn;
1374     }
1375
1376     /* Contextual Shaping */
1377     i = 0;
1378     while(i < *pcGlyphs)
1379     {
1380         INT nextIndex;
1381         INT prevCount = *pcGlyphs;
1382         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1383         if (nextIndex > GSUB_E_NOGLYPH)
1384         {
1385             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1386             i = nextIndex;
1387         }
1388         else
1389             i++;
1390     }
1391
1392     HeapFree(GetProcessHeap(),0,context_shape);
1393     HeapFree(GetProcessHeap(),0,context_type);
1394 }
1395
1396 /*
1397  * ContextualShape_Phags_pa
1398  */
1399
1400 #define phags_pa_CANDRABINDU  0xA873
1401 #define phags_pa_START 0xA840
1402 #define phags_pa_END  0xA87F
1403
1404 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1405 {
1406     INT *context_shape;
1407     INT dirR, dirL;
1408     int i;
1409
1410     if (*pcGlyphs != cChars)
1411     {
1412         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1413         return;
1414     }
1415
1416     if (!psa->fLogicalOrder && psa->fRTL)
1417     {
1418         dirR = 1;
1419         dirL = -1;
1420     }
1421     else
1422     {
1423         dirR = -1;
1424         dirL = 1;
1425     }
1426
1427     if (!psc->GSUB_Table)
1428         psc->GSUB_Table = load_gsub_table(hdc);
1429
1430     if (!psc->GSUB_Table)
1431         return;
1432
1433     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1434
1435     for (i = 0; i < cChars; i++)
1436     {
1437         if (pwcChars[i] >= phags_pa_START && pwcChars[i] <=  phags_pa_END)
1438         {
1439             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1440             WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1441             BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <=  phags_pa_END);
1442             BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <=  phags_pa_END);
1443
1444             if (jrchar && jlchar)
1445                 context_shape[i] = Xm;
1446             else if (jrchar)
1447                 context_shape[i] = Xr;
1448             else if (jlchar)
1449                 context_shape[i] = Xl;
1450             else
1451                 context_shape[i] = Xn;
1452         }
1453         else
1454             context_shape[i] = -1;
1455     }
1456
1457     /* Contextual Shaping */
1458     i = 0;
1459     while(i < *pcGlyphs)
1460     {
1461         if (context_shape[i] >= 0)
1462         {
1463             INT nextIndex;
1464             INT prevCount = *pcGlyphs;
1465             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1466             if (nextIndex > GSUB_E_NOGLYPH)
1467             {
1468                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1469                 i = nextIndex;
1470             }
1471             else
1472                 i++;
1473         }
1474         else
1475             i++;
1476     }
1477
1478     HeapFree(GetProcessHeap(),0,context_shape);
1479 }
1480
1481 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
1482 {
1483     int i,k;
1484
1485     for (i = 0; i < cGlyphs; i++)
1486     {
1487         int char_index[20];
1488         int char_count = 0;
1489
1490         for (k = 0; k < cChars; k++)
1491         {
1492             if (pwLogClust[k] == i)
1493             {
1494                 char_index[char_count] = k;
1495                 char_count++;
1496             }
1497         }
1498
1499         if (char_count == 0)
1500         {
1501             FIXME("No chars in this glyph?  Must be an error\n");
1502             continue;
1503         }
1504
1505         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
1506         {
1507             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
1508             pCharProp[char_index[0]].fCanGlyphAlone = 1;
1509         }
1510         else
1511             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
1512     }
1513
1514     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1515     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1516 }
1517
1518 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
1519 {
1520     int i,k;
1521     int initGlyph, finaGlyph;
1522     INT dirR, dirL;
1523     BYTE *spaces;
1524
1525     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
1526     memset(spaces,0,cGlyphs);
1527
1528     if (!psa->fLogicalOrder && psa->fRTL)
1529     {
1530         initGlyph = cGlyphs-1;
1531         finaGlyph = 0;
1532         dirR = 1;
1533         dirL = -1;
1534     }
1535     else
1536     {
1537         initGlyph = 0;
1538         finaGlyph = cGlyphs-1;
1539         dirR = -1;
1540         dirL = 1;
1541     }
1542
1543     for (i = 0; i < cGlyphs; i++)
1544     {
1545         for (k = 0; k < cChars; k++)
1546             if (pwLogClust[k] == i)
1547             {
1548                 if (pwcChars[k] == 0x0020)
1549                     spaces[i] = 1;
1550             }
1551     }
1552
1553     for (i = 0; i < cGlyphs; i++)
1554     {
1555         int char_index[20];
1556         int char_count = 0;
1557         BOOL isInit, isFinal;
1558
1559         for (k = 0; k < cChars; k++)
1560         {
1561             if (pwLogClust[k] == i)
1562             {
1563                 char_index[char_count] = k;
1564                 char_count++;
1565             }
1566         }
1567
1568         isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
1569         isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
1570
1571         if (char_count == 0)
1572         {
1573             FIXME("No chars in this glyph?  Must be an error\n");
1574             continue;
1575         }
1576
1577         if (char_count == 1)
1578         {
1579             if (pwcChars[char_index[0]] == 0x0020)  /* space */
1580             {
1581                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
1582                 pCharProp[char_index[0]].fCanGlyphAlone = 1;
1583             }
1584             else if (pwcChars[char_index[0]] == 0x0640)  /* kashida */
1585                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
1586             else if (pwcChars[char_index[0]] == 0x0633)  /* SEEN */
1587             {
1588                 if (!isInit && !isFinal)
1589                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
1590                 else if (isInit)
1591                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
1592                 else
1593                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1594             }
1595             else if (!isInit)
1596             {
1597                 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
1598                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
1599                 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
1600                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
1601                 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
1602                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
1603                 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
1604                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
1605                 else
1606                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1607             }
1608             else if (!isInit && !isFinal)
1609                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
1610             else
1611                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1612         }
1613         else if (char_count == 2)
1614         {
1615             if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) ||  (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
1616                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
1617             else if (!isInit)
1618                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
1619             else
1620                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1621         }
1622         else if (!isInit && !isFinal)
1623             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
1624         else
1625             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1626     }
1627
1628     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1629     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1630     HeapFree(GetProcessHeap(),0,spaces);
1631 }
1632
1633 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
1634 {
1635     int i,k;
1636     int finaGlyph;
1637     INT dirL;
1638     BYTE *spaces;
1639
1640     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
1641     memset(spaces,0,cGlyphs);
1642
1643     if (!psa->fLogicalOrder && psa->fRTL)
1644     {
1645         finaGlyph = 0;
1646         dirL = -1;
1647     }
1648     else
1649     {
1650         finaGlyph = cGlyphs-1;
1651         dirL = 1;
1652     }
1653
1654     for (i = 0; i < cGlyphs; i++)
1655     {
1656         for (k = 0; k < cChars; k++)
1657             if (pwLogClust[k] == i)
1658             {
1659                 if (pwcChars[k] == 0x0020)
1660                     spaces[i] = 1;
1661             }
1662     }
1663
1664     for (i = 0; i < cGlyphs; i++)
1665     {
1666         int char_index[20];
1667         int char_count = 0;
1668
1669         for (k = 0; k < cChars; k++)
1670         {
1671             if (pwLogClust[k] == i)
1672             {
1673                 char_index[char_count] = k;
1674                 char_count++;
1675             }
1676         }
1677
1678         if (char_count == 0)
1679         {
1680             FIXME("No chars in this glyph?  Must be an error\n");
1681             continue;
1682         }
1683
1684         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
1685         {
1686             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
1687             pCharProp[char_index[0]].fCanGlyphAlone = 1;
1688         }
1689         else if (i == finaGlyph)
1690             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1691         else
1692             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
1693     }
1694
1695     HeapFree(GetProcessHeap(),0,spaces);
1696     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1697     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1698
1699     /* Do not allow justification between marks and their base */
1700     for (i = 0; i < cGlyphs; i++)
1701     {
1702         if (!pGlyphProp[i].sva.fClusterStart)
1703             pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1704     }
1705 }
1706
1707 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
1708 {
1709     int i,k;
1710
1711     for (i = 0; i < cGlyphs; i++)
1712     {
1713         int char_index[20];
1714         int char_count = 0;
1715
1716         for (k = 0; k < cChars; k++)
1717         {
1718             if (pwLogClust[k] == i)
1719             {
1720                 char_index[char_count] = k;
1721                 char_count++;
1722             }
1723         }
1724
1725         if (char_count == 0)
1726         {
1727             FIXME("No chars in this glyph?  Must be an error\n");
1728             continue;
1729         }
1730
1731         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
1732         {
1733             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
1734             pCharProp[char_index[0]].fCanGlyphAlone = 1;
1735         }
1736         else
1737             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1738     }
1739     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1740     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1741 }
1742
1743 void SHAPE_CharGlyphProp(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp)
1744 {
1745     if (ShapingData[psa->eScript].charGlyphPropProc)
1746         ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
1747     else
1748         ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
1749 }
1750
1751 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1752 {
1753     if (ShapingData[psa->eScript].contextProc)
1754         ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
1755 }
1756
1757 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)
1758 {
1759     int i;
1760     INT dirL;
1761
1762     if (!rpRangeProperties)
1763         return;
1764
1765     if (!psc->GSUB_Table)
1766         psc->GSUB_Table = load_gsub_table(hdc);
1767
1768     if (!psc->GSUB_Table)
1769         return;
1770
1771     if (!psa->fLogicalOrder && psa->fRTL)
1772         dirL = -1;
1773     else
1774         dirL = 1;
1775
1776     for (i = 0; i < rpRangeProperties->cotfRecords; i++)
1777     {
1778         if (rpRangeProperties->potfRecords[i].lParameter > 0)
1779         apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
1780     }
1781 }
1782
1783 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
1784 {
1785 const TEXTRANGE_PROPERTIES *rpRangeProperties;
1786 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
1787
1788     SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
1789 }
1790
1791 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
1792 {
1793     const GSUB_Feature *feature;
1794     int i;
1795
1796     if (!ShapingData[psa->eScript].requiredFeatures)
1797         return S_OK;
1798
1799     if (!psc->GSUB_Table)
1800         psc->GSUB_Table = load_gsub_table(hdc);
1801
1802     /* we need to have at least one of the required features */
1803     i = 0;
1804     while (ShapingData[psa->eScript].requiredFeatures[i])
1805     {
1806         feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
1807         if (feature)
1808             return S_OK;
1809         i++;
1810     }
1811
1812     return USP_E_SCRIPT_NOT_IN_FONT;
1813 }