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