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