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