dlls: Assorted spelling fixes.
[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 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56
57 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
58
59 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);
60 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 );
61 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 );
62 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 );
63 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 );
64 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 );
65 static void ShapeCharGlyphProp_Bengali( 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 );
66 static void ShapeCharGlyphProp_Gurmukhi( 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 );
67 static void ShapeCharGlyphProp_Gujarati( 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 );
68 static void ShapeCharGlyphProp_Oriya( 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 );
69 static void ShapeCharGlyphProp_Tamil( 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 );
70 static void ShapeCharGlyphProp_Telugu( 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 );
71 static void ShapeCharGlyphProp_Kannada( 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 );
72 static void ShapeCharGlyphProp_Malayalam( 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 );
73
74 extern const unsigned short indic_syllabic_table[];
75 extern const unsigned short wine_shaping_table[];
76 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
77
78 enum joining_types {
79     jtU,
80     jtT,
81     jtR,
82     jtL,
83     jtD,
84     jtC
85 };
86
87 enum joined_forms {
88     Xn=0,
89     Xr,
90     Xl,
91     Xm,
92     /* Syriac Alaph */
93     Afj,
94     Afn,
95     Afx
96 };
97
98 #ifdef WORDS_BIGENDIAN
99 #define GET_BE_WORD(x) (x)
100 #else
101 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
102 #endif
103
104 /* These are all structures needed for the GSUB table */
105 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
106 #define GSUB_E_NOFEATURE -2
107 #define GSUB_E_NOGLYPH -1
108
109 typedef struct {
110     DWORD version;
111     WORD ScriptList;
112     WORD FeatureList;
113     WORD LookupList;
114 } GSUB_Header;
115
116 typedef struct {
117     CHAR ScriptTag[4];
118     WORD Script;
119 } GSUB_ScriptRecord;
120
121 typedef struct {
122     WORD ScriptCount;
123     GSUB_ScriptRecord ScriptRecord[1];
124 } GSUB_ScriptList;
125
126 typedef struct {
127     CHAR LangSysTag[4];
128     WORD LangSys;
129 } GSUB_LangSysRecord;
130
131 typedef struct {
132     WORD DefaultLangSys;
133     WORD LangSysCount;
134     GSUB_LangSysRecord LangSysRecord[1];
135 } GSUB_Script;
136
137 typedef struct {
138     WORD LookupOrder; /* Reserved */
139     WORD ReqFeatureIndex;
140     WORD FeatureCount;
141     WORD FeatureIndex[1];
142 } GSUB_LangSys;
143
144 typedef struct {
145     CHAR FeatureTag[4];
146     WORD Feature;
147 } GSUB_FeatureRecord;
148
149 typedef struct {
150     WORD FeatureCount;
151     GSUB_FeatureRecord FeatureRecord[1];
152 } GSUB_FeatureList;
153
154 typedef struct {
155     WORD FeatureParams; /* Reserved */
156     WORD LookupCount;
157     WORD LookupListIndex[1];
158 } GSUB_Feature;
159
160 typedef struct {
161     WORD LookupCount;
162     WORD Lookup[1];
163 } GSUB_LookupList;
164
165 typedef struct {
166     WORD LookupType;
167     WORD LookupFlag;
168     WORD SubTableCount;
169     WORD SubTable[1];
170 } GSUB_LookupTable;
171
172 typedef struct {
173     WORD CoverageFormat;
174     WORD GlyphCount;
175     WORD GlyphArray[1];
176 } GSUB_CoverageFormat1;
177
178 typedef struct {
179     WORD Start;
180     WORD End;
181     WORD StartCoverageIndex;
182 } GSUB_RangeRecord;
183
184 typedef struct {
185     WORD CoverageFormat;
186     WORD RangeCount;
187     GSUB_RangeRecord RangeRecord[1];
188 } GSUB_CoverageFormat2;
189
190 typedef struct {
191     WORD SubstFormat; /* = 1 */
192     WORD Coverage;
193     WORD DeltaGlyphID;
194 } GSUB_SingleSubstFormat1;
195
196 typedef struct {
197     WORD SubstFormat; /* = 2 */
198     WORD Coverage;
199     WORD GlyphCount;
200     WORD Substitute[1];
201 }GSUB_SingleSubstFormat2;
202
203 typedef struct {
204     WORD SubstFormat; /* = 1 */
205     WORD Coverage;
206     WORD LigSetCount;
207     WORD LigatureSet[1];
208 }GSUB_LigatureSubstFormat1;
209
210 typedef struct {
211     WORD LigatureCount;
212     WORD Ligature[1];
213 }GSUB_LigatureSet;
214
215 typedef struct{
216     WORD LigGlyph;
217     WORD CompCount;
218     WORD Component[1];
219 }GSUB_Ligature;
220
221 typedef struct{
222     WORD SequenceIndex;
223     WORD LookupListIndex;
224
225 }GSUB_SubstLookupRecord;
226
227 typedef struct{
228     WORD SubstFormat; /* = 1 */
229     WORD Coverage;
230     WORD ChainSubRuleSetCount;
231     WORD ChainSubRuleSet[1];
232 }GSUB_ChainContextSubstFormat1;
233
234 typedef struct {
235     WORD SubstFormat; /* = 3 */
236     WORD BacktrackGlyphCount;
237     WORD Coverage[1];
238 }GSUB_ChainContextSubstFormat3_1;
239
240 typedef struct{
241     WORD InputGlyphCount;
242     WORD Coverage[1];
243 }GSUB_ChainContextSubstFormat3_2;
244
245 typedef struct{
246     WORD LookaheadGlyphCount;
247     WORD Coverage[1];
248 }GSUB_ChainContextSubstFormat3_3;
249
250 typedef struct{
251     WORD SubstCount;
252     GSUB_SubstLookupRecord SubstLookupRecord[1];
253 }GSUB_ChainContextSubstFormat3_4;
254
255 typedef struct {
256     WORD SubstFormat; /* = 1 */
257     WORD Coverage;
258     WORD AlternateSetCount;
259     WORD AlternateSet[1];
260 } GSUB_AlternateSubstFormat1;
261
262 typedef struct{
263     WORD GlyphCount;
264     WORD Alternate[1];
265 } GSUB_AlternateSet;
266
267 /* These are all structures needed for the GDEF table */
268 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
269
270 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
271
272 typedef struct {
273     DWORD Version;
274     WORD GlyphClassDef;
275     WORD AttachList;
276     WORD LigCaretList;
277     WORD MarkAttachClassDef;
278 } GDEF_Header;
279
280 typedef struct {
281     WORD ClassFormat;
282     WORD StartGlyph;
283     WORD GlyphCount;
284     WORD ClassValueArray[1];
285 } GDEF_ClassDefFormat1;
286
287 typedef struct {
288     WORD Start;
289     WORD End;
290     WORD Class;
291 } GDEF_ClassRangeRecord;
292
293 typedef struct {
294     WORD ClassFormat;
295     WORD ClassRangeCount;
296     GDEF_ClassRangeRecord ClassRangeRecord[1];
297 } GDEF_ClassDefFormat2;
298
299 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
300
301 typedef struct tagVowelComponents
302 {
303     WCHAR base;
304     WCHAR parts[3];
305 } VowelComponents;
306
307 typedef struct tagConsonantComponents
308 {
309     WCHAR parts[3];
310     WCHAR output;
311 } ConsonantComponents;
312
313 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
314
315 /* the orders of joined_forms and contextual_features need to line up */
316 static const char* contextual_features[] =
317 {
318     "isol",
319     "fina",
320     "init",
321     "medi",
322     /* Syriac Alaph */
323     "med2",
324     "fin2",
325     "fin3"
326 };
327
328 static OPENTYPE_FEATURE_RECORD standard_features[] =
329 {
330     { MS_MAKE_TAG('l','i','g','a'), 1},
331     { MS_MAKE_TAG('c','l','i','g'), 1},
332 };
333
334 static OPENTYPE_FEATURE_RECORD arabic_features[] =
335 {
336     { MS_MAKE_TAG('r','l','i','g'), 1},
337     { MS_MAKE_TAG('c','a','l','t'), 1},
338     { MS_MAKE_TAG('l','i','g','a'), 1},
339     { MS_MAKE_TAG('d','l','i','g'), 1},
340     { MS_MAKE_TAG('c','s','w','h'), 1},
341     { MS_MAKE_TAG('m','s','e','t'), 1},
342 };
343
344 static const char* required_arabic_features[] =
345 {
346     "fina",
347     "init",
348     "medi",
349     "rlig",
350     NULL
351 };
352
353 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
354 {
355     { MS_MAKE_TAG('d','l','i','g'), 1},
356 };
357
358 static OPENTYPE_FEATURE_RECORD syriac_features[] =
359 {
360     { MS_MAKE_TAG('r','l','i','g'), 1},
361     { MS_MAKE_TAG('c','a','l','t'), 1},
362     { MS_MAKE_TAG('l','i','g','a'), 1},
363     { MS_MAKE_TAG('d','l','i','g'), 1},
364 };
365
366 static const char* required_syriac_features[] =
367 {
368     "fina",
369     "fin2",
370     "fin3",
371     "init",
372     "medi",
373     "med2",
374     "rlig",
375     NULL
376 };
377
378 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
379 {
380     /* Presentation forms */
381     { MS_MAKE_TAG('b','l','w','s'), 1},
382     { MS_MAKE_TAG('a','b','v','s'), 1},
383     { MS_MAKE_TAG('p','s','t','s'), 1},
384 };
385
386 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
387 {
388     { MS_MAKE_TAG('a','b','v','s'), 1},
389     { MS_MAKE_TAG('b','l','w','s'), 1},
390 };
391
392 static OPENTYPE_FEATURE_RECORD thai_features[] =
393 {
394     { MS_MAKE_TAG('c','c','m','p'), 1},
395 };
396
397 static const char* required_lao_features[] =
398 {
399     "ccmp",
400     NULL
401 };
402
403 static const char* required_devanagari_features[] =
404 {
405     "nukt",
406     "akhn",
407     "rphf",
408     "blwf",
409     "half",
410     "vatu",
411     "pres",
412     "abvs",
413     "blws",
414     "psts",
415     "haln",
416     NULL
417 };
418
419 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
420 {
421     { MS_MAKE_TAG('p','r','e','s'), 1},
422     { MS_MAKE_TAG('a','b','v','s'), 1},
423     { MS_MAKE_TAG('b','l','w','s'), 1},
424     { MS_MAKE_TAG('p','s','t','s'), 1},
425     { MS_MAKE_TAG('h','a','l','n'), 1},
426     { MS_MAKE_TAG('c','a','l','t'), 1},
427 };
428
429 static const char* required_bengali_features[] =
430 {
431     "nukt",
432     "akhn",
433     "rphf",
434     "blwf",
435     "half",
436     "vatu",
437     "pstf",
438     "init",
439     "abvs",
440     "blws",
441     "psts",
442     "haln",
443     NULL
444 };
445
446 static const char* required_gurmukhi_features[] =
447 {
448     "nukt",
449     "akhn",
450     "rphf",
451     "blwf",
452     "half",
453     "pstf",
454     "vatu",
455     "cjct",
456     "pres",
457     "abvs",
458     "blws",
459     "psts",
460     "haln",
461     "calt",
462     NULL
463 };
464
465 static const char* required_oriya_features[] =
466 {
467     "nukt",
468     "akhn",
469     "rphf",
470     "blwf",
471     "pstf",
472     "cjct",
473     "pres",
474     "abvs",
475     "blws",
476     "psts",
477     "haln",
478     "calt",
479     NULL
480 };
481
482 static const char* required_tamil_features[] =
483 {
484     "nukt",
485     "akhn",
486     "rphf",
487     "pref",
488     "half",
489     "pres",
490     "abvs",
491     "blws",
492     "psts",
493     "haln",
494     "calt",
495     NULL
496 };
497
498 static const char* required_telugu_features[] =
499 {
500     "nukt",
501     "akhn",
502     "rphf",
503     "pref",
504     "half",
505     "pstf",
506     "cjct",
507     "pres",
508     "abvs",
509     "blws",
510     "psts",
511     "haln",
512     "calt",
513     NULL
514 };
515
516 typedef struct ScriptShapeDataTag {
517     TEXTRANGE_PROPERTIES   defaultTextRange;
518     const char**           requiredFeatures;
519     CHAR                   otTag[5];
520     CHAR                   newOtTag[5];
521     ContextualShapingProc  contextProc;
522     ShapeCharGlyphPropProc charGlyphPropProc;
523 } ScriptShapeData;
524
525 /* in order of scripts */
526 static const ScriptShapeData ShapingData[] =
527 {
528     {{ standard_features, 2}, NULL, "", "", NULL, NULL},
529     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
530     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
531     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
532     {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
533     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
534     {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
535     {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
536     {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
537     {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
538     {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
539     {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
540     {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
541     {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
542     {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
543     {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
544     {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, NULL},
545     {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
546     {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
547     {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
548     {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
549     {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
550     {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
551     {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
552     {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
553     {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
554     {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
555     {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
556     {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
557     {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
558     {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
559     {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
560     {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
561     {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
562     {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
563     {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
564     {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
565     {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
566     {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
567     {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
568     {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
569     {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
570     {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
571     {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
572 };
573
574 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
575 {
576     const GSUB_CoverageFormat1* cf1;
577
578     cf1 = table;
579
580     if (GET_BE_WORD(cf1->CoverageFormat) == 1)
581     {
582         int count = GET_BE_WORD(cf1->GlyphCount);
583         int i;
584         TRACE("Coverage Format 1, %i glyphs\n",count);
585         for (i = 0; i < count; i++)
586             if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
587                 return i;
588         return -1;
589     }
590     else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
591     {
592         const GSUB_CoverageFormat2* cf2;
593         int i;
594         int count;
595         cf2 = (const GSUB_CoverageFormat2*)cf1;
596
597         count = GET_BE_WORD(cf2->RangeCount);
598         TRACE("Coverage Format 2, %i ranges\n",count);
599         for (i = 0; i < count; i++)
600         {
601             if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
602                 return -1;
603             if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
604                 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
605             {
606                 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
607                     glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
608             }
609         }
610         return -1;
611     }
612     else
613         ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
614
615     return -1;
616 }
617
618 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
619 {
620     const GSUB_ScriptList *script;
621     const GSUB_Script *deflt = NULL;
622     int i;
623     script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
624
625     TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
626     for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
627     {
628         const GSUB_Script *scr;
629         int offset;
630
631         offset = GET_BE_WORD(script->ScriptRecord[i].Script);
632         scr = (const GSUB_Script*)((const BYTE*)script + offset);
633
634         if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
635             return scr;
636         if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
637             deflt = scr;
638     }
639     return deflt;
640 }
641
642 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
643 {
644     int i;
645     int offset;
646     const GSUB_LangSys *Lang;
647
648     TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
649
650     for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
651     {
652         offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
653         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
654
655         if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
656             return Lang;
657     }
658     offset = GET_BE_WORD(script->DefaultLangSys);
659     if (offset)
660     {
661         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
662         return Lang;
663     }
664     return NULL;
665 }
666
667 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
668 {
669     int i;
670     const GSUB_FeatureList *feature;
671     feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
672
673     TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
674     for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
675     {
676         int index = GET_BE_WORD(lang->FeatureIndex[i]);
677         if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
678         {
679             const GSUB_Feature *feat;
680             feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
681             return feat;
682         }
683     }
684     return NULL;
685 }
686
687 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
688 {
689     int j;
690     TRACE("Single Substitution Subtable\n");
691
692     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
693     {
694         int offset;
695         const GSUB_SingleSubstFormat1 *ssf1;
696         offset = GET_BE_WORD(look->SubTable[j]);
697         ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
698         if (GET_BE_WORD(ssf1->SubstFormat) == 1)
699         {
700             int offset = GET_BE_WORD(ssf1->Coverage);
701             TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
702             if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
703             {
704                 TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
705                 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
706                 TRACE(" 0x%x\n",glyphs[glyph_index]);
707                 return glyph_index + 1;
708             }
709         }
710         else
711         {
712             const GSUB_SingleSubstFormat2 *ssf2;
713             INT index;
714             INT offset;
715
716             ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
717             offset = GET_BE_WORD(ssf1->Coverage);
718             TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
719             index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
720             TRACE("  Coverage index %i\n",index);
721             if (index != -1)
722             {
723                 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
724                     return GSUB_E_NOGLYPH;
725
726                 TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
727                 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
728                 TRACE("0x%x\n",glyphs[glyph_index]);
729                 return glyph_index + 1;
730             }
731         }
732     }
733     return GSUB_E_NOGLYPH;
734 }
735
736 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
737 {
738     int j;
739     TRACE("Alternate Substitution Subtable\n");
740
741     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
742     {
743         int offset;
744         const GSUB_AlternateSubstFormat1 *asf1;
745         INT index;
746
747         offset = GET_BE_WORD(look->SubTable[j]);
748         asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
749         offset = GET_BE_WORD(asf1->Coverage);
750
751         index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
752         if (index != -1)
753         {
754             const GSUB_AlternateSet *as;
755             offset =  GET_BE_WORD(asf1->AlternateSet[index]);
756             as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
757             FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
758             if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
759                 return GSUB_E_NOGLYPH;
760
761             TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
762             glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
763             TRACE(" 0x%x\n",glyphs[glyph_index]);
764             return glyph_index + 1;
765         }
766     }
767     return GSUB_E_NOGLYPH;
768 }
769
770 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
771 {
772     int j;
773
774     TRACE("Ligature Substitution Subtable\n");
775     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
776     {
777         const GSUB_LigatureSubstFormat1 *lsf1;
778         int offset,index;
779
780         offset = GET_BE_WORD(look->SubTable[j]);
781         lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
782         offset = GET_BE_WORD(lsf1->Coverage);
783         index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
784         TRACE("  Coverage index %i\n",index);
785         if (index != -1)
786         {
787             const GSUB_LigatureSet *ls;
788             int k, count;
789
790             offset = GET_BE_WORD(lsf1->LigatureSet[index]);
791             ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
792             count = GET_BE_WORD(ls->LigatureCount);
793             TRACE("  LigatureSet has %i members\n",count);
794             for (k = 0; k < count; k++)
795             {
796                 const GSUB_Ligature *lig;
797                 int CompCount,l,CompIndex;
798
799                 offset = GET_BE_WORD(ls->Ligature[k]);
800                 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
801                 CompCount = GET_BE_WORD(lig->CompCount) - 1;
802                 CompIndex = glyph_index+write_dir;
803                 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
804                 {
805                     int CompGlyph;
806                     CompGlyph = GET_BE_WORD(lig->Component[l]);
807                     if (CompGlyph != glyphs[CompIndex])
808                         break;
809                     CompIndex += write_dir;
810                 }
811                 if (l == CompCount)
812                 {
813                     int replaceIdx = glyph_index;
814                     if (write_dir < 0)
815                         replaceIdx = glyph_index - CompCount;
816
817                     TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
818                     glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
819                     TRACE("0x%x\n",glyphs[replaceIdx]);
820                     if (CompCount > 0)
821                     {
822                         int j;
823                         for (j = replaceIdx + 1; j < *glyph_count; j++)
824                             glyphs[j] =glyphs[j+CompCount];
825                         *glyph_count = *glyph_count - CompCount;
826                     }
827                     return replaceIdx + 1;
828                 }
829             }
830         }
831     }
832     return GSUB_E_NOGLYPH;
833 }
834
835 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
836 {
837     int j;
838     BOOL done = FALSE;
839
840     TRACE("Chaining Contextual Substitution Subtable\n");
841     for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
842     {
843         const GSUB_ChainContextSubstFormat1 *ccsf1;
844         int offset;
845         int dirLookahead = write_dir;
846         int dirBacktrack = -1 * write_dir;
847
848         offset = GET_BE_WORD(look->SubTable[j]);
849         ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
850         if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
851         {
852             FIXME("  TODO: subtype 1 (Simple context glyph substitution)\n");
853             continue;
854         }
855         else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
856         {
857             FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
858             continue;
859         }
860         else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
861         {
862             int k;
863             int indexGlyphs;
864             const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
865             const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
866             const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
867             const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
868             int newIndex = glyph_index;
869
870             ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
871
872             TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
873
874             for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
875             {
876                 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
877                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
878                     break;
879             }
880             if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
881                 continue;
882             TRACE("Matched Backtrack\n");
883
884             ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
885
886             indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
887             for (k = 0; k < indexGlyphs; k++)
888             {
889                 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
890                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
891                     break;
892             }
893             if (k != indexGlyphs)
894                 continue;
895             TRACE("Matched IndexGlyphs\n");
896
897             ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
898
899             for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
900             {
901                 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
902                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
903                     break;
904             }
905             if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
906                 continue;
907             TRACE("Matched LookAhead\n");
908
909             ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
910
911             if (GET_BE_WORD(ccsf3_4->SubstCount))
912             {
913                 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
914                 {
915                     int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
916                     int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
917
918                     TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
919                     newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
920                     if (newIndex == -1)
921                     {
922                         ERR("Chain failed to generate a glyph\n");
923                         continue;
924                     }
925                 }
926                 return newIndex;
927             }
928             else return GSUB_E_NOGLYPH;
929         }
930     }
931     return -1;
932 }
933
934 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
935 {
936     int offset;
937     const GSUB_LookupTable *look;
938
939     offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
940     look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
941     TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
942     switch(GET_BE_WORD(look->LookupType))
943     {
944         case 1:
945             return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
946         case 3:
947             return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
948         case 4:
949             return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
950         case 6:
951             return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
952         default:
953             FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
954     }
955     return GSUB_E_NOGLYPH;
956 }
957
958 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
959 {
960     int i;
961     int out_index = GSUB_E_NOGLYPH;
962     const GSUB_LookupList *lookup;
963
964     lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
965
966     TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
967     for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
968     {
969         out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
970         if (out_index != GSUB_E_NOGLYPH)
971             break;
972     }
973     if (out_index == GSUB_E_NOGLYPH)
974         TRACE("lookups found no glyphs\n");
975     else
976     {
977         int out2;
978         out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
979         if (out2!=GSUB_E_NOGLYPH)
980             out_index = out2;
981     }
982     return out_index;
983 }
984
985 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
986 {
987     UINT charset;
988
989     if (psc->userScript != 0)
990     {
991         if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
992             return ShapingData[psa->eScript].newOtTag;
993         else
994             return (char*)&psc->userScript;
995     }
996
997     if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
998         return ShapingData[psa->eScript].newOtTag;
999
1000     if (ShapingData[psa->eScript].otTag[0] != 0)
1001         return ShapingData[psa->eScript].otTag;
1002
1003     /*
1004      * fall back to the font charset
1005      */
1006     charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1007     switch (charset)
1008     {
1009         case ANSI_CHARSET: return "latn";
1010         case BALTIC_CHARSET: return "latn"; /* ?? */
1011         case CHINESEBIG5_CHARSET: return "hani";
1012         case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1013         case GB2312_CHARSET: return "hani";
1014         case GREEK_CHARSET: return "grek";
1015         case HANGUL_CHARSET: return "hang";
1016         case RUSSIAN_CHARSET: return "cyrl";
1017         case SHIFTJIS_CHARSET: return "kana";
1018         case TURKISH_CHARSET: return "latn"; /* ?? */
1019         case VIETNAMESE_CHARSET: return "latn";
1020         case JOHAB_CHARSET: return "latn"; /* ?? */
1021         case ARABIC_CHARSET: return "arab";
1022         case HEBREW_CHARSET: return "hebr";
1023         case THAI_CHARSET: return "thai";
1024         default: return "latn";
1025     }
1026 }
1027
1028 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1029 {
1030     const GSUB_Feature *feature;
1031     int i;
1032
1033     for (i = 0; i <  psc->feature_count; i++)
1034         if (strncmp(psc->features[i].tag,feat,4)==0)
1035             return psc->features[i].feature;
1036
1037     feature = NULL;
1038
1039     if (psc->GSUB_Table)
1040     {
1041         const GSUB_Script *script;
1042         const GSUB_LangSys *language;
1043         int attempt = 2;
1044
1045         do
1046         {
1047             script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1048             attempt--;
1049             if (script)
1050             {
1051                 if (psc->userLang != 0)
1052                     language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1053                 else
1054                     language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1055                 if (language)
1056                     feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1057             }
1058         } while(attempt && !feature);
1059
1060         /* try in the default (latin) table */
1061         if (!feature)
1062         {
1063             script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1064             if (script)
1065             {
1066                 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1067                 if (language)
1068                     feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1069             }
1070         }
1071     }
1072
1073     TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1074
1075     psc->feature_count++;
1076
1077     if (psc->features)
1078         psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1079     else
1080         psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1081
1082     lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1083     psc->features[psc->feature_count - 1].feature = feature;
1084     return feature;
1085 }
1086
1087 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)
1088 {
1089     const GSUB_Feature *feature;
1090
1091     feature = load_GSUB_feature(hdc, psa, psc, feat);
1092     if (!feature)
1093         return GSUB_E_NOFEATURE;
1094
1095     TRACE("applying feature %s\n",feat);
1096     return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1097 }
1098
1099 static VOID *load_gsub_table(HDC hdc)
1100 {
1101     VOID* GSUB_Table = NULL;
1102     int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1103     if (length != GDI_ERROR)
1104     {
1105         GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1106         GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1107         TRACE("Loaded GSUB table of %i bytes\n",length);
1108     }
1109     return GSUB_Table;
1110 }
1111
1112 INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, const WCHAR *chars, INT write_dir, INT count, const char* feature)
1113 {
1114     WORD *glyphs;
1115     INT glyph_count = count;
1116     INT rc;
1117
1118     glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1119     GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1120     rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1121     if (rc > GSUB_E_NOGLYPH)
1122         rc = count - glyph_count;
1123     else
1124         rc = 0;
1125
1126     HeapFree(GetProcessHeap(),0,glyphs);
1127     return rc;
1128 }
1129
1130 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1131 {
1132     int offset;
1133     WORD class = 0;
1134     const GDEF_ClassDefFormat1 *cf1;
1135
1136     if (!header)
1137         return 0;
1138
1139     offset = GET_BE_WORD(header->GlyphClassDef);
1140     if (!offset)
1141         return 0;
1142
1143     cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1144     if (GET_BE_WORD(cf1->ClassFormat) == 1)
1145     {
1146         if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1147         {
1148             int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1149             if (index < GET_BE_WORD(cf1->GlyphCount))
1150                 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1151         }
1152     }
1153     else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1154     {
1155         const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1156         int i, top;
1157         top = GET_BE_WORD(cf2->ClassRangeCount);
1158         for (i = 0; i < top; i++)
1159         {
1160             if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1161                 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1162             {
1163                 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1164                 break;
1165             }
1166         }
1167     }
1168     else
1169         ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1170
1171     return class;
1172 }
1173
1174 static VOID *load_gdef_table(HDC hdc)
1175 {
1176     VOID* GDEF_Table = NULL;
1177     int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1178     if (length != GDI_ERROR)
1179     {
1180         GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1181         GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1182         TRACE("Loaded GDEF table of %i bytes\n",length);
1183     }
1184     return GDEF_Table;
1185 }
1186
1187 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1188 {
1189     int i;
1190
1191     if (!psc->GDEF_Table)
1192         psc->GDEF_Table = load_gdef_table(hdc);
1193
1194     for (i = 0; i < cGlyphs; i++)
1195     {
1196         WORD class;
1197
1198         class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1199
1200         switch (class)
1201         {
1202             case 0:
1203             case BaseGlyph:
1204                 pGlyphProp[i].sva.fClusterStart = 1;
1205                 pGlyphProp[i].sva.fDiacritic = 0;
1206                 pGlyphProp[i].sva.fZeroWidth = 0;
1207                 break;
1208             case LigatureGlyph:
1209                 pGlyphProp[i].sva.fClusterStart = 1;
1210                 pGlyphProp[i].sva.fDiacritic = 0;
1211                 pGlyphProp[i].sva.fZeroWidth = 0;
1212                 break;
1213             case MarkGlyph:
1214                 pGlyphProp[i].sva.fClusterStart = 0;
1215                 pGlyphProp[i].sva.fDiacritic = 1;
1216                 pGlyphProp[i].sva.fZeroWidth = 1;
1217                 break;
1218             case ComponentGlyph:
1219                 pGlyphProp[i].sva.fClusterStart = 0;
1220                 pGlyphProp[i].sva.fDiacritic = 0;
1221                 pGlyphProp[i].sva.fZeroWidth = 0;
1222                 break;
1223             default:
1224                 ERR("Unknown glyph class %i\n",class);
1225                 pGlyphProp[i].sva.fClusterStart = 1;
1226                 pGlyphProp[i].sva.fDiacritic = 0;
1227                 pGlyphProp[i].sva.fZeroWidth = 0;
1228         }
1229     }
1230 }
1231
1232 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1233 {
1234     int i;
1235
1236     for (i = 0; i < cGlyphs; i++)
1237     {
1238         if (!pGlyphProp[i].sva.fClusterStart)
1239         {
1240             int j;
1241             for (j = 0; j < cChars; j++)
1242             {
1243                 if (pwLogClust[j] == i)
1244                 {
1245                     int k = j;
1246                     while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1247                         k-=1;
1248                     if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1249                         pwLogClust[j] = pwLogClust[k];
1250                 }
1251             }
1252         }
1253     }
1254 }
1255
1256 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1257 {
1258     if (changeCount == 0)
1259         return;
1260     else
1261     {
1262         int i;
1263         int target_glyph = nextIndex - 1;
1264         int target_index = -1;
1265         int replacing_glyph = -1;
1266         int changed = 0;
1267
1268         if (write_dir > 0)
1269             for (i = 0; i < chars; i++)
1270             {
1271                 if (pwLogClust[i] == target_glyph)
1272                 {
1273                     target_index = i;
1274                     break;
1275                 }
1276             }
1277         else
1278             for (i = chars - 1; i >= 0; i--)
1279             {
1280                 if (pwLogClust[i] == target_glyph)
1281                 {
1282                     target_index = i;
1283                     break;
1284                 }
1285             }
1286         if (target_index == -1)
1287         {
1288             ERR("Unable to find target glyph\n");
1289             return;
1290         }
1291
1292         if (changeCount < 0)
1293         {
1294             /* merge glyphs */
1295             for(i = target_index; i < chars && i >= 0; i+=write_dir)
1296             {
1297                 if (pwLogClust[i] == target_glyph)
1298                     continue;
1299                 if(pwLogClust[i] == replacing_glyph)
1300                     pwLogClust[i] = target_glyph;
1301                 else
1302                 {
1303                     changed--;
1304                     if (changed >= changeCount)
1305                     {
1306                         replacing_glyph = pwLogClust[i];
1307                         pwLogClust[i] = target_glyph;
1308                     }
1309                     else
1310                         break;
1311                 }
1312             }
1313         }
1314
1315         /* renumber trailing indexes*/
1316         for(i = target_index; i < chars && i >= 0; i+=write_dir)
1317         {
1318             if (pwLogClust[i] != target_glyph)
1319                 pwLogClust[i] += changeCount;
1320         }
1321     }
1322 }
1323
1324 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 )
1325 {
1326     int i;
1327
1328     if (psc->GSUB_Table)
1329     {
1330         const GSUB_Feature *feature;
1331
1332         feature = load_GSUB_feature(hdc, psa, psc, feat);
1333         if (!feature)
1334             return GSUB_E_NOFEATURE;
1335
1336         i = 0;
1337         TRACE("applying feature %s\n",debugstr_an(feat,4));
1338         while(i < *pcGlyphs)
1339         {
1340                 INT nextIndex;
1341                 INT prevCount = *pcGlyphs;
1342                 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1343                 if (nextIndex > GSUB_E_NOGLYPH)
1344                 {
1345                     UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1346                     i = nextIndex;
1347                 }
1348                 else
1349                     i++;
1350         }
1351         return *pcGlyphs;
1352     }
1353     return GSUB_E_NOFEATURE;
1354 }
1355
1356 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1357 {
1358     return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1359 }
1360
1361 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1362 {
1363     if (i + delta < 0)
1364         return 0;
1365     if ( i+ delta >= cchLen)
1366         return 0;
1367
1368     i += delta;
1369
1370     return chars[i];
1371 }
1372
1373 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1374 {
1375     if (i + delta < 0)
1376     {
1377         if (psa->fLinkBefore)
1378             return jtR;
1379         else
1380             return jtU;
1381     }
1382     if ( i+ delta >= cchLen)
1383     {
1384         if (psa->fLinkAfter)
1385             return jtL;
1386         else
1387             return jtU;
1388     }
1389
1390     i += delta;
1391
1392     if (context_type[i] == jtT)
1393         return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1394     else
1395         return context_type[i];
1396 }
1397
1398 static inline BOOL right_join_causing(CHAR joining_type)
1399 {
1400     return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1401 }
1402
1403 static inline BOOL left_join_causing(CHAR joining_type)
1404 {
1405     return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1406 }
1407
1408 static inline BOOL word_break_causing(WCHAR chr)
1409 {
1410     /* we are working within a string of characters already guareented to
1411        be within one script, Syriac, so we do not worry about any character
1412        other than the space character outside of that range */
1413     return (chr == 0 || chr == 0x20 );
1414 }
1415
1416 /*
1417  * ContextualShape_Arabic
1418  */
1419 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1420 {
1421     CHAR *context_type;
1422     INT *context_shape;
1423     INT dirR, dirL;
1424     int i;
1425
1426     if (*pcGlyphs != cChars)
1427     {
1428         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1429         return;
1430     }
1431
1432     if (!psa->fLogicalOrder && psa->fRTL)
1433     {
1434         dirR = 1;
1435         dirL = -1;
1436     }
1437     else
1438     {
1439         dirR = -1;
1440         dirL = 1;
1441     }
1442
1443     if (!psc->GSUB_Table)
1444         psc->GSUB_Table = load_gsub_table(hdc);
1445
1446     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1447     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1448
1449     for (i = 0; i < cChars; i++)
1450         context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1451
1452     for (i = 0; i < cChars; i++)
1453     {
1454         if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1455             context_shape[i] = Xr;
1456         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1457             context_shape[i] = Xl;
1458         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)))
1459             context_shape[i] = Xm;
1460         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1461             context_shape[i] = Xr;
1462         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1463             context_shape[i] = Xl;
1464         else
1465             context_shape[i] = Xn;
1466     }
1467
1468     /* Contextual Shaping */
1469     i = 0;
1470     while(i < *pcGlyphs)
1471     {
1472         BOOL shaped = FALSE;
1473
1474         if (psc->GSUB_Table)
1475         {
1476             INT nextIndex;
1477             INT prevCount = *pcGlyphs;
1478             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1479             if (nextIndex > GSUB_E_NOGLYPH)
1480             {
1481                 i = nextIndex;
1482                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1483             }
1484             shaped = (nextIndex > GSUB_E_NOGLYPH);
1485         }
1486
1487         if (!shaped)
1488         {
1489             WORD newGlyph = pwOutGlyphs[i];
1490             if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1491             {
1492                 /* fall back to presentation form B */
1493                 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1494                 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1495                     pwOutGlyphs[i] = newGlyph;
1496             }
1497             i++;
1498         }
1499     }
1500
1501     HeapFree(GetProcessHeap(),0,context_shape);
1502     HeapFree(GetProcessHeap(),0,context_type);
1503 }
1504
1505 /*
1506  * ContextualShape_Syriac
1507  */
1508
1509 #define ALAPH 0x710
1510 #define DALATH 0x715
1511 #define RISH 0x72A
1512
1513 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1514 {
1515     CHAR *context_type;
1516     INT *context_shape;
1517     INT dirR, dirL;
1518     int i;
1519
1520     if (*pcGlyphs != cChars)
1521     {
1522         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1523         return;
1524     }
1525
1526     if (!psa->fLogicalOrder && psa->fRTL)
1527     {
1528         dirR = 1;
1529         dirL = -1;
1530     }
1531     else
1532     {
1533         dirR = -1;
1534         dirL = 1;
1535     }
1536
1537     if (!psc->GSUB_Table)
1538         psc->GSUB_Table = load_gsub_table(hdc);
1539
1540     if (!psc->GSUB_Table)
1541         return;
1542
1543     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1544     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1545
1546     for (i = 0; i < cChars; i++)
1547         context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1548
1549     for (i = 0; i < cChars; i++)
1550     {
1551         if (pwcChars[i] == ALAPH)
1552         {
1553             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1554
1555             if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1556             context_shape[i] = Afj;
1557             else if ( rchar != DALATH && rchar != RISH &&
1558 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1559 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1560             context_shape[i] = Afn;
1561             else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1562             context_shape[i] = Afx;
1563             else
1564             context_shape[i] = Xn;
1565         }
1566         else if (context_type[i] == jtR &&
1567 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1568             context_shape[i] = Xr;
1569         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1570             context_shape[i] = Xl;
1571         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)))
1572             context_shape[i] = Xm;
1573         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1574             context_shape[i] = Xr;
1575         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1576             context_shape[i] = Xl;
1577         else
1578             context_shape[i] = Xn;
1579     }
1580
1581     /* Contextual Shaping */
1582     i = 0;
1583     while(i < *pcGlyphs)
1584     {
1585         INT nextIndex;
1586         INT prevCount = *pcGlyphs;
1587         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1588         if (nextIndex > GSUB_E_NOGLYPH)
1589         {
1590             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1591             i = nextIndex;
1592         }
1593         else
1594             i++;
1595     }
1596
1597     HeapFree(GetProcessHeap(),0,context_shape);
1598     HeapFree(GetProcessHeap(),0,context_type);
1599 }
1600
1601 /*
1602  * ContextualShape_Phags_pa
1603  */
1604
1605 #define phags_pa_CANDRABINDU  0xA873
1606 #define phags_pa_START 0xA840
1607 #define phags_pa_END  0xA87F
1608
1609 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1610 {
1611     INT *context_shape;
1612     INT dirR, dirL;
1613     int i;
1614
1615     if (*pcGlyphs != cChars)
1616     {
1617         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1618         return;
1619     }
1620
1621     if (!psa->fLogicalOrder && psa->fRTL)
1622     {
1623         dirR = 1;
1624         dirL = -1;
1625     }
1626     else
1627     {
1628         dirR = -1;
1629         dirL = 1;
1630     }
1631
1632     if (!psc->GSUB_Table)
1633         psc->GSUB_Table = load_gsub_table(hdc);
1634
1635     if (!psc->GSUB_Table)
1636         return;
1637
1638     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1639
1640     for (i = 0; i < cChars; i++)
1641     {
1642         if (pwcChars[i] >= phags_pa_START && pwcChars[i] <=  phags_pa_END)
1643         {
1644             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1645             WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1646             BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <=  phags_pa_END);
1647             BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <=  phags_pa_END);
1648
1649             if (jrchar && jlchar)
1650                 context_shape[i] = Xm;
1651             else if (jrchar)
1652                 context_shape[i] = Xr;
1653             else if (jlchar)
1654                 context_shape[i] = Xl;
1655             else
1656                 context_shape[i] = Xn;
1657         }
1658         else
1659             context_shape[i] = -1;
1660     }
1661
1662     /* Contextual Shaping */
1663     i = 0;
1664     while(i < *pcGlyphs)
1665     {
1666         if (context_shape[i] >= 0)
1667         {
1668             INT nextIndex;
1669             INT prevCount = *pcGlyphs;
1670             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1671             if (nextIndex > GSUB_E_NOGLYPH)
1672             {
1673                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1674                 i = nextIndex;
1675             }
1676             else
1677                 i++;
1678         }
1679         else
1680             i++;
1681     }
1682
1683     HeapFree(GetProcessHeap(),0,context_shape);
1684 }
1685
1686 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1687 {
1688     int i;
1689
1690     /* Replace */
1691     pwOutChars[cWalk] = replacements[0];
1692     cWalk=cWalk+1;
1693
1694     /* Insert */
1695     for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1696     {
1697         int j;
1698         for (j = *pcChars; j > cWalk; j--)
1699             pwOutChars[j] = pwOutChars[j-1];
1700         *pcChars= *pcChars+1;
1701         pwOutChars[cWalk] = replacements[i];
1702         cWalk = cWalk+1;
1703     }
1704 }
1705
1706 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1707 {
1708     int i;
1709     int cWalk;
1710
1711     for (cWalk = 0; cWalk < *pcChars; cWalk++)
1712     {
1713         for (i = 0; vowels[i].base != 0x0; i++)
1714         {
1715             if (pwOutChars[cWalk] == vowels[i].base)
1716             {
1717                 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1718                 if (vowels[i].parts[1]) cWalk++;
1719                 if (vowels[i].parts[2]) cWalk++;
1720                 break;
1721             }
1722         }
1723     }
1724 }
1725
1726 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1727 {
1728     int i;
1729     int cWalk;
1730
1731     for (cWalk = 0; cWalk < *pcChars; cWalk++)
1732     {
1733         for (i = 0; consonants[i].output!= 0x0; i++)
1734         {
1735             int j;
1736             for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1737                 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1738                     break;
1739
1740             if (consonants[i].parts[j]==0x0) /* matched all */
1741             {
1742                 int k;
1743                 j--;
1744                 pwOutChars[cWalk] = consonants[i].output;
1745                 for(k = cWalk+1; k < *pcChars - j; k++)
1746                     pwOutChars[k] = pwOutChars[k+j];
1747                 *pcChars = *pcChars - j;
1748                 break;
1749             }
1750         }
1751         cWalk++;
1752     }
1753 }
1754
1755 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1756 {
1757     if (s->ralf >= 0)
1758     {
1759         int j;
1760         WORD Ra = pwChar[s->start];
1761         WORD H = pwChar[s->start+1];
1762
1763         TRACE("Doing reorder of Ra to %i\n",s->base);
1764         for (j = s->start; j < s->base-1; j++)
1765             pwChar[j] = pwChar[j+2];
1766         pwChar[s->base-1] = Ra;
1767         pwChar[s->base] = H;
1768
1769         s->ralf = s->base-1;
1770         s->base -= 2;
1771     }
1772 }
1773
1774 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1775 {
1776     if (s->ralf >= 0)
1777     {
1778         int j,loc;
1779         int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1780         WORD Ra = pwChar[s->start];
1781         WORD H = pwChar[s->start+1];
1782         for (loc = s->end; loc > stop; loc--)
1783             if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1784                 break;
1785
1786         TRACE("Doing reorder of Ra to %i\n",loc);
1787         for (j = s->start; j < loc-1; j++)
1788             pwChar[j] = pwChar[j+2];
1789         pwChar[loc-1] = Ra;
1790         pwChar[loc] = H;
1791
1792         s->ralf = loc-1;
1793         s->base -= 2;
1794         if (s->blwf >= 0) s->blwf -= 2;
1795         if (s->pref >= 0) s->pref -= 2;
1796     }
1797 }
1798
1799 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1800 {
1801     if (s->ralf >= 0)
1802     {
1803         int j;
1804         WORD Ra = pwChar[s->start];
1805         WORD H = pwChar[s->start+1];
1806
1807         TRACE("Doing reorder of Ra to %i\n",s->end-1);
1808         for (j = s->start; j < s->end-1; j++)
1809             pwChar[j] = pwChar[j+2];
1810         pwChar[s->end-1] = Ra;
1811         pwChar[s->end] = H;
1812
1813         s->ralf = s->end-1;
1814         s->base -= 2;
1815         if (s->blwf >= 0) s->blwf -= 2;
1816         if (s->pref >= 0) s->pref -= 2;
1817     }
1818 }
1819
1820 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1821 {
1822     int i;
1823
1824     /* reorder Matras */
1825     if (s->end > s->base)
1826     {
1827         for (i = 1; i <= s->end-s->base; i++)
1828         {
1829             if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1830             {
1831                 int j;
1832                 WCHAR c = pwChar[s->base+i];
1833                 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1834                 for (j = s->base+i; j > s->base; j--)
1835                     pwChar[j] = pwChar[j-1];
1836                 pwChar[s->base] = c;
1837
1838                 if (s->ralf >= s->base) s->ralf++;
1839                 if (s->blwf >= s->base) s->blwf++;
1840                 if (s->pref >= s->base) s->pref++;
1841                 s->base ++;
1842             }
1843         }
1844     }
1845 }
1846
1847 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1848 {
1849     int i;
1850
1851     /* reorder Matras */
1852     if (s->end > s->base)
1853     {
1854         for (i = 1; i <= s->end-s->base; i++)
1855         {
1856             if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1857             {
1858                 int j;
1859                 WCHAR c = pwChar[s->base+i];
1860                 TRACE("Doing reorder of %x to %i\n",c,s->start);
1861                 for (j = s->base+i; j > s->start; j--)
1862                     pwChar[j] = pwChar[j-1];
1863                 pwChar[s->start] = c;
1864
1865                 if (s->ralf >= 0) s->ralf++;
1866                 if (s->blwf >= 0) s->blwf++;
1867                 if (s->pref >= 0) s->pref++;
1868                 s->base ++;
1869             }
1870         }
1871     }
1872 }
1873
1874 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1875 {
1876     if (s->blwf >= 0 && g->blwf > g->base)
1877     {
1878         int j,loc;
1879         int g_offset;
1880         for (loc = s->end; loc > s->blwf; loc--)
1881             if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1882                 break;
1883
1884         g_offset = (loc - s->blwf) - 1;
1885
1886         if (loc != s->blwf)
1887         {
1888             WORD blwf = glyphs[g->blwf];
1889             TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1890             /* do not care about the pwChar array anymore, just the glyphs */
1891             for (j = 0; j < g_offset; j++)
1892                 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1893             glyphs[g->blwf + g_offset] = blwf;
1894         }
1895     }
1896 }
1897
1898 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1899 {
1900     int i;
1901
1902     /* reorder previously moved Matras to correct position*/
1903     for (i = s->start; i < s->base; i++)
1904     {
1905         if (lexical(pwChar[i]) == lex_Matra_pre)
1906         {
1907             int j;
1908             int g_start = g->start + i - s->start;
1909             if (g_start < g->base -1 )
1910             {
1911                 WCHAR og = glyphs[g_start];
1912                 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1913                 for (j = g_start; j < g->base-1; j++)
1914                     glyphs[j] = glyphs[j+1];
1915                 glyphs[g->base-1] = og;
1916             }
1917         }
1918     }
1919 }
1920
1921 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1922 {
1923     if (s->pref >= 0 && g->pref > g->base)
1924     {
1925         int j;
1926         WCHAR og = glyphs[g->pref];
1927         TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1928         for (j = g->pref; j > g->base; j--)
1929             glyphs[j] = glyphs[j-1];
1930         glyphs[g->base] = og;
1931     }
1932 }
1933
1934 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1935 {
1936     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1937     if (s->start == s->base && s->base == s->end)  return;
1938     if (lexical(pwChar[s->base]) == lex_Vowel) return;
1939
1940     Reorder_Ra_follows_base(pwChar, s, lexical);
1941     Reorder_Matra_precede_base(pwChar, s, lexical);
1942 }
1943
1944 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1945 {
1946     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1947     if (s->start == s->base && s->base == s->end)  return;
1948     if (lexical(pwChar[s->base]) == lex_Vowel) return;
1949
1950     Reorder_Ra_follows_matra(pwChar, s, lexical);
1951     Reorder_Matra_precede_syllable(pwChar, s, lexical);
1952 }
1953
1954 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1955 {
1956     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1957     if (s->start == s->base && s->base == s->end)  return;
1958     if (lexical(pwChar[s->base]) == lex_Vowel) return;
1959
1960     Reorder_Ra_follows_base(pwChar, s, lexical);
1961     Reorder_Matra_precede_syllable(pwChar, s, lexical);
1962 }
1963
1964 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1965 {
1966     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1967     if (s->start == s->base && s->base == s->end)  return;
1968     if (lexical(pwChar[s->base]) == lex_Vowel) return;
1969
1970     Reorder_Ra_follows_syllable(pwChar, s, lexical);
1971     Reorder_Matra_precede_syllable(pwChar, s, lexical);
1972 }
1973
1974 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1975 {
1976     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1977     TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1978     if (s->start == s->base && s->base == s->end)  return;
1979     if (lexical(pwChar[s->base]) == lex_Vowel) return;
1980
1981     SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1982 }
1983
1984 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1985 {
1986     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1987     TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1988     if (s->start == s->base && s->base == s->end)  return;
1989     if (lexical(pwChar[s->base]) == lex_Vowel) return;
1990
1991     SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1992     SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1993 }
1994
1995
1996 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1997 {
1998     if (shift == 0)
1999         return;
2000
2001     if (glyph_index->start > index)
2002         glyph_index->start += shift;
2003     if (glyph_index->base > index)
2004         glyph_index->base+= shift;
2005     if (glyph_index->end > index)
2006         glyph_index->end+= shift;
2007     if (glyph_index->ralf > index)
2008         glyph_index->ralf+= shift;
2009     if (glyph_index->blwf > index)
2010         glyph_index->blwf+= shift;
2011     if (glyph_index->pref > index)
2012         glyph_index->pref+= shift;
2013 }
2014
2015 static void Apply_Indic_BasicForm(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, const GSUB_Feature *feature )
2016 {
2017     int index = glyph_index->start;
2018
2019     if (!feature)
2020         return;
2021
2022     while(index <= glyph_index->end)
2023     {
2024             INT nextIndex;
2025             INT prevCount = *pcGlyphs;
2026             nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2027             if (nextIndex > GSUB_E_NOGLYPH)
2028             {
2029                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2030                 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2031                 index = nextIndex;
2032             }
2033             else
2034                 index++;
2035     }
2036 }
2037
2038 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2039 {
2040     int i = 0;
2041     while (i + index < end - 1 && !(is_consonant(lexical(pwChars[index+i])) && (lexical(pwChars[index+i+1]) == lex_Halant || (index + i < end - 2 && lexical(pwChars[index+i+1]) == lex_Nukta && lexical(pwChars[index+i+2] == lex_Halant)))))
2042         i++;
2043     if (index + i <= end-1)
2044         return index + i;
2045     else
2046         return -1;
2047 }
2048
2049 static void Apply_Indic_PreBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, const char* feature)
2050 {
2051     INT index, nextIndex;
2052     INT count,g_offset;
2053
2054     count = syllable->base - syllable->start;
2055
2056     g_offset = 0;
2057     index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2058     while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2059     {
2060         INT prevCount = *pcGlyphs;
2061         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2062         if (nextIndex > GSUB_E_NOGLYPH)
2063         {
2064             UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2065             shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2066             g_offset += (*pcGlyphs - prevCount);
2067         }
2068
2069         index+=2;
2070         index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2071     }
2072 }
2073
2074 static void Apply_Indic_Rphf(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index)
2075 {
2076     INT nextIndex;
2077     INT prevCount = *pcGlyphs;
2078
2079     if (syllable->ralf >= 0)
2080     {
2081         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2082         if (nextIndex > GSUB_E_NOGLYPH)
2083         {
2084             UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2085             shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2086         }
2087     }
2088 }
2089
2090 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2091 {
2092     int i = 0;
2093     while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2094              ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2095               is_consonant(lexical(pwChars[index+i+1])))))
2096         i++;
2097     if (index + i <= end-1)
2098         return index+i;
2099     else
2100         return -1;
2101 }
2102
2103 static void Apply_Indic_PostBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, BOOL modern, const char* feat)
2104 {
2105     INT index, nextIndex;
2106     INT count, g_offset=0;
2107     INT ralf = syllable->ralf;
2108
2109     count = syllable->end - syllable->base;
2110
2111     index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2112
2113     while (index >= 0)
2114     {
2115         INT prevCount = *pcGlyphs;
2116         if (ralf >=0 && ralf < index)
2117         {
2118             g_offset--;
2119             ralf = -1;
2120         }
2121
2122         if (!modern)
2123         {
2124             WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2125             pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2126             pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2127         }
2128
2129         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2130         if (nextIndex > GSUB_E_NOGLYPH)
2131         {
2132             UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2133             shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2134             g_offset += (*pcGlyphs - prevCount);
2135         }
2136         else if (!modern)
2137         {
2138             WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2139             pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2140             pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2141         }
2142
2143         index+=2;
2144         index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2145     }
2146 }
2147
2148 static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllables, INT syllable_count, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, second_reorder_function second_reorder, BOOL modern)
2149 {
2150     int c;
2151     int overall_shift = 0;
2152     const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2153     const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2154     const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2155     const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2156     const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2157     const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2158     const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2159     BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2160     BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2161     BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2162     BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2163     IndicSyllable glyph_indexs;
2164
2165     for (c = 0; c < syllable_count; c++)
2166     {
2167         int old_end;
2168         memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2169         shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2170         old_end = glyph_indexs.end;
2171
2172         if (locl)
2173         {
2174             TRACE("applying feature locl\n");
2175             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2176         }
2177         if (nukt)
2178         {
2179             TRACE("applying feature nukt\n");
2180             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2181         }
2182         if (akhn)
2183         {
2184             TRACE("applying feature akhn\n");
2185             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2186         }
2187
2188         if (rphf)
2189             Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2190         if (rkrf)
2191         {
2192             TRACE("applying feature rkrf\n");
2193             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2194         }
2195         if (pref)
2196             Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2197         if (blwf)
2198         {
2199             if (!modern)
2200                 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2201
2202             Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2203
2204         }
2205         if (half)
2206             Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2207         if (pstf)
2208         {
2209             TRACE("applying feature pstf\n");
2210             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2211         }
2212         if (vatu)
2213         {
2214             TRACE("applying feature vatu\n");
2215             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2216         }
2217         if (cjct)
2218         {
2219             TRACE("applying feature cjct\n");
2220             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2221         }
2222
2223         if (second_reorder)
2224             second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2225
2226         overall_shift += glyph_indexs.end - old_end;
2227     }
2228 }
2229
2230 static inline int unicode_lex(WCHAR c)
2231 {
2232     int type;
2233
2234     if (!c) return lex_Generic;
2235     if (c == 0x200D) return lex_ZWJ;
2236     if (c == 0x200C) return lex_ZWNJ;
2237     if (c == 0x00A0) return lex_NBSP;
2238
2239     type = get_table_entry( indic_syllabic_table, c );
2240
2241     if ((type & 0x00ff) != 0x0007)  type = type & 0x00ff;
2242
2243     switch( type )
2244     {
2245         case 0x0d07: /* Unknown */
2246         case 0x0e07: /* Unknwon */
2247         default: return lex_Generic;
2248         case 0x0001:
2249         case 0x0002:
2250         case 0x0011:
2251         case 0x0012:
2252         case 0x0013:
2253         case 0x0014: return lex_Modifier;
2254         case 0x0003:
2255         case 0x0009:
2256         case 0x000a:
2257         case 0x000b:
2258         case 0x000d:
2259         case 0x000e:
2260         case 0x000f:
2261         case 0x0010: return lex_Consonant;
2262         case 0x0004: return lex_Nukta;
2263         case 0x0005: return lex_Halant;
2264         case 0x0006:
2265         case 0x0008: return lex_Vowel;
2266         case 0x0007:
2267         case 0x0107: return lex_Matra_post;
2268         case 0x0207:
2269         case 0x0307: return lex_Matra_pre;
2270         case 0x0807:
2271         case 0x0907:
2272         case 0x0a07:
2273         case 0x0b07:
2274         case 0x0c07:
2275         case 0x0407: return lex_Composed_Vowel;
2276         case 0x0507: return lex_Matra_above;
2277         case 0x0607: return lex_Matra_below;
2278         case 0x000c: return lex_Ra;
2279     };
2280 }
2281
2282 static int sinhala_lex(WCHAR c)
2283 {
2284     switch (c)
2285     {
2286         case 0x0DDA:
2287         case 0x0DDD:
2288         case 0x0DDC:
2289         case 0x0DDE: return lex_Matra_post;
2290         default:
2291             return unicode_lex(c);
2292     }
2293 }
2294
2295 static const VowelComponents Sinhala_vowels[] = {
2296             {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2297             {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2298             {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2299             {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2300             {0x0000, {0x0000,0x0000,0x0}}};
2301
2302 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2303 {
2304     int cCount = cChars;
2305     int i;
2306     WCHAR *input;
2307     IndicSyllable *syllables = NULL;
2308     int syllable_count = 0;
2309
2310     if (*pcGlyphs != cChars)
2311     {
2312         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2313         return;
2314     }
2315
2316     input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2317
2318     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2319
2320     /* Step 1:  Decompose multi part vowels */
2321     DecomposeVowels(hdc, input,  &cCount, Sinhala_vowels);
2322
2323     TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2324
2325     /* Step 2:  Reorder within Syllables */
2326     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2327     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2328
2329     /* Step 3:  Strip dangling joiners */
2330     for (i = 0; i < cCount; i++)
2331     {
2332         if ((input[i] == 0x200D || input[i] == 0x200C) &&
2333             (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2334             input[i] = 0x0020;
2335     }
2336
2337     /* Step 4: Base Form application to syllables */
2338     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2339     *pcGlyphs = cCount;
2340     ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2341
2342     HeapFree(GetProcessHeap(),0,input);
2343     HeapFree(GetProcessHeap(),0,syllables);
2344 }
2345
2346 static int devanagari_lex(WCHAR c)
2347 {
2348     switch (c)
2349     {
2350         case 0x0930: return lex_Ra;
2351         default:
2352             return unicode_lex(c);
2353     }
2354 }
2355
2356 static const ConsonantComponents Devanagari_consonants[] ={
2357     {{0x0928, 0x093C, 0x00000}, 0x0929},
2358     {{0x0930, 0x093C, 0x00000}, 0x0931},
2359     {{0x0933, 0x093C, 0x00000}, 0x0934},
2360     {{0x0915, 0x093C, 0x00000}, 0x0958},
2361     {{0x0916, 0x093C, 0x00000}, 0x0959},
2362     {{0x0917, 0x093C, 0x00000}, 0x095A},
2363     {{0x091C, 0x093C, 0x00000}, 0x095B},
2364     {{0x0921, 0x093C, 0x00000}, 0x095C},
2365     {{0x0922, 0x093C, 0x00000}, 0x095D},
2366     {{0x092B, 0x093C, 0x00000}, 0x095E},
2367     {{0x092F, 0x093C, 0x00000}, 0x095F}};
2368
2369 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2370 {
2371     int cCount = cChars;
2372     WCHAR *input;
2373     IndicSyllable *syllables = NULL;
2374     int syllable_count = 0;
2375     BOOL modern = get_GSUB_Indic2(psa, psc);
2376
2377     if (*pcGlyphs != cChars)
2378     {
2379         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2380         return;
2381     }
2382
2383     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2384     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2385
2386     /* Step 1: Compose Consonant and Nukta */
2387     ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
2388     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2389
2390     /* Step 2: Reorder within Syllables */
2391     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2392     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2393     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2394     *pcGlyphs = cCount;
2395
2396     /* Step 3: Base Form application to syllables */
2397     ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2398
2399     HeapFree(GetProcessHeap(),0,input);
2400     HeapFree(GetProcessHeap(),0,syllables);
2401 }
2402
2403 static int bengali_lex(WCHAR c)
2404 {
2405     switch (c)
2406     {
2407         case 0x09B0: return lex_Ra;
2408         default:
2409             return unicode_lex(c);
2410     }
2411 }
2412
2413 static const VowelComponents Bengali_vowels[] = {
2414             {0x09CB, {0x09C7,0x09BE,0x0000}},
2415             {0x09CC, {0x09C7,0x09D7,0x0000}},
2416             {0x0000, {0x0000,0x0000,0x0000}}};
2417
2418 static const ConsonantComponents Bengali_consonants[] = {
2419             {{0x09A4,0x09CD,0x200D}, 0x09CE},
2420             {{0x09A1,0x09BC,0x0000}, 0x09DC},
2421             {{0x09A2,0x09BC,0x0000}, 0x09DD},
2422             {{0x09AF,0x09BC,0x0000}, 0x09DF},
2423             {{0x0000,0x0000,0x0000}, 0x0000}};
2424
2425 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2426 {
2427     int cCount = cChars;
2428     WCHAR *input;
2429     IndicSyllable *syllables = NULL;
2430     int syllable_count = 0;
2431     BOOL modern = get_GSUB_Indic2(psa, psc);
2432
2433     if (*pcGlyphs != cChars)
2434     {
2435         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2436         return;
2437     }
2438
2439     input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2440     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2441
2442     /* Step 1: Decompose Vowels and Compose Consonents */
2443     DecomposeVowels(hdc, input,  &cCount, Bengali_vowels);
2444     ComposeConsonants(hdc, input, &cCount, Bengali_consonants);
2445     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2446
2447     /* Step 2: Reorder within Syllables */
2448     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2449     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2450     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2451     *pcGlyphs = cCount;
2452
2453     /* Step 3: Initial form is only applied to the beginning of words */
2454     for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2455     {
2456         if (cCount == 0 || input[cCount] == 0x0020) /* space */
2457         {
2458             int index = cCount;
2459             int gCount = 1;
2460             if (index > 0) index++;
2461
2462             apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2463         }
2464     }
2465
2466     /* Step 4: Base Form application to syllables */
2467     ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2468
2469     HeapFree(GetProcessHeap(),0,input);
2470     HeapFree(GetProcessHeap(),0,syllables);
2471 }
2472
2473 static int gurmukhi_lex(WCHAR c)
2474 {
2475     return unicode_lex(c);
2476 }
2477
2478 static const ConsonantComponents Gurmukhi_consonants[] = {
2479             {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2480             {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2481             {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2482             {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2483             {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2484             {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2485             {{0x0000,0x0000,0x0000}, 0x0000}};
2486
2487 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2488 {
2489     int cCount = cChars;
2490     WCHAR *input;
2491     IndicSyllable *syllables = NULL;
2492     int syllable_count = 0;
2493     BOOL modern = get_GSUB_Indic2(psa, psc);
2494
2495     if (*pcGlyphs != cChars)
2496     {
2497         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2498         return;
2499     }
2500
2501     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2502     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2503
2504     /* Step 1: Compose Consonents */
2505     ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants);
2506     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2507
2508     /* Step 2: Reorder within Syllables */
2509     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2510     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2511     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2512     *pcGlyphs = cCount;
2513
2514     /* Step 3: Base Form application to syllables */
2515     ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2516
2517     HeapFree(GetProcessHeap(),0,input);
2518     HeapFree(GetProcessHeap(),0,syllables);
2519 }
2520
2521 static int gujarati_lex(WCHAR c)
2522 {
2523     switch (c)
2524     {
2525         case 0x0AB0: return lex_Ra;
2526         default:
2527             return unicode_lex(c);
2528     }
2529 }
2530
2531 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2532 {
2533     int cCount = cChars;
2534     WCHAR *input;
2535     IndicSyllable *syllables = NULL;
2536     int syllable_count = 0;
2537     BOOL modern = get_GSUB_Indic2(psa, psc);
2538
2539     if (*pcGlyphs != cChars)
2540     {
2541         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2542         return;
2543     }
2544
2545     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2546     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2547
2548     /* Step 1: Reorder within Syllables */
2549     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2550     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2551     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2552     *pcGlyphs = cCount;
2553
2554     /* Step 2: Base Form application to syllables */
2555     ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2556
2557     HeapFree(GetProcessHeap(),0,input);
2558     HeapFree(GetProcessHeap(),0,syllables);
2559 }
2560
2561 static int oriya_lex(WCHAR c)
2562 {
2563     switch (c)
2564     {
2565         case 0x0B30: return lex_Ra;
2566         default:
2567             return unicode_lex(c);
2568     }
2569 }
2570
2571 static const VowelComponents Oriya_vowels[] = {
2572             {0x0B48, {0x0B47,0x0B56,0x0000}},
2573             {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2574             {0x0B4C, {0x0B47,0x0B57,0x0000}},
2575             {0x0000, {0x0000,0x0000,0x0000}}};
2576
2577 static const ConsonantComponents Oriya_consonants[] = {
2578             {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2579             {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2580             {{0x0000,0x0000,0x0000}, 0x0000}};
2581
2582 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2583 {
2584     int cCount = cChars;
2585     WCHAR *input;
2586     IndicSyllable *syllables = NULL;
2587     int syllable_count = 0;
2588     BOOL modern = get_GSUB_Indic2(psa, psc);
2589
2590     if (*pcGlyphs != cChars)
2591     {
2592         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2593         return;
2594     }
2595
2596     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2597     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2598
2599     /* Step 1: Decompose Vowels and Compose Consonents */
2600     DecomposeVowels(hdc, input,  &cCount, Oriya_vowels);
2601     ComposeConsonants(hdc, input, &cCount, Oriya_consonants);
2602     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2603
2604     /* Step 2: Reorder within Syllables */
2605     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2606     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2607     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2608     *pcGlyphs = cCount;
2609
2610     /* Step 3: Base Form application to syllables */
2611     ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2612
2613     HeapFree(GetProcessHeap(),0,input);
2614     HeapFree(GetProcessHeap(),0,syllables);
2615 }
2616
2617 static int tamil_lex(WCHAR c)
2618 {
2619     return unicode_lex(c);
2620 }
2621
2622 static const VowelComponents Tamil_vowels[] = {
2623             {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2624             {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2625             {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2626             {0x0000, {0x0000,0x0000,0x0000}}};
2627
2628 static const ConsonantComponents Tamil_consonants[] = {
2629             {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2630             {{0x0000,0x0000,0x0000}, 0x0000}};
2631
2632 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2633 {
2634     int cCount = cChars;
2635     WCHAR *input;
2636     IndicSyllable *syllables = NULL;
2637     int syllable_count = 0;
2638     BOOL modern = get_GSUB_Indic2(psa, psc);
2639
2640     if (*pcGlyphs != cChars)
2641     {
2642         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2643         return;
2644     }
2645
2646     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2647     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2648
2649     /* Step 1: Decompose Vowels and Compose Consonents */
2650     DecomposeVowels(hdc, input,  &cCount, Tamil_vowels);
2651     ComposeConsonants(hdc, input, &cCount, Tamil_consonants);
2652     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2653
2654     /* Step 2: Reorder within Syllables */
2655     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2656     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2657     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2658     *pcGlyphs = cCount;
2659
2660     /* Step 3: Base Form application to syllables */
2661     ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2662
2663     HeapFree(GetProcessHeap(),0,input);
2664     HeapFree(GetProcessHeap(),0,syllables);
2665 }
2666
2667 static int telugu_lex(WCHAR c)
2668 {
2669     switch (c)
2670     {
2671         case 0x0C43:
2672         case 0x0C44: return lex_Modifier;
2673         default:
2674             return unicode_lex(c);
2675     }
2676 }
2677
2678 static const VowelComponents Telugu_vowels[] = {
2679             {0x0C48, {0x0C46,0x0C56,0x0000}},
2680             {0x0000, {0x0000,0x0000,0x0000}}};
2681
2682 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2683 {
2684     int cCount = cChars;
2685     WCHAR *input;
2686     IndicSyllable *syllables = NULL;
2687     int syllable_count = 0;
2688     BOOL modern = get_GSUB_Indic2(psa, psc);
2689
2690     if (*pcGlyphs != cChars)
2691     {
2692         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2693         return;
2694     }
2695
2696     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2697     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2698
2699     /* Step 1: Decompose Vowels */
2700     DecomposeVowels(hdc, input,  &cCount, Telugu_vowels);
2701     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2702
2703     /* Step 2: Reorder within Syllables */
2704     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2705     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2706     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2707     *pcGlyphs = cCount;
2708
2709     /* Step 3: Base Form application to syllables */
2710     ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2711
2712     HeapFree(GetProcessHeap(),0,input);
2713     HeapFree(GetProcessHeap(),0,syllables);
2714 }
2715
2716 static int kannada_lex(WCHAR c)
2717 {
2718     switch (c)
2719     {
2720         case 0x0CB0: return lex_Ra;
2721         default:
2722             return unicode_lex(c);
2723     }
2724 }
2725
2726 static const VowelComponents Kannada_vowels[] = {
2727             {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2728             {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2729             {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2730             {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2731             {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2732             {0x0000, {0x0000,0x0000,0x0000}}};
2733
2734 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2735 {
2736     int cCount = cChars;
2737     WCHAR *input;
2738     IndicSyllable *syllables = NULL;
2739     int syllable_count = 0;
2740     BOOL modern = get_GSUB_Indic2(psa, psc);
2741
2742     if (*pcGlyphs != cChars)
2743     {
2744         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2745         return;
2746     }
2747
2748     input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2749     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2750
2751     /* Step 1: Decompose Vowels */
2752     DecomposeVowels(hdc, input,  &cCount, Kannada_vowels);
2753     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2754
2755     /* Step 2: Reorder within Syllables */
2756     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2757     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2758     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2759     *pcGlyphs = cCount;
2760
2761     /* Step 3: Base Form application to syllables */
2762     ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2763
2764     HeapFree(GetProcessHeap(),0,input);
2765     HeapFree(GetProcessHeap(),0,syllables);
2766 }
2767
2768 static int malayalam_lex(WCHAR c)
2769 {
2770     return unicode_lex(c);
2771 }
2772
2773 static const VowelComponents Malayalam_vowels[] = {
2774             {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2775             {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2776             {0x0D4C, {0x0D46,0x0D57,0x0000}},
2777             {0x0000, {0x0000,0x0000,0x0000}}};
2778
2779 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2780 {
2781     int cCount = cChars;
2782     WCHAR *input;
2783     IndicSyllable *syllables = NULL;
2784     int syllable_count = 0;
2785     BOOL modern = get_GSUB_Indic2(psa, psc);
2786
2787     if (*pcGlyphs != cChars)
2788     {
2789         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2790         return;
2791     }
2792
2793     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2794     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2795
2796     /* Step 1: Decompose Vowels */
2797     DecomposeVowels(hdc, input,  &cCount, Malayalam_vowels);
2798     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2799
2800     /* Step 2: Reorder within Syllables */
2801     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2802     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2803     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2804     *pcGlyphs = cCount;
2805
2806     /* Step 3: Base Form application to syllables */
2807     ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2808
2809     HeapFree(GetProcessHeap(),0,input);
2810     HeapFree(GetProcessHeap(),0,syllables);
2811 }
2812
2813 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)
2814 {
2815     int i,k;
2816
2817     for (i = 0; i < cGlyphs; i++)
2818     {
2819         int char_index[20];
2820         int char_count = 0;
2821
2822         for (k = 0; k < cChars; k++)
2823         {
2824             if (pwLogClust[k] == i)
2825             {
2826                 char_index[char_count] = k;
2827                 char_count++;
2828             }
2829         }
2830
2831         if (char_count == 0)
2832         {
2833             FIXME("No chars in this glyph?  Must be an error\n");
2834             continue;
2835         }
2836
2837         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2838         {
2839             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2840             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2841         }
2842         else
2843             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2844     }
2845
2846     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2847     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2848 }
2849
2850 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 )
2851 {
2852     int i,k;
2853     int initGlyph, finaGlyph;
2854     INT dirR, dirL;
2855     BYTE *spaces;
2856
2857     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2858     memset(spaces,0,cGlyphs);
2859
2860     if (!psa->fLogicalOrder && psa->fRTL)
2861     {
2862         initGlyph = cGlyphs-1;
2863         finaGlyph = 0;
2864         dirR = 1;
2865         dirL = -1;
2866     }
2867     else
2868     {
2869         initGlyph = 0;
2870         finaGlyph = cGlyphs-1;
2871         dirR = -1;
2872         dirL = 1;
2873     }
2874
2875     for (i = 0; i < cGlyphs; i++)
2876     {
2877         for (k = 0; k < cChars; k++)
2878             if (pwLogClust[k] == i)
2879             {
2880                 if (pwcChars[k] == 0x0020)
2881                     spaces[i] = 1;
2882             }
2883     }
2884
2885     for (i = 0; i < cGlyphs; i++)
2886     {
2887         int char_index[20];
2888         int char_count = 0;
2889         BOOL isInit, isFinal;
2890
2891         for (k = 0; k < cChars; k++)
2892         {
2893             if (pwLogClust[k] == i)
2894             {
2895                 char_index[char_count] = k;
2896                 char_count++;
2897             }
2898         }
2899
2900         isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2901         isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2902
2903         if (char_count == 0)
2904         {
2905             FIXME("No chars in this glyph?  Must be an error\n");
2906             continue;
2907         }
2908
2909         if (char_count == 1)
2910         {
2911             if (pwcChars[char_index[0]] == 0x0020)  /* space */
2912             {
2913                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2914                 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2915             }
2916             else if (pwcChars[char_index[0]] == 0x0640)  /* kashida */
2917                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2918             else if (pwcChars[char_index[0]] == 0x0633)  /* SEEN */
2919             {
2920                 if (!isInit && !isFinal)
2921                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2922                 else if (isInit)
2923                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2924                 else
2925                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2926             }
2927             else if (!isInit)
2928             {
2929                 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2930                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2931                 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2932                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2933                 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2934                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2935                 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2936                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2937                 else
2938                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2939             }
2940             else if (!isInit && !isFinal)
2941                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2942             else
2943                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2944         }
2945         else if (char_count == 2)
2946         {
2947             if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) ||  (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2948                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2949             else if (!isInit)
2950                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2951             else
2952                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2953         }
2954         else if (!isInit && !isFinal)
2955             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2956         else
2957             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2958     }
2959
2960     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2961     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2962     HeapFree(GetProcessHeap(),0,spaces);
2963 }
2964
2965 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 )
2966 {
2967     int i,k;
2968     int finaGlyph;
2969     INT dirL;
2970     BYTE *spaces;
2971
2972     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2973     memset(spaces,0,cGlyphs);
2974
2975     if (!psa->fLogicalOrder && psa->fRTL)
2976     {
2977         finaGlyph = 0;
2978         dirL = -1;
2979     }
2980     else
2981     {
2982         finaGlyph = cGlyphs-1;
2983         dirL = 1;
2984     }
2985
2986     for (i = 0; i < cGlyphs; i++)
2987     {
2988         for (k = 0; k < cChars; k++)
2989             if (pwLogClust[k] == i)
2990             {
2991                 if (pwcChars[k] == 0x0020)
2992                     spaces[i] = 1;
2993             }
2994     }
2995
2996     for (i = 0; i < cGlyphs; i++)
2997     {
2998         int char_index[20];
2999         int char_count = 0;
3000
3001         for (k = 0; k < cChars; k++)
3002         {
3003             if (pwLogClust[k] == i)
3004             {
3005                 char_index[char_count] = k;
3006                 char_count++;
3007             }
3008         }
3009
3010         if (char_count == 0)
3011         {
3012             FIXME("No chars in this glyph?  Must be an error\n");
3013             continue;
3014         }
3015
3016         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
3017         {
3018             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3019             pCharProp[char_index[0]].fCanGlyphAlone = 1;
3020         }
3021         else if (i == finaGlyph)
3022             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3023         else
3024             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3025     }
3026
3027     HeapFree(GetProcessHeap(),0,spaces);
3028     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3029     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3030
3031     /* Do not allow justification between marks and their base */
3032     for (i = 0; i < cGlyphs; i++)
3033     {
3034         if (!pGlyphProp[i].sva.fClusterStart)
3035             pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3036     }
3037 }
3038
3039 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)
3040 {
3041     int i,k;
3042
3043     for (i = 0; i < cGlyphs; i++)
3044     {
3045         int char_index[20];
3046         int char_count = 0;
3047
3048         for (k = 0; k < cChars; k++)
3049         {
3050             if (pwLogClust[k] == i)
3051             {
3052                 char_index[char_count] = k;
3053                 char_count++;
3054             }
3055         }
3056
3057         if (char_count == 0)
3058         {
3059             FIXME("No chars in this glyph?  Must be an error\n");
3060             continue;
3061         }
3062
3063         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
3064         {
3065             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3066             pCharProp[char_index[0]].fCanGlyphAlone = 1;
3067         }
3068         else
3069             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3070     }
3071     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3072     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3073 }
3074
3075 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)
3076 {
3077     int i,k;
3078
3079     for (i = 0; i < cGlyphs; i++)
3080     {
3081         int char_index[20];
3082         int char_count = 0;
3083
3084         for (k = 0; k < cChars; k++)
3085         {
3086             if (pwLogClust[k] == i)
3087             {
3088                 char_index[char_count] = k;
3089                 char_count++;
3090             }
3091         }
3092
3093         if (char_count == 0)
3094         {
3095             FIXME("No chars in this glyph?  Must be an error\n");
3096             continue;
3097         }
3098
3099         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
3100         {
3101             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3102             pCharProp[char_index[0]].fCanGlyphAlone = 1;
3103         }
3104         else
3105             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3106     }
3107     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3108     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3109
3110     /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3111     for (i = 0; i < cGlyphs; i++)
3112     {
3113         if (!pGlyphProp[i].sva.fClusterStart)
3114         {
3115             pGlyphProp[i].sva.fDiacritic = 0;
3116             pGlyphProp[i].sva.fZeroWidth = 0;
3117         }
3118     }
3119 }
3120
3121 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)
3122 {
3123     int i,k;
3124
3125     for (i = 0; i < cGlyphs; i++)
3126     {
3127         int char_index[20];
3128         int char_count = 0;
3129
3130         for (k = 0; k < cChars; k++)
3131         {
3132             if (pwLogClust[k] == i)
3133             {
3134                 char_index[char_count] = k;
3135                 char_count++;
3136             }
3137         }
3138
3139         if (char_count == 0)
3140         {
3141             FIXME("No chars in this glyph?  Must be an error\n");
3142             continue;
3143         }
3144
3145         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
3146         {
3147             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3148             pCharProp[char_index[0]].fCanGlyphAlone = 1;
3149         }
3150         else
3151             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3152
3153         pGlyphProp[i].sva.fClusterStart = 0;
3154         for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3155             switch (lexical(pwcChars[char_index[k]]))
3156             {
3157                 case lex_Matra_pre:
3158                 case lex_Matra_post:
3159                 case lex_Matra_above:
3160                 case lex_Matra_below:
3161                 case lex_Modifier:
3162                     break;
3163                 default:
3164                     pGlyphProp[i].sva.fClusterStart = 1;
3165                     break;
3166             }
3167     }
3168     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3169 }
3170
3171 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 )
3172 {
3173     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3174 }
3175
3176 static void ShapeCharGlyphProp_Bengali( 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 )
3177 {
3178     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3179 }
3180
3181 static void ShapeCharGlyphProp_Gurmukhi( 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 )
3182 {
3183     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3184 }
3185
3186 static void ShapeCharGlyphProp_Gujarati( 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 )
3187 {
3188     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3189 }
3190
3191 static void ShapeCharGlyphProp_Oriya( 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 )
3192 {
3193     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3194 }
3195
3196 static void ShapeCharGlyphProp_Tamil( 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 )
3197 {
3198     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3199 }
3200
3201 static void ShapeCharGlyphProp_Telugu( 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 )
3202 {
3203     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3204 }
3205
3206 static void ShapeCharGlyphProp_Kannada( 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 )
3207 {
3208     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3209 }
3210
3211 static void ShapeCharGlyphProp_Malayalam( 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 )
3212 {
3213     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3214 }
3215
3216 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)
3217 {
3218     if (ShapingData[psa->eScript].charGlyphPropProc)
3219         ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3220     else
3221         ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3222 }
3223
3224 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3225 {
3226     if (ShapingData[psa->eScript].contextProc)
3227         ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3228 }
3229
3230 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)
3231 {
3232     int i;
3233     INT dirL;
3234
3235     if (!rpRangeProperties)
3236         return;
3237
3238     if (!psc->GSUB_Table)
3239         psc->GSUB_Table = load_gsub_table(hdc);
3240
3241     if (!psc->GSUB_Table)
3242         return;
3243
3244     if (!psa->fLogicalOrder && psa->fRTL)
3245         dirL = -1;
3246     else
3247         dirL = 1;
3248
3249     for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3250     {
3251         if (rpRangeProperties->potfRecords[i].lParameter > 0)
3252         apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3253     }
3254 }
3255
3256 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3257 {
3258 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3259 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3260
3261     SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3262 }
3263
3264 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3265 {
3266     const GSUB_Feature *feature;
3267     int i;
3268
3269     if (!ShapingData[psa->eScript].requiredFeatures)
3270         return S_OK;
3271
3272     if (!psc->GSUB_Table)
3273         psc->GSUB_Table = load_gsub_table(hdc);
3274
3275     /* we need to have at least one of the required features */
3276     i = 0;
3277     while (ShapingData[psa->eScript].requiredFeatures[i])
3278     {
3279         feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3280         if (feature)
3281             return S_OK;
3282         i++;
3283     }
3284
3285     return USP_E_SCRIPT_NOT_IN_FONT;
3286 }