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