usp10: Add Devanagari script.
[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 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48
49
50 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
51
52 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);
53 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 );
54 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 );
55 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 );
56 static void ShapeCharGlyphProp_Tibet( 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 );
57 static void ShapeCharGlyphProp_Devanagari( 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 );
58
59 extern const unsigned short wine_shaping_table[];
60 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
61
62 enum joining_types {
63     jtU,
64     jtT,
65     jtR,
66     jtL,
67     jtD,
68     jtC
69 };
70
71 enum joined_forms {
72     Xn=0,
73     Xr,
74     Xl,
75     Xm,
76     /* Syriac Alaph */
77     Afj,
78     Afn,
79     Afx
80 };
81
82 #ifdef WORDS_BIGENDIAN
83 #define GET_BE_WORD(x) (x)
84 #else
85 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
86 #endif
87
88 /* These are all structures needed for the GSUB table */
89 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
90 #define GSUB_E_NOFEATURE -2
91 #define GSUB_E_NOGLYPH -1
92
93 typedef struct {
94     DWORD version;
95     WORD ScriptList;
96     WORD FeatureList;
97     WORD LookupList;
98 } GSUB_Header;
99
100 typedef struct {
101     CHAR ScriptTag[4];
102     WORD Script;
103 } GSUB_ScriptRecord;
104
105 typedef struct {
106     WORD ScriptCount;
107     GSUB_ScriptRecord ScriptRecord[1];
108 } GSUB_ScriptList;
109
110 typedef struct {
111     CHAR LangSysTag[4];
112     WORD LangSys;
113 } GSUB_LangSysRecord;
114
115 typedef struct {
116     WORD DefaultLangSys;
117     WORD LangSysCount;
118     GSUB_LangSysRecord LangSysRecord[1];
119 } GSUB_Script;
120
121 typedef struct {
122     WORD LookupOrder; /* Reserved */
123     WORD ReqFeatureIndex;
124     WORD FeatureCount;
125     WORD FeatureIndex[1];
126 } GSUB_LangSys;
127
128 typedef struct {
129     CHAR FeatureTag[4];
130     WORD Feature;
131 } GSUB_FeatureRecord;
132
133 typedef struct {
134     WORD FeatureCount;
135     GSUB_FeatureRecord FeatureRecord[1];
136 } GSUB_FeatureList;
137
138 typedef struct {
139     WORD FeatureParams; /* Reserved */
140     WORD LookupCount;
141     WORD LookupListIndex[1];
142 } GSUB_Feature;
143
144 typedef struct {
145     WORD LookupCount;
146     WORD Lookup[1];
147 } GSUB_LookupList;
148
149 typedef struct {
150     WORD LookupType;
151     WORD LookupFlag;
152     WORD SubTableCount;
153     WORD SubTable[1];
154 } GSUB_LookupTable;
155
156 typedef struct {
157     WORD CoverageFormat;
158     WORD GlyphCount;
159     WORD GlyphArray[1];
160 } GSUB_CoverageFormat1;
161
162 typedef struct {
163     WORD Start;
164     WORD End;
165     WORD StartCoverageIndex;
166 } GSUB_RangeRecord;
167
168 typedef struct {
169     WORD CoverageFormat;
170     WORD RangeCount;
171     GSUB_RangeRecord RangeRecord[1];
172 } GSUB_CoverageFormat2;
173
174 typedef struct {
175     WORD SubstFormat; /* = 1 */
176     WORD Coverage;
177     WORD DeltaGlyphID;
178 } GSUB_SingleSubstFormat1;
179
180 typedef struct {
181     WORD SubstFormat; /* = 2 */
182     WORD Coverage;
183     WORD GlyphCount;
184     WORD Substitute[1];
185 }GSUB_SingleSubstFormat2;
186
187 typedef struct {
188     WORD SubstFormat; /* = 1 */
189     WORD Coverage;
190     WORD LigSetCount;
191     WORD LigatureSet[1];
192 }GSUB_LigatureSubstFormat1;
193
194 typedef struct {
195     WORD LigatureCount;
196     WORD Ligature[1];
197 }GSUB_LigatureSet;
198
199 typedef struct{
200     WORD LigGlyph;
201     WORD CompCount;
202     WORD Component[1];
203 }GSUB_Ligature;
204
205 typedef struct{
206     WORD SequenceIndex;
207     WORD LookupListIndex;
208
209 }GSUB_SubstLookupRecord;
210
211 typedef struct{
212     WORD SubstFormat; /* = 1 */
213     WORD Coverage;
214     WORD ChainSubRuleSetCount;
215     WORD ChainSubRuleSet[1];
216 }GSUB_ChainContextSubstFormat1;
217
218 typedef struct {
219     WORD SubstFormat; /* = 3 */
220     WORD BacktrackGlyphCount;
221     WORD Coverage[1];
222 }GSUB_ChainContextSubstFormat3_1;
223
224 typedef struct{
225     WORD InputGlyphCount;
226     WORD Coverage[1];
227 }GSUB_ChainContextSubstFormat3_2;
228
229 typedef struct{
230     WORD LookaheadGlyphCount;
231     WORD Coverage[1];
232 }GSUB_ChainContextSubstFormat3_3;
233
234 typedef struct{
235     WORD SubstCount;
236     GSUB_SubstLookupRecord SubstLookupRecord[1];
237 }GSUB_ChainContextSubstFormat3_4;
238
239 typedef struct {
240     WORD SubstFormat; /* = 1 */
241     WORD Coverage;
242     WORD AlternateSetCount;
243     WORD AlternateSet[1];
244 } GSUB_AlternateSubstFormat1;
245
246 typedef struct{
247     WORD GlyphCount;
248     WORD Alternate[1];
249 } GSUB_AlternateSet;
250
251 /* These are all structures needed for the GDEF table */
252 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
253
254 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
255
256 typedef struct {
257     DWORD Version;
258     WORD GlyphClassDef;
259     WORD AttachList;
260     WORD LigCaretList;
261     WORD MarkAttachClassDef;
262 } GDEF_Header;
263
264 typedef struct {
265     WORD ClassFormat;
266     WORD StartGlyph;
267     WORD GlyphCount;
268     WORD ClassValueArray[1];
269 } GDEF_ClassDefFormat1;
270
271 typedef struct {
272     WORD Start;
273     WORD End;
274     WORD Class;
275 } GDEF_ClassRangeRecord;
276
277 typedef struct {
278     WORD ClassFormat;
279     WORD ClassRangeCount;
280     GDEF_ClassRangeRecord ClassRangeRecord[1];
281 } GDEF_ClassDefFormat2;
282
283 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
284
285 typedef struct tagVowelComponents
286 {
287     WCHAR base;
288     WCHAR parts[3];
289 } VowelComponents;
290
291 typedef struct tagConsonantComponents
292 {
293     WCHAR parts[3];
294     WCHAR output;
295 } ConsonantComponents;
296
297 /* the orders of joined_forms and contextual_features need to line up */
298 static const char* contextual_features[] =
299 {
300     "isol",
301     "fina",
302     "init",
303     "medi",
304     /* Syriac Alaph */
305     "med2",
306     "fin2",
307     "fin3"
308 };
309
310 static OPENTYPE_FEATURE_RECORD standard_features[] =
311 {
312     { MS_MAKE_TAG('l','i','g','a'), 1},
313     { MS_MAKE_TAG('c','l','i','g'), 1},
314 };
315
316 static OPENTYPE_FEATURE_RECORD arabic_features[] =
317 {
318     { MS_MAKE_TAG('r','l','i','g'), 1},
319     { MS_MAKE_TAG('c','a','l','t'), 1},
320     { MS_MAKE_TAG('l','i','g','a'), 1},
321     { MS_MAKE_TAG('d','l','i','g'), 1},
322     { MS_MAKE_TAG('c','s','w','h'), 1},
323     { MS_MAKE_TAG('m','s','e','t'), 1},
324 };
325
326 static const char* required_arabic_features[] =
327 {
328     "fina",
329     "init",
330     "medi",
331     "rlig",
332     NULL
333 };
334
335 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
336 {
337     { MS_MAKE_TAG('d','l','i','g'), 1},
338 };
339
340 static OPENTYPE_FEATURE_RECORD syriac_features[] =
341 {
342     { MS_MAKE_TAG('r','l','i','g'), 1},
343     { MS_MAKE_TAG('c','a','l','t'), 1},
344     { MS_MAKE_TAG('l','i','g','a'), 1},
345     { MS_MAKE_TAG('d','l','i','g'), 1},
346 };
347
348 static const char* required_syriac_features[] =
349 {
350     "fina",
351     "fin2",
352     "fin3",
353     "init",
354     "medi",
355     "med2",
356     "rlig",
357     NULL
358 };
359
360 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
361 {
362     /* Base forms */
363     { MS_MAKE_TAG('a','k','h','n'), 1},
364     { MS_MAKE_TAG('r','p','h','f'), 1},
365     { MS_MAKE_TAG('v','a','t','u'), 1},
366     { MS_MAKE_TAG('p','s','t','f'), 1},
367     /* Presentation forms */
368     { MS_MAKE_TAG('b','l','w','s'), 1},
369     { MS_MAKE_TAG('a','b','v','s'), 1},
370     { MS_MAKE_TAG('p','s','t','s'), 1},
371 };
372
373 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
374 {
375     { MS_MAKE_TAG('a','b','v','s'), 1},
376     { MS_MAKE_TAG('b','l','w','s'), 1},
377 };
378
379 static OPENTYPE_FEATURE_RECORD thai_features[] =
380 {
381     { MS_MAKE_TAG('c','c','m','p'), 1},
382 };
383
384 static const char* required_lao_features[] =
385 {
386     "ccmp",
387     NULL
388 };
389
390 static const char* required_devanagari_features[] =
391 {
392     "nukt",
393     "akhn",
394     "rphf",
395     "blwf",
396     "half",
397     "vatu",
398     "pres",
399     "abvs",
400     "blws",
401     "psts",
402     "haln",
403     NULL
404 };
405
406 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
407 {
408     /* Localized forms */
409     { MS_MAKE_TAG('l','o','c','l'), 1},
410     /* Base forms */
411     { MS_MAKE_TAG('n','u','k','t'), 1},
412     { MS_MAKE_TAG('a','k','h','n'), 1},
413     { MS_MAKE_TAG('r','p','h','f'), 1},
414     { MS_MAKE_TAG('r','k','r','f'), 1},
415     { MS_MAKE_TAG('b','l','w','f'), 1},
416     { MS_MAKE_TAG('h','a','l','f'), 1},
417     { MS_MAKE_TAG('v','a','t','u'), 1},
418     { MS_MAKE_TAG('c','j','c','t'), 1},
419     /* Presentation forms */
420     { MS_MAKE_TAG('p','r','e','s'), 1},
421     { MS_MAKE_TAG('a','b','v','s'), 1},
422     { MS_MAKE_TAG('b','l','w','s'), 1},
423     { MS_MAKE_TAG('p','s','t','s'), 1},
424     { MS_MAKE_TAG('h','a','l','n'), 1},
425     { MS_MAKE_TAG('c','a','l','t'), 1},
426 };
427
428 typedef struct ScriptShapeDataTag {
429     TEXTRANGE_PROPERTIES   defaultTextRange;
430     const char**           requiredFeatures;
431     CHAR                   otTag[5];
432     CHAR                   newOtTag[5];
433     ContextualShapingProc  contextProc;
434     ShapeCharGlyphPropProc charGlyphPropProc;
435 } ScriptShapeData;
436
437 /* in order of scripts */
438 static const ScriptShapeData ShapingData[] =
439 {
440     {{ standard_features, 2}, NULL, "", "", NULL, NULL},
441     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
442     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
443     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
444     {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
445     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
446     {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
447     {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
448     {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
449     {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
450     {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
451     {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
452     {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
453     {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
454     {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
455     {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
456     {{ sinhala_features, 7}, NULL, "sinh", "", ContextualShape_Sinhala, NULL},
457     {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
458     {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
459     {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
460     {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
461     {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
462     {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
463     {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
464     {{ devanagari_features, 15}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
465     {{ devanagari_features, 15}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
466 };
467
468 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
469 {
470     const GSUB_CoverageFormat1* cf1;
471
472     cf1 = table;
473
474     if (GET_BE_WORD(cf1->CoverageFormat) == 1)
475     {
476         int count = GET_BE_WORD(cf1->GlyphCount);
477         int i;
478         TRACE("Coverage Format 1, %i glyphs\n",count);
479         for (i = 0; i < count; i++)
480             if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
481                 return i;
482         return -1;
483     }
484     else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
485     {
486         const GSUB_CoverageFormat2* cf2;
487         int i;
488         int count;
489         cf2 = (const GSUB_CoverageFormat2*)cf1;
490
491         count = GET_BE_WORD(cf2->RangeCount);
492         TRACE("Coverage Format 2, %i ranges\n",count);
493         for (i = 0; i < count; i++)
494         {
495             if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
496                 return -1;
497             if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
498                 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
499             {
500                 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
501                     glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
502             }
503         }
504         return -1;
505     }
506     else
507         ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
508
509     return -1;
510 }
511
512 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
513 {
514     const GSUB_ScriptList *script;
515     const GSUB_Script *deflt = NULL;
516     int i;
517     script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
518
519     TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
520     for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
521     {
522         const GSUB_Script *scr;
523         int offset;
524
525         offset = GET_BE_WORD(script->ScriptRecord[i].Script);
526         scr = (const GSUB_Script*)((const BYTE*)script + offset);
527
528         if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
529             return scr;
530         if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
531             deflt = scr;
532     }
533     return deflt;
534 }
535
536 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
537 {
538     int i;
539     int offset;
540     const GSUB_LangSys *Lang;
541
542     TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
543
544     for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
545     {
546         offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
547         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
548
549         if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
550             return Lang;
551     }
552     offset = GET_BE_WORD(script->DefaultLangSys);
553     if (offset)
554     {
555         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
556         return Lang;
557     }
558     return NULL;
559 }
560
561 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
562 {
563     int i;
564     const GSUB_FeatureList *feature;
565     feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
566
567     TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
568     for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
569     {
570         int index = GET_BE_WORD(lang->FeatureIndex[i]);
571         if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
572         {
573             const GSUB_Feature *feat;
574             feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
575             return feat;
576         }
577     }
578     return NULL;
579 }
580
581 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
582 {
583     int j;
584     TRACE("Single Substitution Subtable\n");
585
586     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
587     {
588         int offset;
589         const GSUB_SingleSubstFormat1 *ssf1;
590         offset = GET_BE_WORD(look->SubTable[j]);
591         ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
592         if (GET_BE_WORD(ssf1->SubstFormat) == 1)
593         {
594             int offset = GET_BE_WORD(ssf1->Coverage);
595             TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
596             if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
597             {
598                 TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
599                 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
600                 TRACE(" 0x%x\n",glyphs[glyph_index]);
601                 return glyph_index + 1;
602             }
603         }
604         else
605         {
606             const GSUB_SingleSubstFormat2 *ssf2;
607             INT index;
608             INT offset;
609
610             ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
611             offset = GET_BE_WORD(ssf1->Coverage);
612             TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
613             index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
614             TRACE("  Coverage index %i\n",index);
615             if (index != -1)
616             {
617                 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
618                     return GSUB_E_NOGLYPH;
619
620                 TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
621                 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
622                 TRACE("0x%x\n",glyphs[glyph_index]);
623                 return glyph_index + 1;
624             }
625         }
626     }
627     return GSUB_E_NOGLYPH;
628 }
629
630 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
631 {
632     int j;
633     TRACE("Alternate Substitution Subtable\n");
634
635     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
636     {
637         int offset;
638         const GSUB_AlternateSubstFormat1 *asf1;
639         INT index;
640
641         offset = GET_BE_WORD(look->SubTable[j]);
642         asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
643         offset = GET_BE_WORD(asf1->Coverage);
644
645         index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
646         if (index != -1)
647         {
648             const GSUB_AlternateSet *as;
649             offset =  GET_BE_WORD(asf1->AlternateSet[index]);
650             as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
651             FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
652             if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
653                 return GSUB_E_NOGLYPH;
654
655             TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
656             glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
657             TRACE(" 0x%x\n",glyphs[glyph_index]);
658             return glyph_index + 1;
659         }
660     }
661     return GSUB_E_NOGLYPH;
662 }
663
664 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
665 {
666     int j;
667
668     TRACE("Ligature Substitution Subtable\n");
669     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
670     {
671         const GSUB_LigatureSubstFormat1 *lsf1;
672         int offset,index;
673
674         offset = GET_BE_WORD(look->SubTable[j]);
675         lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
676         offset = GET_BE_WORD(lsf1->Coverage);
677         index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
678         TRACE("  Coverage index %i\n",index);
679         if (index != -1)
680         {
681             const GSUB_LigatureSet *ls;
682             int k, count;
683
684             offset = GET_BE_WORD(lsf1->LigatureSet[index]);
685             ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
686             count = GET_BE_WORD(ls->LigatureCount);
687             TRACE("  LigatureSet has %i members\n",count);
688             for (k = 0; k < count; k++)
689             {
690                 const GSUB_Ligature *lig;
691                 int CompCount,l,CompIndex;
692
693                 offset = GET_BE_WORD(ls->Ligature[k]);
694                 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
695                 CompCount = GET_BE_WORD(lig->CompCount) - 1;
696                 CompIndex = glyph_index+write_dir;
697                 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
698                 {
699                     int CompGlyph;
700                     CompGlyph = GET_BE_WORD(lig->Component[l]);
701                     if (CompGlyph != glyphs[CompIndex])
702                         break;
703                     CompIndex += write_dir;
704                 }
705                 if (l == CompCount)
706                 {
707                     int replaceIdx = glyph_index;
708                     if (write_dir < 0)
709                         replaceIdx = glyph_index - CompCount;
710
711                     TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
712                     glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
713                     TRACE("0x%x\n",glyphs[replaceIdx]);
714                     if (CompCount > 0)
715                     {
716                         int j;
717                         for (j = replaceIdx + 1; j < *glyph_count; j++)
718                             glyphs[j] =glyphs[j+CompCount];
719                         *glyph_count = *glyph_count - CompCount;
720                     }
721                     return replaceIdx + 1;
722                 }
723             }
724         }
725     }
726     return GSUB_E_NOGLYPH;
727 }
728
729 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
730 {
731     int j;
732     BOOL done = FALSE;
733
734     TRACE("Chaining Contextual Substitution Subtable\n");
735     for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
736     {
737         const GSUB_ChainContextSubstFormat1 *ccsf1;
738         int offset;
739         int dirLookahead = write_dir;
740         int dirBacktrack = -1 * write_dir;
741
742         offset = GET_BE_WORD(look->SubTable[j]);
743         ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
744         if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
745         {
746             FIXME("  TODO: subtype 1 (Simple context glyph substitution)\n");
747             return -1;
748         }
749         else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
750         {
751             FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
752             return -1;
753         }
754         else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
755         {
756             int k;
757             int indexGlyphs;
758             const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
759             const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
760             const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
761             const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
762             int newIndex = glyph_index;
763
764             ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
765
766             TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
767
768             for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
769             {
770                 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
771                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
772                     break;
773             }
774             if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
775                 return -1;
776             TRACE("Matched Backtrack\n");
777
778             ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
779
780             indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
781             for (k = 0; k < indexGlyphs; k++)
782             {
783                 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
784                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
785                     break;
786             }
787             if (k != indexGlyphs)
788                 return -1;
789             TRACE("Matched IndexGlyphs\n");
790
791             ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
792
793             for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
794             {
795                 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
796                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
797                     break;
798             }
799             if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
800                 return -1;
801             TRACE("Matched LookAhead\n");
802
803             ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
804
805             for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
806             {
807                 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
808                 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
809
810                 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
811                 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
812                 if (newIndex == -1)
813                 {
814                     ERR("Chain failed to generate a glyph\n");
815                     return -1;
816                 }
817             }
818             return newIndex + 1;
819         }
820     }
821     return -1;
822 }
823
824 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
825 {
826     int offset;
827     const GSUB_LookupTable *look;
828
829     offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
830     look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
831     TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
832     switch(GET_BE_WORD(look->LookupType))
833     {
834         case 1:
835             return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
836         case 3:
837             return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
838         case 4:
839             return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
840         case 6:
841             return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
842         default:
843             FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
844     }
845     return GSUB_E_NOGLYPH;
846 }
847
848 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
849 {
850     int i;
851     int out_index = GSUB_E_NOGLYPH;
852     const GSUB_LookupList *lookup;
853
854     lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
855
856     TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
857     for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
858     {
859         out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
860         if (out_index != GSUB_E_NOGLYPH)
861             break;
862     }
863     if (out_index == GSUB_E_NOGLYPH)
864         TRACE("lookups found no glyphs\n");
865     else
866     {
867         int out2;
868         out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
869         if (out2!=GSUB_E_NOGLYPH)
870             out_index = out2;
871     }
872     return out_index;
873 }
874
875 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
876 {
877     UINT charset;
878
879     if (psc->userScript != 0)
880     {
881         if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
882             return ShapingData[psa->eScript].newOtTag;
883         else
884             return (char*)&psc->userScript;
885     }
886
887     if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
888         return ShapingData[psa->eScript].newOtTag;
889
890     if (ShapingData[psa->eScript].otTag[0] != 0)
891         return ShapingData[psa->eScript].otTag;
892
893     /*
894      * fall back to the font charset
895      */
896     charset = GetTextCharsetInfo(hdc, NULL, 0x0);
897     switch (charset)
898     {
899         case ANSI_CHARSET: return "latn";
900         case BALTIC_CHARSET: return "latn"; /* ?? */
901         case CHINESEBIG5_CHARSET: return "hani";
902         case EASTEUROPE_CHARSET: return "latn"; /* ?? */
903         case GB2312_CHARSET: return "hani";
904         case GREEK_CHARSET: return "grek";
905         case HANGUL_CHARSET: return "hang";
906         case RUSSIAN_CHARSET: return "cyrl";
907         case SHIFTJIS_CHARSET: return "kana";
908         case TURKISH_CHARSET: return "latn"; /* ?? */
909         case VIETNAMESE_CHARSET: return "latn";
910         case JOHAB_CHARSET: return "latn"; /* ?? */
911         case ARABIC_CHARSET: return "arab";
912         case HEBREW_CHARSET: return "hebr";
913         case THAI_CHARSET: return "thai";
914         default: return "latn";
915     }
916 }
917
918 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
919 {
920     const GSUB_Feature *feature;
921     int i;
922
923     for (i = 0; i <  psc->feature_count; i++)
924         if (strncmp(psc->features[i].tag,feat,4)==0)
925             return psc->features[i].feature;
926
927     feature = NULL;
928
929     if (psc->GSUB_Table)
930     {
931         const GSUB_Script *script;
932         const GSUB_LangSys *language;
933         int attempt = 2;
934
935         do
936         {
937             script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
938             attempt--;
939             if (script)
940             {
941                 if (psc->userLang != 0)
942                     language = GSUB_get_lang_table(script,(char*)&psc->userLang);
943                 else
944                     language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
945                 if (language)
946                     feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
947             }
948         } while(attempt && !feature);
949
950         /* try in the default (latin) table */
951         if (!feature)
952         {
953             script = GSUB_get_script_table(psc->GSUB_Table, "latn");
954             if (script)
955             {
956                 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
957                 if (language)
958                     feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
959             }
960         }
961     }
962
963     TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
964
965     psc->feature_count++;
966
967     if (psc->features)
968         psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
969     else
970         psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
971
972     lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
973     psc->features[psc->feature_count - 1].feature = feature;
974     return feature;
975 }
976
977 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)
978 {
979     const GSUB_Feature *feature;
980
981     feature = load_GSUB_feature(hdc, psa, psc, feat);
982     if (!feature)
983         return GSUB_E_NOFEATURE;
984
985     TRACE("applying feature %s\n",feat);
986     return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
987 }
988
989 static VOID *load_gsub_table(HDC hdc)
990 {
991     VOID* GSUB_Table = NULL;
992     int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
993     if (length != GDI_ERROR)
994     {
995         GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
996         GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
997         TRACE("Loaded GSUB table of %i bytes\n",length);
998     }
999     return GSUB_Table;
1000 }
1001
1002 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1003 {
1004     int offset;
1005     WORD class = 0;
1006     const GDEF_ClassDefFormat1 *cf1;
1007
1008     if (!header)
1009         return 0;
1010
1011     offset = GET_BE_WORD(header->GlyphClassDef);
1012     if (!offset)
1013         return 0;
1014
1015     cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1016     if (GET_BE_WORD(cf1->ClassFormat) == 1)
1017     {
1018         if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1019         {
1020             int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1021             if (index < GET_BE_WORD(cf1->GlyphCount))
1022                 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1023         }
1024     }
1025     else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1026     {
1027         const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1028         int i, top;
1029         top = GET_BE_WORD(cf2->ClassRangeCount);
1030         for (i = 0; i < top; i++)
1031         {
1032             if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1033                 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1034             {
1035                 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1036                 break;
1037             }
1038         }
1039     }
1040     else
1041         ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1042
1043     return class;
1044 }
1045
1046 static VOID *load_gdef_table(HDC hdc)
1047 {
1048     VOID* GDEF_Table = NULL;
1049     int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1050     if (length != GDI_ERROR)
1051     {
1052         GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1053         GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1054         TRACE("Loaded GDEF table of %i bytes\n",length);
1055     }
1056     return GDEF_Table;
1057 }
1058
1059 static void GDEF_UpdateGlyphProps(HDC hdc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1060 {
1061     VOID* header = load_gdef_table(hdc);
1062     int i;
1063
1064     for (i = 0; i < cGlyphs; i++)
1065     {
1066         WORD class;
1067
1068         class = GDEF_get_glyph_class(header, pwGlyphs[i]);
1069
1070         switch (class)
1071         {
1072             case 0:
1073             case BaseGlyph:
1074                 pGlyphProp[i].sva.fClusterStart = 1;
1075                 pGlyphProp[i].sva.fDiacritic = 0;
1076                 pGlyphProp[i].sva.fZeroWidth = 0;
1077                 break;
1078             case LigatureGlyph:
1079                 pGlyphProp[i].sva.fClusterStart = 1;
1080                 pGlyphProp[i].sva.fDiacritic = 0;
1081                 pGlyphProp[i].sva.fZeroWidth = 0;
1082                 break;
1083             case MarkGlyph:
1084                 pGlyphProp[i].sva.fClusterStart = 0;
1085                 pGlyphProp[i].sva.fDiacritic = 1;
1086                 pGlyphProp[i].sva.fZeroWidth = 1;
1087                 break;
1088             case ComponentGlyph:
1089                 pGlyphProp[i].sva.fClusterStart = 0;
1090                 pGlyphProp[i].sva.fDiacritic = 0;
1091                 pGlyphProp[i].sva.fZeroWidth = 0;
1092                 break;
1093             default:
1094                 ERR("Unknown glyph class %i\n",class);
1095                 pGlyphProp[i].sva.fClusterStart = 1;
1096                 pGlyphProp[i].sva.fDiacritic = 0;
1097                 pGlyphProp[i].sva.fZeroWidth = 0;
1098         }
1099     }
1100 }
1101
1102 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1103 {
1104     int i;
1105
1106     for (i = 0; i < cGlyphs; i++)
1107     {
1108         if (!pGlyphProp[i].sva.fClusterStart)
1109         {
1110             int j;
1111             for (j = 0; j < cChars; j++)
1112             {
1113                 if (pwLogClust[j] == i)
1114                 {
1115                     int k = j;
1116                     while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1117                         k-=1;
1118                     if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1119                         pwLogClust[j] = pwLogClust[k];
1120                 }
1121             }
1122         }
1123     }
1124 }
1125
1126 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1127 {
1128     if (changeCount == 0)
1129         return;
1130     else
1131     {
1132         int i;
1133         int target_glyph = nextIndex - 1;
1134         int target_index = -1;
1135         int replacing_glyph = -1;
1136         int changed = 0;
1137
1138         if (write_dir > 0)
1139             for (i = 0; i < chars; i++)
1140             {
1141                 if (pwLogClust[i] == target_glyph)
1142                 {
1143                     target_index = i;
1144                     break;
1145                 }
1146             }
1147         else
1148             for (i = chars - 1; i >= 0; i--)
1149             {
1150                 if (pwLogClust[i] == target_glyph)
1151                 {
1152                     target_index = i;
1153                     break;
1154                 }
1155             }
1156         if (target_index == -1)
1157         {
1158             ERR("Unable to find target glyph\n");
1159             return;
1160         }
1161
1162         if (changeCount < 0)
1163         {
1164             /* merge glyphs */
1165             for(i = target_index; i < chars && i >= 0; i+=write_dir)
1166             {
1167                 if (pwLogClust[i] == target_glyph)
1168                     continue;
1169                 if(pwLogClust[i] == replacing_glyph)
1170                     pwLogClust[i] = target_glyph;
1171                 else
1172                 {
1173                     changed--;
1174                     if (changed >= changeCount)
1175                     {
1176                         replacing_glyph = pwLogClust[i];
1177                         pwLogClust[i] = target_glyph;
1178                     }
1179                     else
1180                         break;
1181                 }
1182             }
1183         }
1184
1185         /* renumber trailing indexes*/
1186         for(i = target_index; i < chars && i >= 0; i+=write_dir)
1187         {
1188             if (pwLogClust[i] != target_glyph)
1189                 pwLogClust[i] += changeCount;
1190         }
1191     }
1192 }
1193
1194 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 )
1195 {
1196     int i;
1197
1198     if (psc->GSUB_Table)
1199     {
1200         const GSUB_Feature *feature;
1201
1202         feature = load_GSUB_feature(hdc, psa, psc, feat);
1203         if (!feature)
1204             return GSUB_E_NOFEATURE;
1205
1206         i = 0;
1207         TRACE("applying feature %s\n",debugstr_an(feat,4));
1208         while(i < *pcGlyphs)
1209         {
1210                 INT nextIndex;
1211                 INT prevCount = *pcGlyphs;
1212                 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1213                 if (nextIndex > GSUB_E_NOGLYPH)
1214                 {
1215                     UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1216                     i = nextIndex;
1217                 }
1218                 else
1219                     i++;
1220         }
1221         return *pcGlyphs;
1222     }
1223     return GSUB_E_NOFEATURE;
1224 }
1225
1226 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1227 {
1228     if (i + delta < 0)
1229         return 0;
1230     if ( i+ delta >= cchLen)
1231         return 0;
1232
1233     i += delta;
1234
1235     return chars[i];
1236 }
1237
1238 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1239 {
1240     if (i + delta < 0)
1241     {
1242         if (psa->fLinkBefore)
1243             return jtR;
1244         else
1245             return jtU;
1246     }
1247     if ( i+ delta >= cchLen)
1248     {
1249         if (psa->fLinkAfter)
1250             return jtL;
1251         else
1252             return jtU;
1253     }
1254
1255     i += delta;
1256
1257     if (context_type[i] == jtT)
1258         return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1259     else
1260         return context_type[i];
1261 }
1262
1263 static inline BOOL right_join_causing(CHAR joining_type)
1264 {
1265     return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1266 }
1267
1268 static inline BOOL left_join_causing(CHAR joining_type)
1269 {
1270     return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1271 }
1272
1273 static inline BOOL word_break_causing(WCHAR chr)
1274 {
1275     /* we are working within a string of characters already guareented to
1276        be within one script, Syriac, so we do not worry about any characers
1277        other than the space character outside of that range */
1278     return (chr == 0 || chr == 0x20 );
1279 }
1280
1281 /*
1282  * ContextualShape_Arabic
1283  */
1284 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1285 {
1286     CHAR *context_type;
1287     INT *context_shape;
1288     INT dirR, dirL;
1289     int i;
1290
1291     if (*pcGlyphs != cChars)
1292     {
1293         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1294         return;
1295     }
1296
1297     if (!psa->fLogicalOrder && psa->fRTL)
1298     {
1299         dirR = 1;
1300         dirL = -1;
1301     }
1302     else
1303     {
1304         dirR = -1;
1305         dirL = 1;
1306     }
1307
1308     if (!psc->GSUB_Table)
1309         psc->GSUB_Table = load_gsub_table(hdc);
1310
1311     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1312     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1313
1314     for (i = 0; i < cChars; i++)
1315         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1316
1317     for (i = 0; i < cChars; i++)
1318     {
1319         if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1320             context_shape[i] = Xr;
1321         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1322             context_shape[i] = Xl;
1323         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)))
1324             context_shape[i] = Xm;
1325         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1326             context_shape[i] = Xr;
1327         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1328             context_shape[i] = Xl;
1329         else
1330             context_shape[i] = Xn;
1331     }
1332
1333     /* Contextual Shaping */
1334     i = 0;
1335     while(i < *pcGlyphs)
1336     {
1337         BOOL shaped = FALSE;
1338
1339         if (psc->GSUB_Table)
1340         {
1341             INT nextIndex;
1342             INT prevCount = *pcGlyphs;
1343             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1344             if (nextIndex > GSUB_E_NOGLYPH)
1345             {
1346                 i = nextIndex;
1347                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1348             }
1349             shaped = (nextIndex > GSUB_E_NOGLYPH);
1350         }
1351
1352         if (!shaped)
1353         {
1354             WORD newGlyph = pwOutGlyphs[i];
1355             if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1356             {
1357                 /* fall back to presentation form B */
1358                 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1359                 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1360                     pwOutGlyphs[i] = newGlyph;
1361             }
1362             i++;
1363         }
1364     }
1365
1366     HeapFree(GetProcessHeap(),0,context_shape);
1367     HeapFree(GetProcessHeap(),0,context_type);
1368 }
1369
1370 /*
1371  * ContextualShape_Syriac
1372  */
1373
1374 #define ALAPH 0x710
1375 #define DALATH 0x715
1376 #define RISH 0x72A
1377
1378 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1379 {
1380     CHAR *context_type;
1381     INT *context_shape;
1382     INT dirR, dirL;
1383     int i;
1384
1385     if (*pcGlyphs != cChars)
1386     {
1387         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1388         return;
1389     }
1390
1391     if (!psa->fLogicalOrder && psa->fRTL)
1392     {
1393         dirR = 1;
1394         dirL = -1;
1395     }
1396     else
1397     {
1398         dirR = -1;
1399         dirL = 1;
1400     }
1401
1402     if (!psc->GSUB_Table)
1403         psc->GSUB_Table = load_gsub_table(hdc);
1404
1405     if (!psc->GSUB_Table)
1406         return;
1407
1408     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1409     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1410
1411     for (i = 0; i < cChars; i++)
1412         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1413
1414     for (i = 0; i < cChars; i++)
1415     {
1416         if (pwcChars[i] == ALAPH)
1417         {
1418             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1419
1420             if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1421             context_shape[i] = Afj;
1422             else if ( rchar != DALATH && rchar != RISH &&
1423 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1424 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1425             context_shape[i] = Afn;
1426             else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1427             context_shape[i] = Afx;
1428             else
1429             context_shape[i] = Xn;
1430         }
1431         else if (context_type[i] == jtR &&
1432 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1433             context_shape[i] = Xr;
1434         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1435             context_shape[i] = Xl;
1436         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)))
1437             context_shape[i] = Xm;
1438         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1439             context_shape[i] = Xr;
1440         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1441             context_shape[i] = Xl;
1442         else
1443             context_shape[i] = Xn;
1444     }
1445
1446     /* Contextual Shaping */
1447     i = 0;
1448     while(i < *pcGlyphs)
1449     {
1450         INT nextIndex;
1451         INT prevCount = *pcGlyphs;
1452         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1453         if (nextIndex > GSUB_E_NOGLYPH)
1454         {
1455             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1456             i = nextIndex;
1457         }
1458         else
1459             i++;
1460     }
1461
1462     HeapFree(GetProcessHeap(),0,context_shape);
1463     HeapFree(GetProcessHeap(),0,context_type);
1464 }
1465
1466 /*
1467  * ContextualShape_Phags_pa
1468  */
1469
1470 #define phags_pa_CANDRABINDU  0xA873
1471 #define phags_pa_START 0xA840
1472 #define phags_pa_END  0xA87F
1473
1474 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1475 {
1476     INT *context_shape;
1477     INT dirR, dirL;
1478     int i;
1479
1480     if (*pcGlyphs != cChars)
1481     {
1482         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1483         return;
1484     }
1485
1486     if (!psa->fLogicalOrder && psa->fRTL)
1487     {
1488         dirR = 1;
1489         dirL = -1;
1490     }
1491     else
1492     {
1493         dirR = -1;
1494         dirL = 1;
1495     }
1496
1497     if (!psc->GSUB_Table)
1498         psc->GSUB_Table = load_gsub_table(hdc);
1499
1500     if (!psc->GSUB_Table)
1501         return;
1502
1503     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1504
1505     for (i = 0; i < cChars; i++)
1506     {
1507         if (pwcChars[i] >= phags_pa_START && pwcChars[i] <=  phags_pa_END)
1508         {
1509             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1510             WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1511             BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <=  phags_pa_END);
1512             BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <=  phags_pa_END);
1513
1514             if (jrchar && jlchar)
1515                 context_shape[i] = Xm;
1516             else if (jrchar)
1517                 context_shape[i] = Xr;
1518             else if (jlchar)
1519                 context_shape[i] = Xl;
1520             else
1521                 context_shape[i] = Xn;
1522         }
1523         else
1524             context_shape[i] = -1;
1525     }
1526
1527     /* Contextual Shaping */
1528     i = 0;
1529     while(i < *pcGlyphs)
1530     {
1531         if (context_shape[i] >= 0)
1532         {
1533             INT nextIndex;
1534             INT prevCount = *pcGlyphs;
1535             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1536             if (nextIndex > GSUB_E_NOGLYPH)
1537             {
1538                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1539                 i = nextIndex;
1540             }
1541             else
1542                 i++;
1543         }
1544         else
1545             i++;
1546     }
1547
1548     HeapFree(GetProcessHeap(),0,context_shape);
1549 }
1550
1551 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1552 {
1553     int i;
1554
1555     /* Replace */
1556     pwOutChars[cWalk] = replacements[0];
1557     cWalk=cWalk+1;
1558
1559     /* Insert */
1560     for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1561     {
1562         int j;
1563         for (j = *pcChars; j > cWalk; j--)
1564             pwOutChars[j] = pwOutChars[j-1];
1565         *pcChars= *pcChars+1;
1566         pwOutChars[cWalk] = replacements[i];
1567         cWalk = cWalk+1;
1568     }
1569 }
1570
1571 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1572 {
1573     int i;
1574     int cWalk;
1575
1576     for (cWalk = 0; cWalk < *pcChars; cWalk++)
1577     {
1578         for (i = 0; vowels[i].base != 0x0; i++)
1579         {
1580             if (pwOutChars[cWalk] == vowels[i].base)
1581             {
1582                 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1583                 break;
1584             }
1585         }
1586     }
1587 }
1588
1589 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1590 {
1591     int i;
1592     int cWalk;
1593
1594     for (cWalk = 0; cWalk < *pcChars; cWalk++)
1595     {
1596         for (i = 0; consonants[i].output!= 0x0; i++)
1597         {
1598             int j;
1599             for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1600                 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1601                     break;
1602
1603             if (consonants[i].parts[j]==0x0) /* matched all */
1604             {
1605                 int k;
1606                 j--;
1607                 pwOutChars[cWalk] = consonants[i].output;
1608                 for(k = cWalk+1; k < *pcChars - j; k++)
1609                     pwOutChars[k] = pwOutChars[k+j];
1610                 *pcChars = *pcChars - j;
1611                 break;
1612             }
1613         }
1614         cWalk++;
1615     }
1616 }
1617
1618 static void Reorder_Ra_follows_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1619 {
1620     if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1621     {
1622         int j;
1623         WORD Ra = pwChar[start];
1624         WORD H = pwChar[start+1];
1625
1626         TRACE("Doing reorder of Ra to %i\n",main);
1627         for (j = start; j < main-1; j++)
1628             pwChar[j] = pwChar[j+2];
1629         pwChar[main-1] = Ra;
1630         pwChar[main] = H;
1631     }
1632 }
1633
1634 static void Reorder_Ra_follows_mantra_post(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1635 {
1636     if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1637     {
1638         int j,loc;
1639         WORD Ra = pwChar[start];
1640         WORD H = pwChar[start+1];
1641         for (loc = main; loc > end; loc++)
1642             if (lexical(pwChar[loc]) == lex_Mantra_post)
1643                 break;
1644         if (loc == end) loc = main;
1645
1646         TRACE("Doing reorder of Ra to %i\n",loc);
1647         for (j = start; j < loc-1; j++)
1648             pwChar[j] = pwChar[j+2];
1649         pwChar[loc-1] = Ra;
1650         pwChar[loc] = H;
1651     }
1652 }
1653
1654 static void Reorder_Mantra_precede_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1655 {
1656     int i;
1657
1658     /* reorder Mantras */
1659     if (end > main)
1660     {
1661         for (i = 1; i <= end-main; i++)
1662         {
1663             if (lexical(pwChar[main+i]) == lex_Mantra_pre)
1664             {
1665                 int j;
1666                 WCHAR c = pwChar[main+i];
1667                 TRACE("Doing reorder of %x %x\n",c,pwChar[main]);
1668                 for (j = main+i; j > main; j--)
1669                     pwChar[j] = pwChar[j-1];
1670                 pwChar[main] = c;
1671             }
1672         }
1673     }
1674 }
1675
1676 static void Reorder_Mantra_precede_syllable(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1677 {
1678     int i;
1679
1680     /* reorder Mantras */
1681     if (end > main)
1682     {
1683         for (i = 1; i <= end-main; i++)
1684         {
1685             if (lexical(pwChar[main+i]) == lex_Mantra_pre)
1686             {
1687                 int j;
1688                 WCHAR c = pwChar[main+i];
1689                 TRACE("Doing reorder of %x to %i\n",c,start);
1690                 for (j = main+i; j > start; j--)
1691                     pwChar[j] = pwChar[j-1];
1692                 pwChar[start] = c;
1693             }
1694         }
1695     }
1696 }
1697
1698 static void Reorder_Like_Sinhala(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1699 {
1700     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1701     if (start == main && main == end)  return;
1702
1703     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1704     if (lexical(pwChar[main]) == lex_Vowel) return;
1705
1706     Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1707     Reorder_Mantra_precede_base(pwChar, start, main, end, lexical);
1708 }
1709
1710 static void Reorder_Like_Devanagari(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1711 {
1712     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1713     if (start == main && main == end)  return;
1714
1715     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1716     if (lexical(pwChar[main]) == lex_Vowel) return;
1717
1718     Reorder_Ra_follows_mantra_post(pwChar, start, main, end, lexical);
1719     Reorder_Mantra_precede_syllable(pwChar, start, main, end, lexical);
1720 }
1721
1722 static int sinhala_lex(WCHAR c)
1723 {
1724     switch (c)
1725     {
1726         case 0x0DCA: return lex_Halant;
1727         case 0x0DCF:
1728         case 0x0DDF:
1729         case 0x0DD8: return lex_Mantra_post;
1730         case 0x0DD9:
1731         case 0x0DDB: return lex_Mantra_pre;
1732         case 0x0DDA:
1733         case 0x0DDC: return lex_Composed_Vowel;
1734         case 0x200D: return lex_ZWJ;
1735         case 0x200C: return lex_ZWNJ;
1736         case 0x00A0: return lex_NBSP;
1737         default:
1738             if (c>=0x0D82 && c <=0x0D83) return lex_Modifier;
1739             else if (c>=0x0D85 && c <=0x0D96) return lex_Vowel;
1740             else if (c>=0x0D96 && c <=0x0DC6) return lex_Consonant;
1741             else if (c>=0x0DD0 && c <=0x0DD1) return lex_Mantra_post;
1742             else if (c>=0x0DD2 && c <=0x0DD3) return lex_Mantra_above;
1743             else if (c>=0x0DD4 && c <=0x0DD6) return lex_Mantra_below;
1744             else if (c>=0x0DDD && c <=0x0DDE) return lex_Composed_Vowel;
1745             else if (c>=0x0DF2 && c <=0x0DF3) return lex_Mantra_post;
1746             else return lex_Generic;
1747     }
1748 }
1749
1750 static const VowelComponents Sinhala_vowels[] = {
1751             {0x0DDA, {0x0DD9,0x0DCA,0x0}},
1752             {0x0DDC, {0x0DD9,0x0DCF,0x0}},
1753             {0x0DDD, {0x0DD9,0x0DCF,0x0DCA}},
1754             {0x0DDE, {0x0DD9,0x0DDF,0x0}},
1755             {0x0000, {0x0000,0x0000,0x0}}};
1756
1757 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1758 {
1759     int cCount = cChars;
1760     WCHAR *input;
1761
1762     if (*pcGlyphs != cChars)
1763     {
1764         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1765         return;
1766     }
1767
1768     input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
1769
1770     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1771
1772     /* Step 1:  Decompose multi part vowels */
1773     DecomposeVowels(hdc, input,  &cCount, Sinhala_vowels);
1774
1775     TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1776
1777     /* Step 2:  Reorder within Syllables */
1778     Indic_ReorderCharacters( input, cCount, sinhala_lex, Reorder_Like_Sinhala);
1779     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1780
1781     /* Step 3:  Get glyphs */
1782     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1783     *pcGlyphs = cCount;
1784
1785     HeapFree(GetProcessHeap(),0,input);
1786 }
1787
1788 static int devanagari_lex(WCHAR c)
1789 {
1790     switch (c)
1791     {
1792         case 0x0951:
1793         case 0x0952:
1794         case 0x0903: return lex_Modifier;
1795         case 0x0930: return lex_Ra;
1796         case 0x093C: return lex_Nukta;
1797         case 0x0940:
1798         case 0x093E: return lex_Mantra_post;
1799         case 0x093F: return lex_Mantra_pre;
1800         case 0x094D: return lex_Halant;
1801         case 0x0972: return lex_Vowel;
1802         case 0x200C: return lex_ZWNJ;
1803         case 0x200D: return lex_ZWJ;
1804         default:
1805             if (c>=0x0901 && c<=0x0902) return lex_Mantra_above;
1806             else if (c>=0x0904 && c<=0x0914) return lex_Vowel;
1807             else if (c>=0x0915 && c<=0x0939) return lex_Consonant;
1808             else if (c>=0x0941 && c<=0x0944) return lex_Mantra_below;
1809             else if (c>=0x0945 && c<=0x0948) return lex_Mantra_above;
1810             else if (c>=0x0949 && c<=0x094C) return lex_Mantra_post;
1811             else if (c>=0x0953 && c<=0x0954) return lex_Modifier;
1812             else if (c>=0x0958 && c<=0x095F) return lex_Consonant;
1813             else if (c>=0x0960 && c<=0x0961) return lex_Vowel;
1814             else if (c>=0x0962 && c<=0x0963) return lex_Mantra_below;
1815             else if (c>=0x097B && c<=0x097C) return lex_Consonant;
1816             else if (c>=0x097E && c<=0x097F) return lex_Consonant;
1817             else return lex_Generic;
1818     }
1819 }
1820
1821 static const ConsonantComponents Devanagari_consonants[] ={
1822     {{0x0928, 0x093C, 0x00000}, 0x0929},
1823     {{0x0930, 0x093C, 0x00000}, 0x0931},
1824     {{0x0933, 0x093C, 0x00000}, 0x0934},
1825     {{0x0915, 0x093C, 0x00000}, 0x0958},
1826     {{0x0916, 0x093C, 0x00000}, 0x0959},
1827     {{0x0917, 0x093C, 0x00000}, 0x095A},
1828     {{0x091C, 0x093C, 0x00000}, 0x095B},
1829     {{0x0921, 0x093C, 0x00000}, 0x095C},
1830     {{0x0922, 0x093C, 0x00000}, 0x095D},
1831     {{0x092B, 0x093C, 0x00000}, 0x095E},
1832     {{0x092F, 0x093C, 0x00000}, 0x095F}};
1833
1834 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1835 {
1836     int cCount = cChars;
1837     WCHAR *input;
1838
1839     if (*pcGlyphs != cChars)
1840     {
1841         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1842         return;
1843     }
1844
1845     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
1846     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1847
1848     /* Step 1: Compose Consonant and Nukta */
1849     ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
1850     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1851
1852     /* Step 2: Reorder within Syllables */
1853     Indic_ReorderCharacters( input, cCount, devanagari_lex, Reorder_Like_Devanagari);
1854     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1855     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1856     *pcGlyphs = cCount;
1857
1858     HeapFree(GetProcessHeap(),0,input);
1859 }
1860
1861 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)
1862 {
1863     int i,k;
1864
1865     for (i = 0; i < cGlyphs; i++)
1866     {
1867         int char_index[20];
1868         int char_count = 0;
1869
1870         for (k = 0; k < cChars; k++)
1871         {
1872             if (pwLogClust[k] == i)
1873             {
1874                 char_index[char_count] = k;
1875                 char_count++;
1876             }
1877         }
1878
1879         if (char_count == 0)
1880         {
1881             FIXME("No chars in this glyph?  Must be an error\n");
1882             continue;
1883         }
1884
1885         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
1886         {
1887             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
1888             pCharProp[char_index[0]].fCanGlyphAlone = 1;
1889         }
1890         else
1891             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
1892     }
1893
1894     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1895     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1896 }
1897
1898 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 )
1899 {
1900     int i,k;
1901     int initGlyph, finaGlyph;
1902     INT dirR, dirL;
1903     BYTE *spaces;
1904
1905     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
1906     memset(spaces,0,cGlyphs);
1907
1908     if (!psa->fLogicalOrder && psa->fRTL)
1909     {
1910         initGlyph = cGlyphs-1;
1911         finaGlyph = 0;
1912         dirR = 1;
1913         dirL = -1;
1914     }
1915     else
1916     {
1917         initGlyph = 0;
1918         finaGlyph = cGlyphs-1;
1919         dirR = -1;
1920         dirL = 1;
1921     }
1922
1923     for (i = 0; i < cGlyphs; i++)
1924     {
1925         for (k = 0; k < cChars; k++)
1926             if (pwLogClust[k] == i)
1927             {
1928                 if (pwcChars[k] == 0x0020)
1929                     spaces[i] = 1;
1930             }
1931     }
1932
1933     for (i = 0; i < cGlyphs; i++)
1934     {
1935         int char_index[20];
1936         int char_count = 0;
1937         BOOL isInit, isFinal;
1938
1939         for (k = 0; k < cChars; k++)
1940         {
1941             if (pwLogClust[k] == i)
1942             {
1943                 char_index[char_count] = k;
1944                 char_count++;
1945             }
1946         }
1947
1948         isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
1949         isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
1950
1951         if (char_count == 0)
1952         {
1953             FIXME("No chars in this glyph?  Must be an error\n");
1954             continue;
1955         }
1956
1957         if (char_count == 1)
1958         {
1959             if (pwcChars[char_index[0]] == 0x0020)  /* space */
1960             {
1961                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
1962                 pCharProp[char_index[0]].fCanGlyphAlone = 1;
1963             }
1964             else if (pwcChars[char_index[0]] == 0x0640)  /* kashida */
1965                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
1966             else if (pwcChars[char_index[0]] == 0x0633)  /* SEEN */
1967             {
1968                 if (!isInit && !isFinal)
1969                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
1970                 else if (isInit)
1971                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
1972                 else
1973                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1974             }
1975             else if (!isInit)
1976             {
1977                 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
1978                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
1979                 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
1980                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
1981                 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
1982                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
1983                 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
1984                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
1985                 else
1986                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1987             }
1988             else if (!isInit && !isFinal)
1989                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
1990             else
1991                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1992         }
1993         else if (char_count == 2)
1994         {
1995             if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) ||  (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
1996                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
1997             else if (!isInit)
1998                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
1999             else
2000                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2001         }
2002         else if (!isInit && !isFinal)
2003             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2004         else
2005             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2006     }
2007
2008     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2009     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2010     HeapFree(GetProcessHeap(),0,spaces);
2011 }
2012
2013 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 )
2014 {
2015     int i,k;
2016     int finaGlyph;
2017     INT dirL;
2018     BYTE *spaces;
2019
2020     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2021     memset(spaces,0,cGlyphs);
2022
2023     if (!psa->fLogicalOrder && psa->fRTL)
2024     {
2025         finaGlyph = 0;
2026         dirL = -1;
2027     }
2028     else
2029     {
2030         finaGlyph = cGlyphs-1;
2031         dirL = 1;
2032     }
2033
2034     for (i = 0; i < cGlyphs; i++)
2035     {
2036         for (k = 0; k < cChars; k++)
2037             if (pwLogClust[k] == i)
2038             {
2039                 if (pwcChars[k] == 0x0020)
2040                     spaces[i] = 1;
2041             }
2042     }
2043
2044     for (i = 0; i < cGlyphs; i++)
2045     {
2046         int char_index[20];
2047         int char_count = 0;
2048
2049         for (k = 0; k < cChars; k++)
2050         {
2051             if (pwLogClust[k] == i)
2052             {
2053                 char_index[char_count] = k;
2054                 char_count++;
2055             }
2056         }
2057
2058         if (char_count == 0)
2059         {
2060             FIXME("No chars in this glyph?  Must be an error\n");
2061             continue;
2062         }
2063
2064         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2065         {
2066             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2067             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2068         }
2069         else if (i == finaGlyph)
2070             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2071         else
2072             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2073     }
2074
2075     HeapFree(GetProcessHeap(),0,spaces);
2076     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2077     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2078
2079     /* Do not allow justification between marks and their base */
2080     for (i = 0; i < cGlyphs; i++)
2081     {
2082         if (!pGlyphProp[i].sva.fClusterStart)
2083             pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2084     }
2085 }
2086
2087 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)
2088 {
2089     int i,k;
2090
2091     for (i = 0; i < cGlyphs; i++)
2092     {
2093         int char_index[20];
2094         int char_count = 0;
2095
2096         for (k = 0; k < cChars; k++)
2097         {
2098             if (pwLogClust[k] == i)
2099             {
2100                 char_index[char_count] = k;
2101                 char_count++;
2102             }
2103         }
2104
2105         if (char_count == 0)
2106         {
2107             FIXME("No chars in this glyph?  Must be an error\n");
2108             continue;
2109         }
2110
2111         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2112         {
2113             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2114             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2115         }
2116         else
2117             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2118     }
2119     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2120     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2121 }
2122
2123 static void ShapeCharGlyphProp_Tibet( 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)
2124 {
2125     int i,k;
2126
2127     for (i = 0; i < cGlyphs; i++)
2128     {
2129         int char_index[20];
2130         int char_count = 0;
2131
2132         for (k = 0; k < cChars; k++)
2133         {
2134             if (pwLogClust[k] == i)
2135             {
2136                 char_index[char_count] = k;
2137                 char_count++;
2138             }
2139         }
2140
2141         if (char_count == 0)
2142         {
2143             FIXME("No chars in this glyph?  Must be an error\n");
2144             continue;
2145         }
2146
2147         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2148         {
2149             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2150             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2151         }
2152         else
2153             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2154     }
2155     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2156     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2157
2158     /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2159     for (i = 0; i < cGlyphs; i++)
2160     {
2161         if (!pGlyphProp[i].sva.fClusterStart)
2162         {
2163             pGlyphProp[i].sva.fDiacritic = 0;
2164             pGlyphProp[i].sva.fZeroWidth = 0;
2165         }
2166     }
2167 }
2168
2169 static void ShapeCharGlyphProp_BaseIndic( 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, lexical_function lexical)
2170 {
2171     int i,k;
2172
2173     for (i = 0; i < cGlyphs; i++)
2174     {
2175         int char_index[20];
2176         int char_count = 0;
2177
2178         for (k = 0; k < cChars; k++)
2179         {
2180             if (pwLogClust[k] == i)
2181             {
2182                 char_index[char_count] = k;
2183                 char_count++;
2184             }
2185         }
2186
2187         if (char_count == 0)
2188         {
2189             FIXME("No chars in this glyph?  Must be an error\n");
2190             continue;
2191         }
2192
2193         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2194         {
2195             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2196             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2197         }
2198         else
2199             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2200
2201         pGlyphProp[i].sva.fClusterStart = 0;
2202         for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
2203             switch (lexical(pwcChars[char_index[k]]))
2204             {
2205                 case lex_Mantra_pre:
2206                 case lex_Mantra_post:
2207                 case lex_Mantra_above:
2208                 case lex_Mantra_below:
2209                 case lex_Modifier:
2210                     break;
2211                 default:
2212                     pGlyphProp[i].sva.fClusterStart = 1;
2213                     break;
2214             }
2215     }
2216     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2217 }
2218
2219 static void ShapeCharGlyphProp_Devanagari( 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 )
2220 {
2221     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
2222 }
2223
2224 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)
2225 {
2226     if (ShapingData[psa->eScript].charGlyphPropProc)
2227         ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2228     else
2229         ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2230 }
2231
2232 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2233 {
2234     if (ShapingData[psa->eScript].contextProc)
2235         ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2236 }
2237
2238 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)
2239 {
2240     int i;
2241     INT dirL;
2242
2243     if (!rpRangeProperties)
2244         return;
2245
2246     if (!psc->GSUB_Table)
2247         psc->GSUB_Table = load_gsub_table(hdc);
2248
2249     if (!psc->GSUB_Table)
2250         return;
2251
2252     if (!psa->fLogicalOrder && psa->fRTL)
2253         dirL = -1;
2254     else
2255         dirL = 1;
2256
2257     for (i = 0; i < rpRangeProperties->cotfRecords; i++)
2258     {
2259         if (rpRangeProperties->potfRecords[i].lParameter > 0)
2260         apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
2261     }
2262 }
2263
2264 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
2265 {
2266 const TEXTRANGE_PROPERTIES *rpRangeProperties;
2267 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
2268
2269     SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
2270 }
2271
2272 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
2273 {
2274     const GSUB_Feature *feature;
2275     int i;
2276
2277     if (!ShapingData[psa->eScript].requiredFeatures)
2278         return S_OK;
2279
2280     if (!psc->GSUB_Table)
2281         psc->GSUB_Table = load_gsub_table(hdc);
2282
2283     /* we need to have at least one of the required features */
2284     i = 0;
2285     while (ShapingData[psa->eScript].requiredFeatures[i])
2286     {
2287         feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
2288         if (feature)
2289             return S_OK;
2290         i++;
2291     }
2292
2293     return USP_E_SCRIPT_NOT_IN_FONT;
2294 }