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