mmdevapi/tests: Fix wrong buffer unit and memory leaks.
[wine] / dlls / usp10 / shape.c
1 /*
2  * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
3  *
4  * Copyright 2010 CodeWeavers, Aric Stewart
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  */
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "usp10.h"
29 #include "winternl.h"
30
31 #include "usp10_internal.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
36
37 #define FIRST_ARABIC_CHAR 0x0600
38 #define LAST_ARABIC_CHAR  0x06ff
39
40 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
41                                       WCHAR*, INT, WORD*, INT*, INT, WORD*);
42
43 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
44 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56
57 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
58
59 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
60 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 );
61 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 );
62 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 );
63 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 );
64 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 );
65 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 );
66 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 );
67 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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73
74 extern const unsigned short wine_shaping_table[];
75 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
76
77 enum joining_types {
78     jtU,
79     jtT,
80     jtR,
81     jtL,
82     jtD,
83     jtC
84 };
85
86 enum joined_forms {
87     Xn=0,
88     Xr,
89     Xl,
90     Xm,
91     /* Syriac Alaph */
92     Afj,
93     Afn,
94     Afx
95 };
96
97 #ifdef WORDS_BIGENDIAN
98 #define GET_BE_WORD(x) (x)
99 #else
100 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
101 #endif
102
103 /* These are all structures needed for the GSUB table */
104 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
105 #define GSUB_E_NOFEATURE -2
106 #define GSUB_E_NOGLYPH -1
107
108 typedef struct {
109     DWORD version;
110     WORD ScriptList;
111     WORD FeatureList;
112     WORD LookupList;
113 } GSUB_Header;
114
115 typedef struct {
116     CHAR ScriptTag[4];
117     WORD Script;
118 } GSUB_ScriptRecord;
119
120 typedef struct {
121     WORD ScriptCount;
122     GSUB_ScriptRecord ScriptRecord[1];
123 } GSUB_ScriptList;
124
125 typedef struct {
126     CHAR LangSysTag[4];
127     WORD LangSys;
128 } GSUB_LangSysRecord;
129
130 typedef struct {
131     WORD DefaultLangSys;
132     WORD LangSysCount;
133     GSUB_LangSysRecord LangSysRecord[1];
134 } GSUB_Script;
135
136 typedef struct {
137     WORD LookupOrder; /* Reserved */
138     WORD ReqFeatureIndex;
139     WORD FeatureCount;
140     WORD FeatureIndex[1];
141 } GSUB_LangSys;
142
143 typedef struct {
144     CHAR FeatureTag[4];
145     WORD Feature;
146 } GSUB_FeatureRecord;
147
148 typedef struct {
149     WORD FeatureCount;
150     GSUB_FeatureRecord FeatureRecord[1];
151 } GSUB_FeatureList;
152
153 typedef struct {
154     WORD FeatureParams; /* Reserved */
155     WORD LookupCount;
156     WORD LookupListIndex[1];
157 } GSUB_Feature;
158
159 typedef struct {
160     WORD LookupCount;
161     WORD Lookup[1];
162 } GSUB_LookupList;
163
164 typedef struct {
165     WORD LookupType;
166     WORD LookupFlag;
167     WORD SubTableCount;
168     WORD SubTable[1];
169 } GSUB_LookupTable;
170
171 typedef struct {
172     WORD CoverageFormat;
173     WORD GlyphCount;
174     WORD GlyphArray[1];
175 } GSUB_CoverageFormat1;
176
177 typedef struct {
178     WORD Start;
179     WORD End;
180     WORD StartCoverageIndex;
181 } GSUB_RangeRecord;
182
183 typedef struct {
184     WORD CoverageFormat;
185     WORD RangeCount;
186     GSUB_RangeRecord RangeRecord[1];
187 } GSUB_CoverageFormat2;
188
189 typedef struct {
190     WORD SubstFormat; /* = 1 */
191     WORD Coverage;
192     WORD DeltaGlyphID;
193 } GSUB_SingleSubstFormat1;
194
195 typedef struct {
196     WORD SubstFormat; /* = 2 */
197     WORD Coverage;
198     WORD GlyphCount;
199     WORD Substitute[1];
200 }GSUB_SingleSubstFormat2;
201
202 typedef struct {
203     WORD SubstFormat; /* = 1 */
204     WORD Coverage;
205     WORD LigSetCount;
206     WORD LigatureSet[1];
207 }GSUB_LigatureSubstFormat1;
208
209 typedef struct {
210     WORD LigatureCount;
211     WORD Ligature[1];
212 }GSUB_LigatureSet;
213
214 typedef struct{
215     WORD LigGlyph;
216     WORD CompCount;
217     WORD Component[1];
218 }GSUB_Ligature;
219
220 typedef struct{
221     WORD SequenceIndex;
222     WORD LookupListIndex;
223
224 }GSUB_SubstLookupRecord;
225
226 typedef struct{
227     WORD SubstFormat; /* = 1 */
228     WORD Coverage;
229     WORD ChainSubRuleSetCount;
230     WORD ChainSubRuleSet[1];
231 }GSUB_ChainContextSubstFormat1;
232
233 typedef struct {
234     WORD SubstFormat; /* = 3 */
235     WORD BacktrackGlyphCount;
236     WORD Coverage[1];
237 }GSUB_ChainContextSubstFormat3_1;
238
239 typedef struct{
240     WORD InputGlyphCount;
241     WORD Coverage[1];
242 }GSUB_ChainContextSubstFormat3_2;
243
244 typedef struct{
245     WORD LookaheadGlyphCount;
246     WORD Coverage[1];
247 }GSUB_ChainContextSubstFormat3_3;
248
249 typedef struct{
250     WORD SubstCount;
251     GSUB_SubstLookupRecord SubstLookupRecord[1];
252 }GSUB_ChainContextSubstFormat3_4;
253
254 typedef struct {
255     WORD SubstFormat; /* = 1 */
256     WORD Coverage;
257     WORD AlternateSetCount;
258     WORD AlternateSet[1];
259 } GSUB_AlternateSubstFormat1;
260
261 typedef struct{
262     WORD GlyphCount;
263     WORD Alternate[1];
264 } GSUB_AlternateSet;
265
266 /* These are all structures needed for the GDEF table */
267 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
268
269 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
270
271 typedef struct {
272     DWORD Version;
273     WORD GlyphClassDef;
274     WORD AttachList;
275     WORD LigCaretList;
276     WORD MarkAttachClassDef;
277 } GDEF_Header;
278
279 typedef struct {
280     WORD ClassFormat;
281     WORD StartGlyph;
282     WORD GlyphCount;
283     WORD ClassValueArray[1];
284 } GDEF_ClassDefFormat1;
285
286 typedef struct {
287     WORD Start;
288     WORD End;
289     WORD Class;
290 } GDEF_ClassRangeRecord;
291
292 typedef struct {
293     WORD ClassFormat;
294     WORD ClassRangeCount;
295     GDEF_ClassRangeRecord ClassRangeRecord[1];
296 } GDEF_ClassDefFormat2;
297
298 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
299
300 typedef struct tagVowelComponents
301 {
302     WCHAR base;
303     WCHAR parts[3];
304 } VowelComponents;
305
306 typedef struct tagConsonantComponents
307 {
308     WCHAR parts[3];
309     WCHAR output;
310 } ConsonantComponents;
311
312 /* the orders of joined_forms and contextual_features need to line up */
313 static const char* contextual_features[] =
314 {
315     "isol",
316     "fina",
317     "init",
318     "medi",
319     /* Syriac Alaph */
320     "med2",
321     "fin2",
322     "fin3"
323 };
324
325 static OPENTYPE_FEATURE_RECORD standard_features[] =
326 {
327     { MS_MAKE_TAG('l','i','g','a'), 1},
328     { MS_MAKE_TAG('c','l','i','g'), 1},
329 };
330
331 static OPENTYPE_FEATURE_RECORD arabic_features[] =
332 {
333     { MS_MAKE_TAG('r','l','i','g'), 1},
334     { MS_MAKE_TAG('c','a','l','t'), 1},
335     { MS_MAKE_TAG('l','i','g','a'), 1},
336     { MS_MAKE_TAG('d','l','i','g'), 1},
337     { MS_MAKE_TAG('c','s','w','h'), 1},
338     { MS_MAKE_TAG('m','s','e','t'), 1},
339 };
340
341 static const char* required_arabic_features[] =
342 {
343     "fina",
344     "init",
345     "medi",
346     "rlig",
347     NULL
348 };
349
350 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
351 {
352     { MS_MAKE_TAG('d','l','i','g'), 1},
353 };
354
355 static OPENTYPE_FEATURE_RECORD syriac_features[] =
356 {
357     { MS_MAKE_TAG('r','l','i','g'), 1},
358     { MS_MAKE_TAG('c','a','l','t'), 1},
359     { MS_MAKE_TAG('l','i','g','a'), 1},
360     { MS_MAKE_TAG('d','l','i','g'), 1},
361 };
362
363 static const char* required_syriac_features[] =
364 {
365     "fina",
366     "fin2",
367     "fin3",
368     "init",
369     "medi",
370     "med2",
371     "rlig",
372     NULL
373 };
374
375 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
376 {
377     /* Base forms */
378     { MS_MAKE_TAG('a','k','h','n'), 1},
379     { MS_MAKE_TAG('r','p','h','f'), 1},
380     { MS_MAKE_TAG('v','a','t','u'), 1},
381     { MS_MAKE_TAG('p','s','t','f'), 1},
382     /* Presentation forms */
383     { MS_MAKE_TAG('b','l','w','s'), 1},
384     { MS_MAKE_TAG('a','b','v','s'), 1},
385     { MS_MAKE_TAG('p','s','t','s'), 1},
386 };
387
388 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
389 {
390     { MS_MAKE_TAG('a','b','v','s'), 1},
391     { MS_MAKE_TAG('b','l','w','s'), 1},
392 };
393
394 static OPENTYPE_FEATURE_RECORD thai_features[] =
395 {
396     { MS_MAKE_TAG('c','c','m','p'), 1},
397 };
398
399 static const char* required_lao_features[] =
400 {
401     "ccmp",
402     NULL
403 };
404
405 static const char* required_devanagari_features[] =
406 {
407     "nukt",
408     "akhn",
409     "rphf",
410     "blwf",
411     "half",
412     "vatu",
413     "pres",
414     "abvs",
415     "blws",
416     "psts",
417     "haln",
418     NULL
419 };
420
421 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
422 {
423     /* Localized forms */
424     { MS_MAKE_TAG('l','o','c','l'), 1},
425     /* Base forms */
426     { MS_MAKE_TAG('n','u','k','t'), 1},
427     { MS_MAKE_TAG('a','k','h','n'), 1},
428     { MS_MAKE_TAG('r','p','h','f'), 1},
429     { MS_MAKE_TAG('r','k','r','f'), 1},
430     { MS_MAKE_TAG('b','l','w','f'), 1},
431     { MS_MAKE_TAG('h','a','l','f'), 1},
432     { MS_MAKE_TAG('v','a','t','u'), 1},
433     { MS_MAKE_TAG('c','j','c','t'), 1},
434     /* Presentation forms */
435     { MS_MAKE_TAG('p','r','e','s'), 1},
436     { MS_MAKE_TAG('a','b','v','s'), 1},
437     { MS_MAKE_TAG('b','l','w','s'), 1},
438     { MS_MAKE_TAG('p','s','t','s'), 1},
439     { MS_MAKE_TAG('h','a','l','n'), 1},
440     { MS_MAKE_TAG('c','a','l','t'), 1},
441 };
442
443 static const char* required_bengali_features[] =
444 {
445     "nukt",
446     "akhn",
447     "rphf",
448     "blwf",
449     "half",
450     "vatu",
451     "pstf",
452     "init",
453     "abvs",
454     "blws",
455     "psts",
456     "haln",
457     NULL
458 };
459
460 static OPENTYPE_FEATURE_RECORD bengali_features[] =
461 {
462     /* Localized forms */
463     { MS_MAKE_TAG('l','o','c','l'), 1},
464     /* Base forms */
465     { MS_MAKE_TAG('n','u','k','t'), 1},
466     { MS_MAKE_TAG('a','k','h','n'), 1},
467     { MS_MAKE_TAG('r','p','h','f'), 1},
468     { MS_MAKE_TAG('b','l','w','f'), 1},
469     { MS_MAKE_TAG('h','a','l','f'), 1},
470     { MS_MAKE_TAG('p','s','t','f'), 1},
471     { MS_MAKE_TAG('v','a','t','u'), 1},
472     { MS_MAKE_TAG('c','j','c','t'), 1},
473     /* Presentation forms */
474     { MS_MAKE_TAG('i','n','i','t'), 1},
475     { MS_MAKE_TAG('p','r','e','s'), 1},
476     { MS_MAKE_TAG('a','b','v','s'), 1},
477     { MS_MAKE_TAG('b','l','w','s'), 1},
478     { MS_MAKE_TAG('p','s','t','s'), 1},
479     { MS_MAKE_TAG('h','a','l','n'), 1},
480     { MS_MAKE_TAG('c','a','l','t'), 1},
481 };
482
483 static const char* required_gurmukhi_features[] =
484 {
485     "nukt",
486     "akhn",
487     "rphf",
488     "blwf",
489     "half",
490     "pstf",
491     "vatu",
492     "cjct",
493     "pres",
494     "abvs",
495     "blws",
496     "psts",
497     "haln",
498     "calt",
499     NULL
500 };
501
502 static OPENTYPE_FEATURE_RECORD gurmukhi_features[] =
503 {
504     /* Localized forms */
505     { MS_MAKE_TAG('l','o','c','l'), 1},
506     /* Base forms */
507     { MS_MAKE_TAG('n','u','k','t'), 1},
508     { MS_MAKE_TAG('a','k','h','n'), 1},
509     { MS_MAKE_TAG('r','p','h','f'), 1},
510     { MS_MAKE_TAG('b','l','w','f'), 1},
511     { MS_MAKE_TAG('h','a','l','f'), 1},
512     { MS_MAKE_TAG('p','s','t','f'), 1},
513     { MS_MAKE_TAG('v','a','t','u'), 1},
514     { MS_MAKE_TAG('c','j','c','t'), 1},
515     /* Presentation forms */
516     { MS_MAKE_TAG('p','r','e','s'), 1},
517     { MS_MAKE_TAG('a','b','v','s'), 1},
518     { MS_MAKE_TAG('b','l','w','s'), 1},
519     { MS_MAKE_TAG('p','s','t','s'), 1},
520     { MS_MAKE_TAG('h','a','l','n'), 1},
521     { MS_MAKE_TAG('c','a','l','t'), 1},
522 };
523
524 static const char* required_oriya_features[] =
525 {
526     "nukt",
527     "akhn",
528     "rphf",
529     "blwf",
530     "pstf",
531     "cjct",
532     "pres",
533     "abvs",
534     "blws",
535     "psts",
536     "haln",
537     "calt",
538     NULL
539 };
540
541 static OPENTYPE_FEATURE_RECORD oriya_features[] =
542 {
543     /* Localized forms */
544     { MS_MAKE_TAG('l','o','c','l'), 1},
545     /* Base forms */
546     { MS_MAKE_TAG('n','u','k','t'), 1},
547     { MS_MAKE_TAG('a','k','h','n'), 1},
548     { MS_MAKE_TAG('r','p','h','f'), 1},
549     { MS_MAKE_TAG('b','l','w','f'), 1},
550     { MS_MAKE_TAG('p','s','t','f'), 1},
551     { MS_MAKE_TAG('c','j','c','t'), 1},
552     /* Presentation forms */
553     { MS_MAKE_TAG('p','r','e','s'), 1},
554     { MS_MAKE_TAG('a','b','v','s'), 1},
555     { MS_MAKE_TAG('b','l','w','s'), 1},
556     { MS_MAKE_TAG('p','s','t','s'), 1},
557     { MS_MAKE_TAG('h','a','l','n'), 1},
558     { MS_MAKE_TAG('c','a','l','t'), 1},
559 };
560
561 static const char* required_tamil_features[] =
562 {
563     "nukt",
564     "akhn",
565     "rphf",
566     "pref",
567     "half",
568     "pres",
569     "abvs",
570     "blws",
571     "psts",
572     "haln",
573     "calt",
574     NULL
575 };
576
577 static OPENTYPE_FEATURE_RECORD tamil_features[] =
578 {
579     /* Localized forms */
580     { MS_MAKE_TAG('l','o','c','l'), 1},
581     /* Base forms */
582     { MS_MAKE_TAG('n','u','k','t'), 1},
583     { MS_MAKE_TAG('a','k','h','n'), 1},
584     { MS_MAKE_TAG('r','p','h','f'), 1},
585     { MS_MAKE_TAG('p','r','e','f'), 1},
586     { MS_MAKE_TAG('h','a','l','f'), 1},
587     /* Presentation forms */
588     { MS_MAKE_TAG('p','r','e','s'), 1},
589     { MS_MAKE_TAG('a','b','v','s'), 1},
590     { MS_MAKE_TAG('b','l','w','s'), 1},
591     { MS_MAKE_TAG('p','s','t','s'), 1},
592     { MS_MAKE_TAG('h','a','l','n'), 1},
593     { MS_MAKE_TAG('c','a','l','t'), 1},
594 };
595
596 static const char* required_telugu_features[] =
597 {
598     "nukt",
599     "akhn",
600     "rphf",
601     "pref",
602     "half",
603     "pstf",
604     "cjct",
605     "pres",
606     "abvs",
607     "blws",
608     "psts",
609     "haln",
610     "calt",
611     NULL
612 };
613
614 static OPENTYPE_FEATURE_RECORD telugu_features[] =
615 {
616     /* Localized forms */
617     { MS_MAKE_TAG('l','o','c','l'), 1},
618     /* Base forms */
619     { MS_MAKE_TAG('n','u','k','t'), 1},
620     { MS_MAKE_TAG('a','k','h','n'), 1},
621     { MS_MAKE_TAG('r','p','h','f'), 1},
622     { MS_MAKE_TAG('p','r','e','f'), 1},
623     { MS_MAKE_TAG('b','l','w','f'), 1},
624     { MS_MAKE_TAG('h','a','l','f'), 1},
625     { MS_MAKE_TAG('p','s','t','f'), 1},
626     { MS_MAKE_TAG('c','j','c','t'), 1},
627     /* Presentation forms */
628     { MS_MAKE_TAG('p','r','e','s'), 1},
629     { MS_MAKE_TAG('a','b','v','s'), 1},
630     { MS_MAKE_TAG('b','l','w','s'), 1},
631     { MS_MAKE_TAG('p','s','t','s'), 1},
632     { MS_MAKE_TAG('h','a','l','n'), 1},
633     { MS_MAKE_TAG('c','a','l','t'), 1},
634 };
635
636 typedef struct ScriptShapeDataTag {
637     TEXTRANGE_PROPERTIES   defaultTextRange;
638     const char**           requiredFeatures;
639     CHAR                   otTag[5];
640     CHAR                   newOtTag[5];
641     ContextualShapingProc  contextProc;
642     ShapeCharGlyphPropProc charGlyphPropProc;
643 } ScriptShapeData;
644
645 /* in order of scripts */
646 static const ScriptShapeData ShapingData[] =
647 {
648     {{ standard_features, 2}, NULL, "", "", NULL, NULL},
649     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
650     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
651     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
652     {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
653     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
654     {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
655     {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
656     {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
657     {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
658     {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
659     {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
660     {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
661     {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
662     {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
663     {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
664     {{ sinhala_features, 7}, NULL, "sinh", "", ContextualShape_Sinhala, NULL},
665     {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
666     {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
667     {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
668     {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
669     {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
670     {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
671     {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
672     {{ devanagari_features, 15}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
673     {{ devanagari_features, 15}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
674     {{ bengali_features, 16}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
675     {{ bengali_features, 16}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
676     {{ gurmukhi_features, 15}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
677     {{ gurmukhi_features, 15}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
678     {{ devanagari_features, 15}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
679     {{ devanagari_features, 15}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
680     {{ devanagari_features, 15}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
681     {{ oriya_features, 13}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
682     {{ oriya_features, 13}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
683     {{ tamil_features, 12}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
684     {{ tamil_features, 12}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
685     {{ telugu_features, 15}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
686     {{ telugu_features, 15}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
687     {{ telugu_features, 15}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
688     {{ telugu_features, 15}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
689     {{ telugu_features, 15}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
690     {{ telugu_features, 15}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
691 };
692
693 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
694 {
695     const GSUB_CoverageFormat1* cf1;
696
697     cf1 = table;
698
699     if (GET_BE_WORD(cf1->CoverageFormat) == 1)
700     {
701         int count = GET_BE_WORD(cf1->GlyphCount);
702         int i;
703         TRACE("Coverage Format 1, %i glyphs\n",count);
704         for (i = 0; i < count; i++)
705             if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
706                 return i;
707         return -1;
708     }
709     else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
710     {
711         const GSUB_CoverageFormat2* cf2;
712         int i;
713         int count;
714         cf2 = (const GSUB_CoverageFormat2*)cf1;
715
716         count = GET_BE_WORD(cf2->RangeCount);
717         TRACE("Coverage Format 2, %i ranges\n",count);
718         for (i = 0; i < count; i++)
719         {
720             if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
721                 return -1;
722             if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
723                 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
724             {
725                 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
726                     glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
727             }
728         }
729         return -1;
730     }
731     else
732         ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
733
734     return -1;
735 }
736
737 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
738 {
739     const GSUB_ScriptList *script;
740     const GSUB_Script *deflt = NULL;
741     int i;
742     script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
743
744     TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
745     for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
746     {
747         const GSUB_Script *scr;
748         int offset;
749
750         offset = GET_BE_WORD(script->ScriptRecord[i].Script);
751         scr = (const GSUB_Script*)((const BYTE*)script + offset);
752
753         if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
754             return scr;
755         if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
756             deflt = scr;
757     }
758     return deflt;
759 }
760
761 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
762 {
763     int i;
764     int offset;
765     const GSUB_LangSys *Lang;
766
767     TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
768
769     for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
770     {
771         offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
772         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
773
774         if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
775             return Lang;
776     }
777     offset = GET_BE_WORD(script->DefaultLangSys);
778     if (offset)
779     {
780         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
781         return Lang;
782     }
783     return NULL;
784 }
785
786 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
787 {
788     int i;
789     const GSUB_FeatureList *feature;
790     feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
791
792     TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
793     for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
794     {
795         int index = GET_BE_WORD(lang->FeatureIndex[i]);
796         if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
797         {
798             const GSUB_Feature *feat;
799             feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
800             return feat;
801         }
802     }
803     return NULL;
804 }
805
806 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
807 {
808     int j;
809     TRACE("Single Substitution Subtable\n");
810
811     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
812     {
813         int offset;
814         const GSUB_SingleSubstFormat1 *ssf1;
815         offset = GET_BE_WORD(look->SubTable[j]);
816         ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
817         if (GET_BE_WORD(ssf1->SubstFormat) == 1)
818         {
819             int offset = GET_BE_WORD(ssf1->Coverage);
820             TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
821             if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
822             {
823                 TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
824                 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
825                 TRACE(" 0x%x\n",glyphs[glyph_index]);
826                 return glyph_index + 1;
827             }
828         }
829         else
830         {
831             const GSUB_SingleSubstFormat2 *ssf2;
832             INT index;
833             INT offset;
834
835             ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
836             offset = GET_BE_WORD(ssf1->Coverage);
837             TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
838             index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
839             TRACE("  Coverage index %i\n",index);
840             if (index != -1)
841             {
842                 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
843                     return GSUB_E_NOGLYPH;
844
845                 TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
846                 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
847                 TRACE("0x%x\n",glyphs[glyph_index]);
848                 return glyph_index + 1;
849             }
850         }
851     }
852     return GSUB_E_NOGLYPH;
853 }
854
855 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
856 {
857     int j;
858     TRACE("Alternate Substitution Subtable\n");
859
860     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
861     {
862         int offset;
863         const GSUB_AlternateSubstFormat1 *asf1;
864         INT index;
865
866         offset = GET_BE_WORD(look->SubTable[j]);
867         asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
868         offset = GET_BE_WORD(asf1->Coverage);
869
870         index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
871         if (index != -1)
872         {
873             const GSUB_AlternateSet *as;
874             offset =  GET_BE_WORD(asf1->AlternateSet[index]);
875             as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
876             FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
877             if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
878                 return GSUB_E_NOGLYPH;
879
880             TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
881             glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
882             TRACE(" 0x%x\n",glyphs[glyph_index]);
883             return glyph_index + 1;
884         }
885     }
886     return GSUB_E_NOGLYPH;
887 }
888
889 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
890 {
891     int j;
892
893     TRACE("Ligature Substitution Subtable\n");
894     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
895     {
896         const GSUB_LigatureSubstFormat1 *lsf1;
897         int offset,index;
898
899         offset = GET_BE_WORD(look->SubTable[j]);
900         lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
901         offset = GET_BE_WORD(lsf1->Coverage);
902         index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
903         TRACE("  Coverage index %i\n",index);
904         if (index != -1)
905         {
906             const GSUB_LigatureSet *ls;
907             int k, count;
908
909             offset = GET_BE_WORD(lsf1->LigatureSet[index]);
910             ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
911             count = GET_BE_WORD(ls->LigatureCount);
912             TRACE("  LigatureSet has %i members\n",count);
913             for (k = 0; k < count; k++)
914             {
915                 const GSUB_Ligature *lig;
916                 int CompCount,l,CompIndex;
917
918                 offset = GET_BE_WORD(ls->Ligature[k]);
919                 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
920                 CompCount = GET_BE_WORD(lig->CompCount) - 1;
921                 CompIndex = glyph_index+write_dir;
922                 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
923                 {
924                     int CompGlyph;
925                     CompGlyph = GET_BE_WORD(lig->Component[l]);
926                     if (CompGlyph != glyphs[CompIndex])
927                         break;
928                     CompIndex += write_dir;
929                 }
930                 if (l == CompCount)
931                 {
932                     int replaceIdx = glyph_index;
933                     if (write_dir < 0)
934                         replaceIdx = glyph_index - CompCount;
935
936                     TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
937                     glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
938                     TRACE("0x%x\n",glyphs[replaceIdx]);
939                     if (CompCount > 0)
940                     {
941                         int j;
942                         for (j = replaceIdx + 1; j < *glyph_count; j++)
943                             glyphs[j] =glyphs[j+CompCount];
944                         *glyph_count = *glyph_count - CompCount;
945                     }
946                     return replaceIdx + 1;
947                 }
948             }
949         }
950     }
951     return GSUB_E_NOGLYPH;
952 }
953
954 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
955 {
956     int j;
957     BOOL done = FALSE;
958
959     TRACE("Chaining Contextual Substitution Subtable\n");
960     for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
961     {
962         const GSUB_ChainContextSubstFormat1 *ccsf1;
963         int offset;
964         int dirLookahead = write_dir;
965         int dirBacktrack = -1 * write_dir;
966
967         offset = GET_BE_WORD(look->SubTable[j]);
968         ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
969         if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
970         {
971             FIXME("  TODO: subtype 1 (Simple context glyph substitution)\n");
972             continue;
973         }
974         else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
975         {
976             FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
977             continue;
978         }
979         else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
980         {
981             int k;
982             int indexGlyphs;
983             const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
984             const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
985             const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
986             const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
987             int newIndex = glyph_index;
988
989             ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
990
991             TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
992
993             for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
994             {
995                 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
996                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
997                     break;
998             }
999             if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
1000                 continue;
1001             TRACE("Matched Backtrack\n");
1002
1003             ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
1004
1005             indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
1006             for (k = 0; k < indexGlyphs; k++)
1007             {
1008                 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
1009                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
1010                     break;
1011             }
1012             if (k != indexGlyphs)
1013                 continue;
1014             TRACE("Matched IndexGlyphs\n");
1015
1016             ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
1017
1018             for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
1019             {
1020                 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
1021                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
1022                     break;
1023             }
1024             if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
1025                 continue;
1026             TRACE("Matched LookAhead\n");
1027
1028             ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
1029
1030             for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
1031             {
1032                 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
1033                 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
1034
1035                 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
1036                 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
1037                 if (newIndex == -1)
1038                 {
1039                     ERR("Chain failed to generate a glyph\n");
1040                     continue;
1041                 }
1042             }
1043             return newIndex + 1;
1044         }
1045     }
1046     return -1;
1047 }
1048
1049 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1050 {
1051     int offset;
1052     const GSUB_LookupTable *look;
1053
1054     offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1055     look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1056     TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1057     switch(GET_BE_WORD(look->LookupType))
1058     {
1059         case 1:
1060             return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1061         case 3:
1062             return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1063         case 4:
1064             return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1065         case 6:
1066             return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1067         default:
1068             FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1069     }
1070     return GSUB_E_NOGLYPH;
1071 }
1072
1073 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1074 {
1075     int i;
1076     int out_index = GSUB_E_NOGLYPH;
1077     const GSUB_LookupList *lookup;
1078
1079     lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1080
1081     TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1082     for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1083     {
1084         out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1085         if (out_index != GSUB_E_NOGLYPH)
1086             break;
1087     }
1088     if (out_index == GSUB_E_NOGLYPH)
1089         TRACE("lookups found no glyphs\n");
1090     else
1091     {
1092         int out2;
1093         out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1094         if (out2!=GSUB_E_NOGLYPH)
1095             out_index = out2;
1096     }
1097     return out_index;
1098 }
1099
1100 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1101 {
1102     UINT charset;
1103
1104     if (psc->userScript != 0)
1105     {
1106         if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1107             return ShapingData[psa->eScript].newOtTag;
1108         else
1109             return (char*)&psc->userScript;
1110     }
1111
1112     if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1113         return ShapingData[psa->eScript].newOtTag;
1114
1115     if (ShapingData[psa->eScript].otTag[0] != 0)
1116         return ShapingData[psa->eScript].otTag;
1117
1118     /*
1119      * fall back to the font charset
1120      */
1121     charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1122     switch (charset)
1123     {
1124         case ANSI_CHARSET: return "latn";
1125         case BALTIC_CHARSET: return "latn"; /* ?? */
1126         case CHINESEBIG5_CHARSET: return "hani";
1127         case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1128         case GB2312_CHARSET: return "hani";
1129         case GREEK_CHARSET: return "grek";
1130         case HANGUL_CHARSET: return "hang";
1131         case RUSSIAN_CHARSET: return "cyrl";
1132         case SHIFTJIS_CHARSET: return "kana";
1133         case TURKISH_CHARSET: return "latn"; /* ?? */
1134         case VIETNAMESE_CHARSET: return "latn";
1135         case JOHAB_CHARSET: return "latn"; /* ?? */
1136         case ARABIC_CHARSET: return "arab";
1137         case HEBREW_CHARSET: return "hebr";
1138         case THAI_CHARSET: return "thai";
1139         default: return "latn";
1140     }
1141 }
1142
1143 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1144 {
1145     const GSUB_Feature *feature;
1146     int i;
1147
1148     for (i = 0; i <  psc->feature_count; i++)
1149         if (strncmp(psc->features[i].tag,feat,4)==0)
1150             return psc->features[i].feature;
1151
1152     feature = NULL;
1153
1154     if (psc->GSUB_Table)
1155     {
1156         const GSUB_Script *script;
1157         const GSUB_LangSys *language;
1158         int attempt = 2;
1159
1160         do
1161         {
1162             script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1163             attempt--;
1164             if (script)
1165             {
1166                 if (psc->userLang != 0)
1167                     language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1168                 else
1169                     language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1170                 if (language)
1171                     feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1172             }
1173         } while(attempt && !feature);
1174
1175         /* try in the default (latin) table */
1176         if (!feature)
1177         {
1178             script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1179             if (script)
1180             {
1181                 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1182                 if (language)
1183                     feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1184             }
1185         }
1186     }
1187
1188     TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1189
1190     psc->feature_count++;
1191
1192     if (psc->features)
1193         psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1194     else
1195         psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1196
1197     lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1198     psc->features[psc->feature_count - 1].feature = feature;
1199     return feature;
1200 }
1201
1202 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)
1203 {
1204     const GSUB_Feature *feature;
1205
1206     feature = load_GSUB_feature(hdc, psa, psc, feat);
1207     if (!feature)
1208         return GSUB_E_NOFEATURE;
1209
1210     TRACE("applying feature %s\n",feat);
1211     return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1212 }
1213
1214 static VOID *load_gsub_table(HDC hdc)
1215 {
1216     VOID* GSUB_Table = NULL;
1217     int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1218     if (length != GDI_ERROR)
1219     {
1220         GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1221         GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1222         TRACE("Loaded GSUB table of %i bytes\n",length);
1223     }
1224     return GSUB_Table;
1225 }
1226
1227 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1228 {
1229     int offset;
1230     WORD class = 0;
1231     const GDEF_ClassDefFormat1 *cf1;
1232
1233     if (!header)
1234         return 0;
1235
1236     offset = GET_BE_WORD(header->GlyphClassDef);
1237     if (!offset)
1238         return 0;
1239
1240     cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1241     if (GET_BE_WORD(cf1->ClassFormat) == 1)
1242     {
1243         if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1244         {
1245             int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1246             if (index < GET_BE_WORD(cf1->GlyphCount))
1247                 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1248         }
1249     }
1250     else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1251     {
1252         const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1253         int i, top;
1254         top = GET_BE_WORD(cf2->ClassRangeCount);
1255         for (i = 0; i < top; i++)
1256         {
1257             if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1258                 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1259             {
1260                 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1261                 break;
1262             }
1263         }
1264     }
1265     else
1266         ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1267
1268     return class;
1269 }
1270
1271 static VOID *load_gdef_table(HDC hdc)
1272 {
1273     VOID* GDEF_Table = NULL;
1274     int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1275     if (length != GDI_ERROR)
1276     {
1277         GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1278         GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1279         TRACE("Loaded GDEF table of %i bytes\n",length);
1280     }
1281     return GDEF_Table;
1282 }
1283
1284 static void GDEF_UpdateGlyphProps(HDC hdc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1285 {
1286     VOID* header = load_gdef_table(hdc);
1287     int i;
1288
1289     for (i = 0; i < cGlyphs; i++)
1290     {
1291         WORD class;
1292
1293         class = GDEF_get_glyph_class(header, pwGlyphs[i]);
1294
1295         switch (class)
1296         {
1297             case 0:
1298             case BaseGlyph:
1299                 pGlyphProp[i].sva.fClusterStart = 1;
1300                 pGlyphProp[i].sva.fDiacritic = 0;
1301                 pGlyphProp[i].sva.fZeroWidth = 0;
1302                 break;
1303             case LigatureGlyph:
1304                 pGlyphProp[i].sva.fClusterStart = 1;
1305                 pGlyphProp[i].sva.fDiacritic = 0;
1306                 pGlyphProp[i].sva.fZeroWidth = 0;
1307                 break;
1308             case MarkGlyph:
1309                 pGlyphProp[i].sva.fClusterStart = 0;
1310                 pGlyphProp[i].sva.fDiacritic = 1;
1311                 pGlyphProp[i].sva.fZeroWidth = 1;
1312                 break;
1313             case ComponentGlyph:
1314                 pGlyphProp[i].sva.fClusterStart = 0;
1315                 pGlyphProp[i].sva.fDiacritic = 0;
1316                 pGlyphProp[i].sva.fZeroWidth = 0;
1317                 break;
1318             default:
1319                 ERR("Unknown glyph class %i\n",class);
1320                 pGlyphProp[i].sva.fClusterStart = 1;
1321                 pGlyphProp[i].sva.fDiacritic = 0;
1322                 pGlyphProp[i].sva.fZeroWidth = 0;
1323         }
1324     }
1325 }
1326
1327 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1328 {
1329     int i;
1330
1331     for (i = 0; i < cGlyphs; i++)
1332     {
1333         if (!pGlyphProp[i].sva.fClusterStart)
1334         {
1335             int j;
1336             for (j = 0; j < cChars; j++)
1337             {
1338                 if (pwLogClust[j] == i)
1339                 {
1340                     int k = j;
1341                     while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1342                         k-=1;
1343                     if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1344                         pwLogClust[j] = pwLogClust[k];
1345                 }
1346             }
1347         }
1348     }
1349 }
1350
1351 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1352 {
1353     if (changeCount == 0)
1354         return;
1355     else
1356     {
1357         int i;
1358         int target_glyph = nextIndex - 1;
1359         int target_index = -1;
1360         int replacing_glyph = -1;
1361         int changed = 0;
1362
1363         if (write_dir > 0)
1364             for (i = 0; i < chars; i++)
1365             {
1366                 if (pwLogClust[i] == target_glyph)
1367                 {
1368                     target_index = i;
1369                     break;
1370                 }
1371             }
1372         else
1373             for (i = chars - 1; i >= 0; i--)
1374             {
1375                 if (pwLogClust[i] == target_glyph)
1376                 {
1377                     target_index = i;
1378                     break;
1379                 }
1380             }
1381         if (target_index == -1)
1382         {
1383             ERR("Unable to find target glyph\n");
1384             return;
1385         }
1386
1387         if (changeCount < 0)
1388         {
1389             /* merge glyphs */
1390             for(i = target_index; i < chars && i >= 0; i+=write_dir)
1391             {
1392                 if (pwLogClust[i] == target_glyph)
1393                     continue;
1394                 if(pwLogClust[i] == replacing_glyph)
1395                     pwLogClust[i] = target_glyph;
1396                 else
1397                 {
1398                     changed--;
1399                     if (changed >= changeCount)
1400                     {
1401                         replacing_glyph = pwLogClust[i];
1402                         pwLogClust[i] = target_glyph;
1403                     }
1404                     else
1405                         break;
1406                 }
1407             }
1408         }
1409
1410         /* renumber trailing indexes*/
1411         for(i = target_index; i < chars && i >= 0; i+=write_dir)
1412         {
1413             if (pwLogClust[i] != target_glyph)
1414                 pwLogClust[i] += changeCount;
1415         }
1416     }
1417 }
1418
1419 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 )
1420 {
1421     int i;
1422
1423     if (psc->GSUB_Table)
1424     {
1425         const GSUB_Feature *feature;
1426
1427         feature = load_GSUB_feature(hdc, psa, psc, feat);
1428         if (!feature)
1429             return GSUB_E_NOFEATURE;
1430
1431         i = 0;
1432         TRACE("applying feature %s\n",debugstr_an(feat,4));
1433         while(i < *pcGlyphs)
1434         {
1435                 INT nextIndex;
1436                 INT prevCount = *pcGlyphs;
1437                 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1438                 if (nextIndex > GSUB_E_NOGLYPH)
1439                 {
1440                     UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1441                     i = nextIndex;
1442                 }
1443                 else
1444                     i++;
1445         }
1446         return *pcGlyphs;
1447     }
1448     return GSUB_E_NOFEATURE;
1449 }
1450
1451 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1452 {
1453     if (i + delta < 0)
1454         return 0;
1455     if ( i+ delta >= cchLen)
1456         return 0;
1457
1458     i += delta;
1459
1460     return chars[i];
1461 }
1462
1463 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1464 {
1465     if (i + delta < 0)
1466     {
1467         if (psa->fLinkBefore)
1468             return jtR;
1469         else
1470             return jtU;
1471     }
1472     if ( i+ delta >= cchLen)
1473     {
1474         if (psa->fLinkAfter)
1475             return jtL;
1476         else
1477             return jtU;
1478     }
1479
1480     i += delta;
1481
1482     if (context_type[i] == jtT)
1483         return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1484     else
1485         return context_type[i];
1486 }
1487
1488 static inline BOOL right_join_causing(CHAR joining_type)
1489 {
1490     return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1491 }
1492
1493 static inline BOOL left_join_causing(CHAR joining_type)
1494 {
1495     return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1496 }
1497
1498 static inline BOOL word_break_causing(WCHAR chr)
1499 {
1500     /* we are working within a string of characters already guareented to
1501        be within one script, Syriac, so we do not worry about any characers
1502        other than the space character outside of that range */
1503     return (chr == 0 || chr == 0x20 );
1504 }
1505
1506 /*
1507  * ContextualShape_Arabic
1508  */
1509 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1510 {
1511     CHAR *context_type;
1512     INT *context_shape;
1513     INT dirR, dirL;
1514     int i;
1515
1516     if (*pcGlyphs != cChars)
1517     {
1518         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1519         return;
1520     }
1521
1522     if (!psa->fLogicalOrder && psa->fRTL)
1523     {
1524         dirR = 1;
1525         dirL = -1;
1526     }
1527     else
1528     {
1529         dirR = -1;
1530         dirL = 1;
1531     }
1532
1533     if (!psc->GSUB_Table)
1534         psc->GSUB_Table = load_gsub_table(hdc);
1535
1536     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1537     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1538
1539     for (i = 0; i < cChars; i++)
1540         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1541
1542     for (i = 0; i < cChars; i++)
1543     {
1544         if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1545             context_shape[i] = Xr;
1546         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1547             context_shape[i] = Xl;
1548         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)))
1549             context_shape[i] = Xm;
1550         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1551             context_shape[i] = Xr;
1552         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1553             context_shape[i] = Xl;
1554         else
1555             context_shape[i] = Xn;
1556     }
1557
1558     /* Contextual Shaping */
1559     i = 0;
1560     while(i < *pcGlyphs)
1561     {
1562         BOOL shaped = FALSE;
1563
1564         if (psc->GSUB_Table)
1565         {
1566             INT nextIndex;
1567             INT prevCount = *pcGlyphs;
1568             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1569             if (nextIndex > GSUB_E_NOGLYPH)
1570             {
1571                 i = nextIndex;
1572                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1573             }
1574             shaped = (nextIndex > GSUB_E_NOGLYPH);
1575         }
1576
1577         if (!shaped)
1578         {
1579             WORD newGlyph = pwOutGlyphs[i];
1580             if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1581             {
1582                 /* fall back to presentation form B */
1583                 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1584                 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1585                     pwOutGlyphs[i] = newGlyph;
1586             }
1587             i++;
1588         }
1589     }
1590
1591     HeapFree(GetProcessHeap(),0,context_shape);
1592     HeapFree(GetProcessHeap(),0,context_type);
1593 }
1594
1595 /*
1596  * ContextualShape_Syriac
1597  */
1598
1599 #define ALAPH 0x710
1600 #define DALATH 0x715
1601 #define RISH 0x72A
1602
1603 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1604 {
1605     CHAR *context_type;
1606     INT *context_shape;
1607     INT dirR, dirL;
1608     int i;
1609
1610     if (*pcGlyphs != cChars)
1611     {
1612         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1613         return;
1614     }
1615
1616     if (!psa->fLogicalOrder && psa->fRTL)
1617     {
1618         dirR = 1;
1619         dirL = -1;
1620     }
1621     else
1622     {
1623         dirR = -1;
1624         dirL = 1;
1625     }
1626
1627     if (!psc->GSUB_Table)
1628         psc->GSUB_Table = load_gsub_table(hdc);
1629
1630     if (!psc->GSUB_Table)
1631         return;
1632
1633     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1634     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1635
1636     for (i = 0; i < cChars; i++)
1637         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1638
1639     for (i = 0; i < cChars; i++)
1640     {
1641         if (pwcChars[i] == ALAPH)
1642         {
1643             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1644
1645             if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1646             context_shape[i] = Afj;
1647             else if ( rchar != DALATH && rchar != RISH &&
1648 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1649 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1650             context_shape[i] = Afn;
1651             else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1652             context_shape[i] = Afx;
1653             else
1654             context_shape[i] = Xn;
1655         }
1656         else if (context_type[i] == jtR &&
1657 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1658             context_shape[i] = Xr;
1659         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1660             context_shape[i] = Xl;
1661         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)))
1662             context_shape[i] = Xm;
1663         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1664             context_shape[i] = Xr;
1665         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1666             context_shape[i] = Xl;
1667         else
1668             context_shape[i] = Xn;
1669     }
1670
1671     /* Contextual Shaping */
1672     i = 0;
1673     while(i < *pcGlyphs)
1674     {
1675         INT nextIndex;
1676         INT prevCount = *pcGlyphs;
1677         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1678         if (nextIndex > GSUB_E_NOGLYPH)
1679         {
1680             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1681             i = nextIndex;
1682         }
1683         else
1684             i++;
1685     }
1686
1687     HeapFree(GetProcessHeap(),0,context_shape);
1688     HeapFree(GetProcessHeap(),0,context_type);
1689 }
1690
1691 /*
1692  * ContextualShape_Phags_pa
1693  */
1694
1695 #define phags_pa_CANDRABINDU  0xA873
1696 #define phags_pa_START 0xA840
1697 #define phags_pa_END  0xA87F
1698
1699 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1700 {
1701     INT *context_shape;
1702     INT dirR, dirL;
1703     int i;
1704
1705     if (*pcGlyphs != cChars)
1706     {
1707         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1708         return;
1709     }
1710
1711     if (!psa->fLogicalOrder && psa->fRTL)
1712     {
1713         dirR = 1;
1714         dirL = -1;
1715     }
1716     else
1717     {
1718         dirR = -1;
1719         dirL = 1;
1720     }
1721
1722     if (!psc->GSUB_Table)
1723         psc->GSUB_Table = load_gsub_table(hdc);
1724
1725     if (!psc->GSUB_Table)
1726         return;
1727
1728     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1729
1730     for (i = 0; i < cChars; i++)
1731     {
1732         if (pwcChars[i] >= phags_pa_START && pwcChars[i] <=  phags_pa_END)
1733         {
1734             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1735             WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1736             BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <=  phags_pa_END);
1737             BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <=  phags_pa_END);
1738
1739             if (jrchar && jlchar)
1740                 context_shape[i] = Xm;
1741             else if (jrchar)
1742                 context_shape[i] = Xr;
1743             else if (jlchar)
1744                 context_shape[i] = Xl;
1745             else
1746                 context_shape[i] = Xn;
1747         }
1748         else
1749             context_shape[i] = -1;
1750     }
1751
1752     /* Contextual Shaping */
1753     i = 0;
1754     while(i < *pcGlyphs)
1755     {
1756         if (context_shape[i] >= 0)
1757         {
1758             INT nextIndex;
1759             INT prevCount = *pcGlyphs;
1760             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1761             if (nextIndex > GSUB_E_NOGLYPH)
1762             {
1763                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1764                 i = nextIndex;
1765             }
1766             else
1767                 i++;
1768         }
1769         else
1770             i++;
1771     }
1772
1773     HeapFree(GetProcessHeap(),0,context_shape);
1774 }
1775
1776 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1777 {
1778     int i;
1779
1780     /* Replace */
1781     pwOutChars[cWalk] = replacements[0];
1782     cWalk=cWalk+1;
1783
1784     /* Insert */
1785     for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1786     {
1787         int j;
1788         for (j = *pcChars; j > cWalk; j--)
1789             pwOutChars[j] = pwOutChars[j-1];
1790         *pcChars= *pcChars+1;
1791         pwOutChars[cWalk] = replacements[i];
1792         cWalk = cWalk+1;
1793     }
1794 }
1795
1796 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1797 {
1798     int i;
1799     int cWalk;
1800
1801     for (cWalk = 0; cWalk < *pcChars; cWalk++)
1802     {
1803         for (i = 0; vowels[i].base != 0x0; i++)
1804         {
1805             if (pwOutChars[cWalk] == vowels[i].base)
1806             {
1807                 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1808                 break;
1809             }
1810         }
1811     }
1812 }
1813
1814 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1815 {
1816     int i;
1817     int cWalk;
1818
1819     for (cWalk = 0; cWalk < *pcChars; cWalk++)
1820     {
1821         for (i = 0; consonants[i].output!= 0x0; i++)
1822         {
1823             int j;
1824             for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1825                 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1826                     break;
1827
1828             if (consonants[i].parts[j]==0x0) /* matched all */
1829             {
1830                 int k;
1831                 j--;
1832                 pwOutChars[cWalk] = consonants[i].output;
1833                 for(k = cWalk+1; k < *pcChars - j; k++)
1834                     pwOutChars[k] = pwOutChars[k+j];
1835                 *pcChars = *pcChars - j;
1836                 break;
1837             }
1838         }
1839         cWalk++;
1840     }
1841 }
1842
1843 static void Reorder_Ra_follows_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1844 {
1845     if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1846     {
1847         int j;
1848         WORD Ra = pwChar[start];
1849         WORD H = pwChar[start+1];
1850
1851         TRACE("Doing reorder of Ra to %i\n",main);
1852         for (j = start; j < main-1; j++)
1853             pwChar[j] = pwChar[j+2];
1854         pwChar[main-1] = Ra;
1855         pwChar[main] = H;
1856     }
1857 }
1858
1859 static void Reorder_Ra_follows_matra_post(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1860 {
1861     if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1862     {
1863         int j,loc;
1864         WORD Ra = pwChar[start];
1865         WORD H = pwChar[start+1];
1866         for (loc = main; loc > end; loc++)
1867             if (lexical(pwChar[loc]) == lex_Matra_post)
1868                 break;
1869         if (loc == end) loc = main;
1870
1871         TRACE("Doing reorder of Ra to %i\n",loc);
1872         for (j = start; j < loc-1; j++)
1873             pwChar[j] = pwChar[j+2];
1874         pwChar[loc-1] = Ra;
1875         pwChar[loc] = H;
1876     }
1877 }
1878
1879 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1880 {
1881     if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1882     {
1883         int j;
1884         WORD Ra = pwChar[start];
1885         WORD H = pwChar[start+1];
1886
1887         TRACE("Doing reorder of Ra to %i\n",end-1);
1888         for (j = start; j < end-1; j++)
1889             pwChar[j] = pwChar[j+2];
1890         pwChar[end-1] = Ra;
1891         pwChar[end] = H;
1892     }
1893 }
1894
1895 static void Reorder_Matra_precede_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1896 {
1897     int i;
1898
1899     /* reorder Matras */
1900     if (end > main)
1901     {
1902         for (i = 1; i <= end-main; i++)
1903         {
1904             if (lexical(pwChar[main+i]) == lex_Matra_pre)
1905             {
1906                 int j;
1907                 WCHAR c = pwChar[main+i];
1908                 TRACE("Doing reorder of %x %x\n",c,pwChar[main]);
1909                 for (j = main+i; j > main; j--)
1910                     pwChar[j] = pwChar[j-1];
1911                 pwChar[main] = c;
1912             }
1913         }
1914     }
1915 }
1916
1917 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1918 {
1919     int i;
1920
1921     /* reorder Matras */
1922     if (end > main)
1923     {
1924         for (i = 1; i <= end-main; i++)
1925         {
1926             if (lexical(pwChar[main+i]) == lex_Matra_pre)
1927             {
1928                 int j;
1929                 WCHAR c = pwChar[main+i];
1930                 TRACE("Doing reorder of %x to %i\n",c,start);
1931                 for (j = main+i; j > start; j--)
1932                     pwChar[j] = pwChar[j-1];
1933                 pwChar[start] = c;
1934             }
1935         }
1936     }
1937 }
1938
1939 static void Reorder_Like_Sinhala(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1940 {
1941     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1942     if (start == main && main == end)  return;
1943
1944     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1945     if (lexical(pwChar[main]) == lex_Vowel) return;
1946
1947     Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1948     Reorder_Matra_precede_base(pwChar, start, main, end, lexical);
1949 }
1950
1951 static void Reorder_Like_Devanagari(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1952 {
1953     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1954     if (start == main && main == end)  return;
1955
1956     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1957     if (lexical(pwChar[main]) == lex_Vowel) return;
1958
1959     Reorder_Ra_follows_matra_post(pwChar, start, main, end, lexical);
1960     Reorder_Matra_precede_syllable(pwChar, start, main, end, lexical);
1961 }
1962
1963 static void Reorder_Like_Bengali(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1964 {
1965     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1966     if (start == main && main == end)  return;
1967
1968     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1969     if (lexical(pwChar[main]) == lex_Vowel) return;
1970
1971     Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1972     Reorder_Matra_precede_syllable(pwChar, start, main, end, lexical);
1973 }
1974
1975 static void Reorder_Like_Kannada(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1976 {
1977     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1978     if (start == main && main == end)  return;
1979
1980     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1981     if (lexical(pwChar[main]) == lex_Vowel) return;
1982
1983     Reorder_Ra_follows_syllable(pwChar, start, main, end, lexical);
1984     Reorder_Matra_precede_syllable(pwChar, start, main, end, lexical);
1985 }
1986
1987 static void Reorder_Like_Malayalam(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1988 {
1989     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1990     if (start == main && main == end)  return;
1991
1992     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1993     if (lexical(pwChar[main]) == lex_Vowel) return;
1994
1995     Reorder_Ra_follows_matra_post(pwChar, start, main, end, lexical);
1996     Reorder_Matra_precede_base(pwChar, start, main, end, lexical);
1997 }
1998
1999 static int sinhala_lex(WCHAR c)
2000 {
2001     switch (c)
2002     {
2003         case 0x0DCA: return lex_Halant;
2004         case 0x0DCF:
2005         case 0x0DDF:
2006         case 0x0DD8: return lex_Matra_post;
2007         case 0x0DD9:
2008         case 0x0DDB: return lex_Matra_pre;
2009         case 0x0DDA:
2010         case 0x0DDC: return lex_Composed_Vowel;
2011         case 0x200D: return lex_ZWJ;
2012         case 0x200C: return lex_ZWNJ;
2013         case 0x00A0: return lex_NBSP;
2014         default:
2015             if (c>=0x0D82 && c <=0x0D83) return lex_Modifier;
2016             else if (c>=0x0D85 && c <=0x0D96) return lex_Vowel;
2017             else if (c>=0x0D96 && c <=0x0DC6) return lex_Consonant;
2018             else if (c>=0x0DD0 && c <=0x0DD1) return lex_Matra_post;
2019             else if (c>=0x0DD2 && c <=0x0DD3) return lex_Matra_above;
2020             else if (c>=0x0DD4 && c <=0x0DD6) return lex_Matra_below;
2021             else if (c>=0x0DDD && c <=0x0DDE) return lex_Composed_Vowel;
2022             else if (c>=0x0DF2 && c <=0x0DF3) return lex_Matra_post;
2023             else return lex_Generic;
2024     }
2025 }
2026
2027 static const VowelComponents Sinhala_vowels[] = {
2028             {0x0DDA, {0x0DD9,0x0DCA,0x0}},
2029             {0x0DDC, {0x0DD9,0x0DCF,0x0}},
2030             {0x0DDD, {0x0DD9,0x0DCF,0x0DCA}},
2031             {0x0DDE, {0x0DD9,0x0DDF,0x0}},
2032             {0x0000, {0x0000,0x0000,0x0}}};
2033
2034 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2035 {
2036     int cCount = cChars;
2037     WCHAR *input;
2038
2039     if (*pcGlyphs != cChars)
2040     {
2041         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2042         return;
2043     }
2044
2045     input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2046
2047     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2048
2049     /* Step 1:  Decompose multi part vowels */
2050     DecomposeVowels(hdc, input,  &cCount, Sinhala_vowels);
2051
2052     TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2053
2054     /* Step 2:  Reorder within Syllables */
2055     Indic_ReorderCharacters( input, cCount, sinhala_lex, Reorder_Like_Sinhala);
2056     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2057
2058     /* Step 3:  Get glyphs */
2059     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2060     *pcGlyphs = cCount;
2061
2062     HeapFree(GetProcessHeap(),0,input);
2063 }
2064
2065 static int devanagari_lex(WCHAR c)
2066 {
2067     switch (c)
2068     {
2069         case 0x0951:
2070         case 0x0952:
2071         case 0x0903: return lex_Modifier;
2072         case 0x0930: return lex_Ra;
2073         case 0x093C: return lex_Nukta;
2074         case 0x0940:
2075         case 0x093E: return lex_Matra_post;
2076         case 0x093F: return lex_Matra_pre;
2077         case 0x094D: return lex_Halant;
2078         case 0x0972: return lex_Vowel;
2079         case 0x200C: return lex_ZWNJ;
2080         case 0x200D: return lex_ZWJ;
2081         default:
2082             if (c>=0x0901 && c<=0x0902) return lex_Matra_above;
2083             else if (c>=0x0904 && c<=0x0914) return lex_Vowel;
2084             else if (c>=0x0915 && c<=0x0939) return lex_Consonant;
2085             else if (c>=0x0941 && c<=0x0944) return lex_Matra_below;
2086             else if (c>=0x0945 && c<=0x0948) return lex_Matra_above;
2087             else if (c>=0x0949 && c<=0x094C) return lex_Matra_post;
2088             else if (c>=0x0953 && c<=0x0954) return lex_Modifier;
2089             else if (c>=0x0958 && c<=0x095F) return lex_Consonant;
2090             else if (c>=0x0960 && c<=0x0961) return lex_Vowel;
2091             else if (c>=0x0962 && c<=0x0963) return lex_Matra_below;
2092             else if (c>=0x097B && c<=0x097C) return lex_Consonant;
2093             else if (c>=0x097E && c<=0x097F) return lex_Consonant;
2094             else return lex_Generic;
2095     }
2096 }
2097
2098 static const ConsonantComponents Devanagari_consonants[] ={
2099     {{0x0928, 0x093C, 0x00000}, 0x0929},
2100     {{0x0930, 0x093C, 0x00000}, 0x0931},
2101     {{0x0933, 0x093C, 0x00000}, 0x0934},
2102     {{0x0915, 0x093C, 0x00000}, 0x0958},
2103     {{0x0916, 0x093C, 0x00000}, 0x0959},
2104     {{0x0917, 0x093C, 0x00000}, 0x095A},
2105     {{0x091C, 0x093C, 0x00000}, 0x095B},
2106     {{0x0921, 0x093C, 0x00000}, 0x095C},
2107     {{0x0922, 0x093C, 0x00000}, 0x095D},
2108     {{0x092B, 0x093C, 0x00000}, 0x095E},
2109     {{0x092F, 0x093C, 0x00000}, 0x095F}};
2110
2111 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2112 {
2113     int cCount = cChars;
2114     WCHAR *input;
2115
2116     if (*pcGlyphs != cChars)
2117     {
2118         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2119         return;
2120     }
2121
2122     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2123     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2124
2125     /* Step 1: Compose Consonant and Nukta */
2126     ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
2127     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2128
2129     /* Step 2: Reorder within Syllables */
2130     Indic_ReorderCharacters( input, cCount, devanagari_lex, Reorder_Like_Devanagari);
2131     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2132     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2133     *pcGlyphs = cCount;
2134
2135     HeapFree(GetProcessHeap(),0,input);
2136 }
2137
2138 static int bengali_lex(WCHAR c)
2139 {
2140     switch (c)
2141     {
2142         case 0x0981: return lex_Modifier;
2143         case 0x09AC:
2144         case 0x09AF:
2145         case 0x09CE: return lex_Consonant;
2146         case 0x09B0: return lex_Ra;
2147         case 0x09BC: return lex_Nukta;
2148         case 0x09BF: return lex_Matra_pre;
2149         case 0x09D7:
2150         case 0x09BE:
2151         case 0x09C0: return lex_Matra_post;
2152         case 0x09CD: return lex_Halant;
2153         case 0x200C: return lex_ZWNJ;
2154         case 0x200D: return lex_ZWJ;
2155         default:
2156             if (c>=0x0982 && c<=0x0983) return lex_Matra_post;
2157             else if (c>=0x0985 && c<=0x0994) return lex_Vowel;
2158             else if (c>=0x0995 && c<=0x09B9) return lex_Consonant;
2159             else if (c>=0x09C1 && c<=0x09C4) return lex_Matra_below;
2160             else if (c>=0x09C7 && c<=0x09C8) return lex_Matra_pre;
2161             else if (c>=0x09DC && c<=0x09DF) return lex_Consonant;
2162             else if (c>=0x09E0 && c<=0x09E1) return lex_Vowel;
2163             else if (c>=0x09E2 && c<=0x09E3) return lex_Matra_below;
2164             else if (c>=0x09F0 && c<=0x09F1) return lex_Consonant;
2165             else return lex_Generic;
2166     }
2167 }
2168
2169 static const VowelComponents Bengali_vowels[] = {
2170             {0x09CB, {0x09C7,0x09BE,0x0000}},
2171             {0x09CC, {0x09C7,0x09D7,0x0000}},
2172             {0x0000, {0x0000,0x0000,0x0000}}};
2173
2174 static const ConsonantComponents Bengali_consonants[] = {
2175             {{0x09A4,0x09CD,0x200D}, 0x09CE},
2176             {{0x09A1,0x09BC,0x0000}, 0x09DC},
2177             {{0x09A2,0x09BC,0x0000}, 0x09DD},
2178             {{0x09AF,0x09BC,0x0000}, 0x09DF},
2179             {{0x0000,0x0000,0x0000}, 0x0000}};
2180
2181 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2182 {
2183     int cCount = cChars;
2184     WCHAR *input;
2185
2186     if (*pcGlyphs != cChars)
2187     {
2188         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2189         return;
2190     }
2191
2192     input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2193     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2194
2195     /* Step 1: Decompose Vowels and Compose Consonents */
2196     DecomposeVowels(hdc, input,  &cCount, Bengali_vowels);
2197     ComposeConsonants(hdc, input, &cCount, Bengali_consonants);
2198     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2199
2200     /* Step 2: Reorder within Syllables */
2201     Indic_ReorderCharacters( input, cCount, bengali_lex, Reorder_Like_Bengali);
2202     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2203     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2204     *pcGlyphs = cCount;
2205
2206     HeapFree(GetProcessHeap(),0,input);
2207 }
2208
2209 static int gurmukhi_lex(WCHAR c)
2210 {
2211     switch (c)
2212     {
2213         case 0x0A2f: return lex_Consonant;
2214         case 0x0A30:
2215         case 0x0A35:
2216         case 0x0A39: return lex_Ra;
2217         case 0x0A3C: return lex_Nukta;
2218         case 0x0A3F: return lex_Matra_pre;
2219         case 0x0A03:
2220         case 0x0A3E:
2221         case 0x0A40: return lex_Matra_post;
2222         case 0x0A4D: return lex_Halant;
2223         case 0x0A70:
2224         case 0x0A71: return lex_Modifier;
2225         case 0x200C: return lex_ZWNJ;
2226         case 0x200D: return lex_ZWJ;
2227         default:
2228             if (c>=0x0A01 && c<=0x0A02) return lex_Modifier;
2229             else if (c>=0x0A05 && c<=0x0A14) return lex_Vowel;
2230             else if (c>=0x0A15 && c<=0x0A38) return lex_Consonant;
2231             else if (c>=0x0A41 && c<=0x0A42) return lex_Matra_below;
2232             else if (c>=0x0A47 && c<=0x0A4C) return lex_Matra_above;
2233             else if (c>=0x0A59 && c<=0x0A5E) return lex_Consonant;
2234             else return lex_Generic;
2235     }
2236 }
2237
2238 static const ConsonantComponents Gurmukhi_consonants[] = {
2239             {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2240             {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2241             {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2242             {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2243             {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2244             {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2245             {{0x0000,0x0000,0x0000}, 0x0000}};
2246
2247 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2248 {
2249     int cCount = cChars;
2250     WCHAR *input;
2251
2252     if (*pcGlyphs != cChars)
2253     {
2254         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2255         return;
2256     }
2257
2258     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2259     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2260
2261     /* Step 1: Compose Consonents */
2262     ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants);
2263     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2264
2265     /* Step 2: Reorder within Syllables */
2266     Indic_ReorderCharacters( input, cCount, gurmukhi_lex, Reorder_Like_Bengali);
2267     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2268     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2269     *pcGlyphs = cCount;
2270
2271     HeapFree(GetProcessHeap(),0,input);
2272 }
2273
2274 static int gujarati_lex(WCHAR c)
2275 {
2276     switch (c)
2277     {
2278         case 0x0A83: return lex_Modifier;
2279         case 0x0AB0: return lex_Ra;
2280         case 0x0ABC: return lex_Nukta;
2281         case 0x0ABF: return lex_Matra_pre;
2282         case 0x0ABE:
2283         case 0x0AC0: return lex_Matra_post;
2284         case 0x0ACD: return lex_Halant;
2285         case 0x200C: return lex_ZWNJ;
2286         case 0x200D: return lex_ZWJ;
2287         default:
2288             if (c>=0x0A81 && c<=0x0A82) return lex_Modifier;
2289             else if (c>=0x0A85 && c<=0x0A94) return lex_Vowel;
2290             else if (c>=0x0A95 && c<=0x0AB9) return lex_Consonant;
2291             else if (c>=0x0AC1 && c<=0x0AC4) return lex_Matra_below;
2292             else if (c>=0x0AC5 && c<=0x0AC8) return lex_Matra_above;
2293             else if (c>=0x0AC9 && c<=0x0ACC) return lex_Matra_post;
2294             else if (c>=0x0AE0 && c<=0x0AE1) return lex_Vowel;
2295             else if (c>=0x0AE2 && c<=0x0AE3) return lex_Matra_below;
2296             else return lex_Generic;
2297     }
2298 }
2299
2300 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2301 {
2302     int cCount = cChars;
2303     WCHAR *input;
2304
2305     if (*pcGlyphs != cChars)
2306     {
2307         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2308         return;
2309     }
2310
2311     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2312     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2313
2314     /* Step 1: Reorder within Syllables */
2315     Indic_ReorderCharacters( input, cCount, gujarati_lex, Reorder_Like_Devanagari);
2316     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2317     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2318     *pcGlyphs = cCount;
2319
2320     HeapFree(GetProcessHeap(),0,input);
2321 }
2322
2323 static int oriya_lex(WCHAR c)
2324 {
2325     switch (c)
2326     {
2327         case 0x0B24:
2328         case 0x0B28:
2329         case 0x0B2F:
2330         case 0x0B5F:
2331         case 0x0B71:
2332         case 0x0B33: return lex_Consonant;
2333         case 0x0B30: return lex_Ra;
2334         case 0x0B3C: return lex_Nukta;
2335         case 0x0B3F:
2336         case 0x0B56: return lex_Matra_above;
2337         case 0x0B3E:
2338         case 0x0B40: return lex_Matra_post;
2339         case 0x0B47:
2340         case 0x0B57: return lex_Matra_pre;
2341         case 0x0B4D: return lex_Halant;
2342         case 0x200C: return lex_ZWNJ;
2343         case 0x200D: return lex_ZWJ;
2344         default:
2345             if (c>=0x0B01 && c<=0x0B03) return lex_Modifier;
2346             else if (c>=0x0B05 && c<=0x0B14) return lex_Vowel;
2347             else if (c>=0x0B15 && c<=0x0B39) return lex_Consonant;
2348             else if (c>=0x0B2C && c<=0x0B2E) return lex_Consonant;
2349             else if (c>=0x0B32 && c<=0x0B33) return lex_Consonant;
2350             else if (c>=0x0B41 && c<=0x0B44) return lex_Matra_below;
2351             else if (c>=0x0B48 && c<=0x0B4C) return lex_Composed_Vowel;
2352             else if (c>=0x0B5C && c<=0x0B5D) return lex_Consonant;
2353             else if (c>=0x0B60 && c<=0x0B61) return lex_Vowel;
2354             else if (c>=0x0B62 && c<=0x0B63) return lex_Matra_below;
2355             else return lex_Generic;
2356     }
2357 }
2358
2359 static const VowelComponents Oriya_vowels[] = {
2360             {0x0B48, {0x0B47,0x0B56,0x0000}},
2361             {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2362             {0x0B4C, {0x0B47,0x0B57,0x0000}},
2363             {0x0000, {0x0000,0x0000,0x0000}}};
2364
2365 static const ConsonantComponents Oriya_consonants[] = {
2366             {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2367             {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2368             {{0x0000,0x0000,0x0000}, 0x0000}};
2369
2370 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2371 {
2372     int cCount = cChars;
2373     WCHAR *input;
2374
2375     if (*pcGlyphs != cChars)
2376     {
2377         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2378         return;
2379     }
2380
2381     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2382     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2383
2384     /* Step 1: Decompose Vowels and Compose Consonents */
2385     DecomposeVowels(hdc, input,  &cCount, Oriya_vowels);
2386     ComposeConsonants(hdc, input, &cCount, Oriya_consonants);
2387     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2388
2389     /* Step 2: Reorder within Syllables */
2390     Indic_ReorderCharacters( input, cCount, oriya_lex, Reorder_Like_Bengali);
2391     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2392     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2393     *pcGlyphs = cCount;
2394
2395     HeapFree(GetProcessHeap(),0,input);
2396 }
2397
2398 static int tamil_lex(WCHAR c)
2399 {
2400     switch (c)
2401     {
2402         case 0x0BC0: return lex_Matra_above;
2403         case 0x0BCD: return lex_Halant;
2404         case 0x0BD7: return lex_Matra_post;
2405         case 0x200C: return lex_ZWNJ;
2406         case 0x200D: return lex_ZWJ;
2407         default:
2408             if (c>=0x0B95 && c<=0x0BB9) return lex_Consonant;
2409             else if (c>=0x0BBE && c<=0x0BBF) return lex_Matra_post;
2410             else if (c>=0x0BC1 && c<=0x0BC2) return lex_Matra_below;
2411             else if (c>=0x0BC6 && c<=0x0BC8) return lex_Matra_pre;
2412             else return lex_Generic;
2413     }
2414 }
2415
2416 static const VowelComponents Tamil_vowels[] = {
2417             {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2418             {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2419             {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2420             {0x0000, {0x0000,0x0000,0x0000}}};
2421
2422 static const ConsonantComponents Tamil_consonants[] = {
2423             {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2424             {{0x0000,0x0000,0x0000}, 0x0000}};
2425
2426 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2427 {
2428     int cCount = cChars;
2429     WCHAR *input;
2430
2431     if (*pcGlyphs != cChars)
2432     {
2433         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2434         return;
2435     }
2436
2437     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2438     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2439
2440     /* Step 1: Decompose Vowels and Compose Consonents */
2441     DecomposeVowels(hdc, input,  &cCount, Tamil_vowels);
2442     ComposeConsonants(hdc, input, &cCount, Tamil_consonants);
2443     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2444
2445     /* Step 2: Reorder within Syllables */
2446     Indic_ReorderCharacters( input, cCount, tamil_lex, Reorder_Like_Sinhala);
2447     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2448     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2449     *pcGlyphs = cCount;
2450
2451     HeapFree(GetProcessHeap(),0,input);
2452 }
2453
2454 static int telugu_lex(WCHAR c)
2455 {
2456     switch (c)
2457     {
2458         case 0x0C4D: return lex_Halant;
2459         case 0x0C55: return lex_Matra_above;
2460         case 0x0C56: return lex_Matra_below;
2461         case 0x200C: return lex_ZWNJ;
2462         case 0x200D: return lex_ZWJ;
2463         default:
2464             if (c>=0x0C01 && c<=0x0C03) return lex_Matra_post;
2465             else if (c>=0x0C05 && c<=0x0C14) return lex_Vowel;
2466             else if (c>=0x0C15 && c<=0x0C39) return lex_Consonant;
2467             else if (c>=0x0C3E && c<=0x0C40) return lex_Matra_above;
2468             else if (c>=0x0C41 && c<=0x0C44) return lex_Matra_post;
2469             else if (c>=0x0C46 && c<=0x0C47) return lex_Matra_above;
2470             else if (c>=0x0C4A && c<=0x0C4C) return lex_Matra_above;
2471             else if (c>=0x0C58 && c<=0x0C59) return lex_Consonant;
2472             else if (c>=0x0C60 && c<=0x0C61) return lex_Vowel;
2473             else if (c>=0x0C62 && c<=0x0C63) return lex_Matra_below;
2474             else return lex_Generic;
2475     }
2476 }
2477
2478 static const VowelComponents Telugu_vowels[] = {
2479             {0x0C48, {0x0C46,0x0C56,0x0000}},
2480             {0x0000, {0x0000,0x0000,0x0000}}};
2481
2482 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2483 {
2484     int cCount = cChars;
2485     WCHAR *input;
2486
2487     if (*pcGlyphs != cChars)
2488     {
2489         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2490         return;
2491     }
2492
2493     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2494     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2495
2496     /* Step 1: Decompose Vowels */
2497     DecomposeVowels(hdc, input,  &cCount, Telugu_vowels);
2498     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2499
2500     /* Step 2: Reorder within Syllables */
2501     Indic_ReorderCharacters( input, cCount, telugu_lex, Reorder_Like_Bengali);
2502     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2503     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2504     *pcGlyphs = cCount;
2505
2506     HeapFree(GetProcessHeap(),0,input);
2507 }
2508
2509 static int kannada_lex(WCHAR c)
2510 {
2511     switch (c)
2512     {
2513         case 0x0CB0: return lex_Ra;
2514         case 0x0CBC: return lex_Nukta;
2515         case 0x0CBE: return lex_Matra_post;
2516         case 0x0CBF: return lex_Matra_above;
2517         case 0x0CC6: return lex_Matra_above;
2518         case 0x0CCC: return lex_Matra_above;
2519         case 0x0CCD: return lex_Halant;
2520         case 0x0CCE: return lex_Consonant;
2521         case 0x200C: return lex_ZWNJ;
2522         case 0x200D: return lex_ZWJ;
2523         default:
2524             if (c>=0x0C82 && c<=0x0C83) return lex_Modifier;
2525             else if (c>=0x0C85 && c<=0x0C94) return lex_Vowel;
2526             else if (c>=0x0C95 && c<=0x0CB9) return lex_Consonant;
2527             else if (c>=0x0CC1 && c<=0x0CC4) return lex_Matra_post;
2528             else if (c>=0x0CD5 && c<=0x0CD6) return lex_Modifier;
2529             else if (c>=0x0CE0 && c<=0x0CE1) return lex_Vowel;
2530             else if (c>=0x0CE2 && c<=0x0CE3) return lex_Matra_below;
2531             else return lex_Generic;
2532     }
2533 }
2534
2535 static const VowelComponents Kannada_vowels[] = {
2536             {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2537             {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2538             {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2539             {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2540             {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2541             {0x0000, {0x0000,0x0000,0x0000}}};
2542
2543 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2544 {
2545     int cCount = cChars;
2546     WCHAR *input;
2547
2548     if (*pcGlyphs != cChars)
2549     {
2550         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2551         return;
2552     }
2553
2554     input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2555     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2556
2557     /* Step 1: Decompose Vowels */
2558     DecomposeVowels(hdc, input,  &cCount, Kannada_vowels);
2559     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2560
2561     /* Step 2: Reorder within Syllables */
2562     Indic_ReorderCharacters( input, cCount, kannada_lex, Reorder_Like_Kannada);
2563     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2564     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2565     *pcGlyphs = cCount;
2566
2567     HeapFree(GetProcessHeap(),0,input);
2568 }
2569
2570 static int malayalam_lex(WCHAR c)
2571 {
2572     switch (c)
2573     {
2574         case 0x0D35: return lex_Consonant;
2575         case 0x0D4D: return lex_Halant;
2576         case 0x0D57: return lex_Matra_post;
2577         case 0x200C: return lex_ZWNJ;
2578         case 0x200D: return lex_ZWJ;
2579         default:
2580             if (c>=0x0D02 && c<=0x0D03) return lex_Modifier;
2581             else if (c>=0x0D05 && c<=0x0D14) return lex_Vowel;
2582             else if (c>=0x0D15 && c<=0x0D39) return lex_Consonant;
2583             else if (c>=0x0D3E && c<=0x0D44) return lex_Matra_post;
2584             else if (c>=0x0D46 && c<=0x0D48) return lex_Matra_pre;
2585             else if (c>=0x0D60 && c<=0x0D61) return lex_Vowel;
2586             else if (c>=0x0D62 && c<=0x0D63) return lex_Matra_below;
2587             else return lex_Generic;
2588     }
2589 }
2590
2591 static const VowelComponents Malayalam_vowels[] = {
2592             {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2593             {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2594             {0x0D4C, {0x0D46,0x0D57,0x0000}},
2595             {0x0000, {0x0000,0x0000,0x0000}}};
2596
2597 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2598 {
2599     int cCount = cChars;
2600     WCHAR *input;
2601
2602     if (*pcGlyphs != cChars)
2603     {
2604         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2605         return;
2606     }
2607
2608     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2609     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2610
2611     /* Step 1: Decompose Vowels */
2612     DecomposeVowels(hdc, input,  &cCount, Malayalam_vowels);
2613     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2614
2615     /* Step 2: Reorder within Syllables */
2616     Indic_ReorderCharacters( input, cCount, malayalam_lex, Reorder_Like_Malayalam);
2617     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2618     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2619     *pcGlyphs = cCount;
2620
2621     HeapFree(GetProcessHeap(),0,input);
2622 }
2623
2624 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
2625 {
2626     int i,k;
2627
2628     for (i = 0; i < cGlyphs; i++)
2629     {
2630         int char_index[20];
2631         int char_count = 0;
2632
2633         for (k = 0; k < cChars; k++)
2634         {
2635             if (pwLogClust[k] == i)
2636             {
2637                 char_index[char_count] = k;
2638                 char_count++;
2639             }
2640         }
2641
2642         if (char_count == 0)
2643         {
2644             FIXME("No chars in this glyph?  Must be an error\n");
2645             continue;
2646         }
2647
2648         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2649         {
2650             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2651             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2652         }
2653         else
2654             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2655     }
2656
2657     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2658     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2659 }
2660
2661 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 )
2662 {
2663     int i,k;
2664     int initGlyph, finaGlyph;
2665     INT dirR, dirL;
2666     BYTE *spaces;
2667
2668     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2669     memset(spaces,0,cGlyphs);
2670
2671     if (!psa->fLogicalOrder && psa->fRTL)
2672     {
2673         initGlyph = cGlyphs-1;
2674         finaGlyph = 0;
2675         dirR = 1;
2676         dirL = -1;
2677     }
2678     else
2679     {
2680         initGlyph = 0;
2681         finaGlyph = cGlyphs-1;
2682         dirR = -1;
2683         dirL = 1;
2684     }
2685
2686     for (i = 0; i < cGlyphs; i++)
2687     {
2688         for (k = 0; k < cChars; k++)
2689             if (pwLogClust[k] == i)
2690             {
2691                 if (pwcChars[k] == 0x0020)
2692                     spaces[i] = 1;
2693             }
2694     }
2695
2696     for (i = 0; i < cGlyphs; i++)
2697     {
2698         int char_index[20];
2699         int char_count = 0;
2700         BOOL isInit, isFinal;
2701
2702         for (k = 0; k < cChars; k++)
2703         {
2704             if (pwLogClust[k] == i)
2705             {
2706                 char_index[char_count] = k;
2707                 char_count++;
2708             }
2709         }
2710
2711         isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2712         isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2713
2714         if (char_count == 0)
2715         {
2716             FIXME("No chars in this glyph?  Must be an error\n");
2717             continue;
2718         }
2719
2720         if (char_count == 1)
2721         {
2722             if (pwcChars[char_index[0]] == 0x0020)  /* space */
2723             {
2724                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2725                 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2726             }
2727             else if (pwcChars[char_index[0]] == 0x0640)  /* kashida */
2728                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2729             else if (pwcChars[char_index[0]] == 0x0633)  /* SEEN */
2730             {
2731                 if (!isInit && !isFinal)
2732                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2733                 else if (isInit)
2734                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2735                 else
2736                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2737             }
2738             else if (!isInit)
2739             {
2740                 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2741                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2742                 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2743                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2744                 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2745                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2746                 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2747                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2748                 else
2749                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2750             }
2751             else if (!isInit && !isFinal)
2752                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2753             else
2754                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2755         }
2756         else if (char_count == 2)
2757         {
2758             if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) ||  (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2759                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2760             else if (!isInit)
2761                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2762             else
2763                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2764         }
2765         else if (!isInit && !isFinal)
2766             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2767         else
2768             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2769     }
2770
2771     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2772     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2773     HeapFree(GetProcessHeap(),0,spaces);
2774 }
2775
2776 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 )
2777 {
2778     int i,k;
2779     int finaGlyph;
2780     INT dirL;
2781     BYTE *spaces;
2782
2783     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2784     memset(spaces,0,cGlyphs);
2785
2786     if (!psa->fLogicalOrder && psa->fRTL)
2787     {
2788         finaGlyph = 0;
2789         dirL = -1;
2790     }
2791     else
2792     {
2793         finaGlyph = cGlyphs-1;
2794         dirL = 1;
2795     }
2796
2797     for (i = 0; i < cGlyphs; i++)
2798     {
2799         for (k = 0; k < cChars; k++)
2800             if (pwLogClust[k] == i)
2801             {
2802                 if (pwcChars[k] == 0x0020)
2803                     spaces[i] = 1;
2804             }
2805     }
2806
2807     for (i = 0; i < cGlyphs; i++)
2808     {
2809         int char_index[20];
2810         int char_count = 0;
2811
2812         for (k = 0; k < cChars; k++)
2813         {
2814             if (pwLogClust[k] == i)
2815             {
2816                 char_index[char_count] = k;
2817                 char_count++;
2818             }
2819         }
2820
2821         if (char_count == 0)
2822         {
2823             FIXME("No chars in this glyph?  Must be an error\n");
2824             continue;
2825         }
2826
2827         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2828         {
2829             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2830             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2831         }
2832         else if (i == finaGlyph)
2833             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2834         else
2835             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2836     }
2837
2838     HeapFree(GetProcessHeap(),0,spaces);
2839     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2840     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2841
2842     /* Do not allow justification between marks and their base */
2843     for (i = 0; i < cGlyphs; i++)
2844     {
2845         if (!pGlyphProp[i].sva.fClusterStart)
2846             pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2847     }
2848 }
2849
2850 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)
2851 {
2852     int i,k;
2853
2854     for (i = 0; i < cGlyphs; i++)
2855     {
2856         int char_index[20];
2857         int char_count = 0;
2858
2859         for (k = 0; k < cChars; k++)
2860         {
2861             if (pwLogClust[k] == i)
2862             {
2863                 char_index[char_count] = k;
2864                 char_count++;
2865             }
2866         }
2867
2868         if (char_count == 0)
2869         {
2870             FIXME("No chars in this glyph?  Must be an error\n");
2871             continue;
2872         }
2873
2874         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2875         {
2876             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2877             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2878         }
2879         else
2880             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2881     }
2882     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2883     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2884 }
2885
2886 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)
2887 {
2888     int i,k;
2889
2890     for (i = 0; i < cGlyphs; i++)
2891     {
2892         int char_index[20];
2893         int char_count = 0;
2894
2895         for (k = 0; k < cChars; k++)
2896         {
2897             if (pwLogClust[k] == i)
2898             {
2899                 char_index[char_count] = k;
2900                 char_count++;
2901             }
2902         }
2903
2904         if (char_count == 0)
2905         {
2906             FIXME("No chars in this glyph?  Must be an error\n");
2907             continue;
2908         }
2909
2910         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2911         {
2912             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2913             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2914         }
2915         else
2916             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2917     }
2918     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2919     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2920
2921     /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2922     for (i = 0; i < cGlyphs; i++)
2923     {
2924         if (!pGlyphProp[i].sva.fClusterStart)
2925         {
2926             pGlyphProp[i].sva.fDiacritic = 0;
2927             pGlyphProp[i].sva.fZeroWidth = 0;
2928         }
2929     }
2930 }
2931
2932 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)
2933 {
2934     int i,k;
2935
2936     for (i = 0; i < cGlyphs; i++)
2937     {
2938         int char_index[20];
2939         int char_count = 0;
2940
2941         for (k = 0; k < cChars; k++)
2942         {
2943             if (pwLogClust[k] == i)
2944             {
2945                 char_index[char_count] = k;
2946                 char_count++;
2947             }
2948         }
2949
2950         if (char_count == 0)
2951         {
2952             FIXME("No chars in this glyph?  Must be an error\n");
2953             continue;
2954         }
2955
2956         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2957         {
2958             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2959             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2960         }
2961         else
2962             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2963
2964         pGlyphProp[i].sva.fClusterStart = 0;
2965         for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
2966             switch (lexical(pwcChars[char_index[k]]))
2967             {
2968                 case lex_Matra_pre:
2969                 case lex_Matra_post:
2970                 case lex_Matra_above:
2971                 case lex_Matra_below:
2972                 case lex_Modifier:
2973                     break;
2974                 default:
2975                     pGlyphProp[i].sva.fClusterStart = 1;
2976                     break;
2977             }
2978     }
2979     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2980 }
2981
2982 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 )
2983 {
2984     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
2985 }
2986
2987 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 )
2988 {
2989     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
2990 }
2991
2992 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 )
2993 {
2994     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
2995 }
2996
2997 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 )
2998 {
2999     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3000 }
3001
3002 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 )
3003 {
3004     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3005 }
3006
3007 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 )
3008 {
3009     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3010 }
3011
3012 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 )
3013 {
3014     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3015 }
3016
3017 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 )
3018 {
3019     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3020 }
3021
3022 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 )
3023 {
3024     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3025 }
3026
3027 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)
3028 {
3029     if (ShapingData[psa->eScript].charGlyphPropProc)
3030         ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3031     else
3032         ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3033 }
3034
3035 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3036 {
3037     if (ShapingData[psa->eScript].contextProc)
3038         ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3039 }
3040
3041 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)
3042 {
3043     int i;
3044     INT dirL;
3045
3046     if (!rpRangeProperties)
3047         return;
3048
3049     if (!psc->GSUB_Table)
3050         psc->GSUB_Table = load_gsub_table(hdc);
3051
3052     if (!psc->GSUB_Table)
3053         return;
3054
3055     if (!psa->fLogicalOrder && psa->fRTL)
3056         dirL = -1;
3057     else
3058         dirL = 1;
3059
3060     for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3061     {
3062         if (rpRangeProperties->potfRecords[i].lParameter > 0)
3063         apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3064     }
3065 }
3066
3067 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3068 {
3069 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3070 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3071
3072     SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3073 }
3074
3075 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3076 {
3077     const GSUB_Feature *feature;
3078     int i;
3079
3080     if (!ShapingData[psa->eScript].requiredFeatures)
3081         return S_OK;
3082
3083     if (!psc->GSUB_Table)
3084         psc->GSUB_Table = load_gsub_table(hdc);
3085
3086     /* we need to have at least one of the required features */
3087     i = 0;
3088     while (ShapingData[psa->eScript].requiredFeatures[i])
3089     {
3090         feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3091         if (feature)
3092             return S_OK;
3093         i++;
3094     }
3095
3096     return USP_E_SCRIPT_NOT_IN_FONT;
3097 }