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