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