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