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