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