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