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