usp10: Store the GDEF table in the script cache.
[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;
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, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1285 {
1286     int i;
1287
1288     if (!psc->GDEF_Table)
1289         psc->GDEF_Table = load_gdef_table(hdc);
1290
1291     for (i = 0; i < cGlyphs; i++)
1292     {
1293         WORD class;
1294
1295         class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1296
1297         switch (class)
1298         {
1299             case 0:
1300             case BaseGlyph:
1301                 pGlyphProp[i].sva.fClusterStart = 1;
1302                 pGlyphProp[i].sva.fDiacritic = 0;
1303                 pGlyphProp[i].sva.fZeroWidth = 0;
1304                 break;
1305             case LigatureGlyph:
1306                 pGlyphProp[i].sva.fClusterStart = 1;
1307                 pGlyphProp[i].sva.fDiacritic = 0;
1308                 pGlyphProp[i].sva.fZeroWidth = 0;
1309                 break;
1310             case MarkGlyph:
1311                 pGlyphProp[i].sva.fClusterStart = 0;
1312                 pGlyphProp[i].sva.fDiacritic = 1;
1313                 pGlyphProp[i].sva.fZeroWidth = 1;
1314                 break;
1315             case ComponentGlyph:
1316                 pGlyphProp[i].sva.fClusterStart = 0;
1317                 pGlyphProp[i].sva.fDiacritic = 0;
1318                 pGlyphProp[i].sva.fZeroWidth = 0;
1319                 break;
1320             default:
1321                 ERR("Unknown glyph class %i\n",class);
1322                 pGlyphProp[i].sva.fClusterStart = 1;
1323                 pGlyphProp[i].sva.fDiacritic = 0;
1324                 pGlyphProp[i].sva.fZeroWidth = 0;
1325         }
1326     }
1327 }
1328
1329 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1330 {
1331     int i;
1332
1333     for (i = 0; i < cGlyphs; i++)
1334     {
1335         if (!pGlyphProp[i].sva.fClusterStart)
1336         {
1337             int j;
1338             for (j = 0; j < cChars; j++)
1339             {
1340                 if (pwLogClust[j] == i)
1341                 {
1342                     int k = j;
1343                     while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1344                         k-=1;
1345                     if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1346                         pwLogClust[j] = pwLogClust[k];
1347                 }
1348             }
1349         }
1350     }
1351 }
1352
1353 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1354 {
1355     if (changeCount == 0)
1356         return;
1357     else
1358     {
1359         int i;
1360         int target_glyph = nextIndex - 1;
1361         int target_index = -1;
1362         int replacing_glyph = -1;
1363         int changed = 0;
1364
1365         if (write_dir > 0)
1366             for (i = 0; i < chars; i++)
1367             {
1368                 if (pwLogClust[i] == target_glyph)
1369                 {
1370                     target_index = i;
1371                     break;
1372                 }
1373             }
1374         else
1375             for (i = chars - 1; i >= 0; i--)
1376             {
1377                 if (pwLogClust[i] == target_glyph)
1378                 {
1379                     target_index = i;
1380                     break;
1381                 }
1382             }
1383         if (target_index == -1)
1384         {
1385             ERR("Unable to find target glyph\n");
1386             return;
1387         }
1388
1389         if (changeCount < 0)
1390         {
1391             /* merge glyphs */
1392             for(i = target_index; i < chars && i >= 0; i+=write_dir)
1393             {
1394                 if (pwLogClust[i] == target_glyph)
1395                     continue;
1396                 if(pwLogClust[i] == replacing_glyph)
1397                     pwLogClust[i] = target_glyph;
1398                 else
1399                 {
1400                     changed--;
1401                     if (changed >= changeCount)
1402                     {
1403                         replacing_glyph = pwLogClust[i];
1404                         pwLogClust[i] = target_glyph;
1405                     }
1406                     else
1407                         break;
1408                 }
1409             }
1410         }
1411
1412         /* renumber trailing indexes*/
1413         for(i = target_index; i < chars && i >= 0; i+=write_dir)
1414         {
1415             if (pwLogClust[i] != target_glyph)
1416                 pwLogClust[i] += changeCount;
1417         }
1418     }
1419 }
1420
1421 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 )
1422 {
1423     int i;
1424
1425     if (psc->GSUB_Table)
1426     {
1427         const GSUB_Feature *feature;
1428
1429         feature = load_GSUB_feature(hdc, psa, psc, feat);
1430         if (!feature)
1431             return GSUB_E_NOFEATURE;
1432
1433         i = 0;
1434         TRACE("applying feature %s\n",debugstr_an(feat,4));
1435         while(i < *pcGlyphs)
1436         {
1437                 INT nextIndex;
1438                 INT prevCount = *pcGlyphs;
1439                 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1440                 if (nextIndex > GSUB_E_NOGLYPH)
1441                 {
1442                     UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1443                     i = nextIndex;
1444                 }
1445                 else
1446                     i++;
1447         }
1448         return *pcGlyphs;
1449     }
1450     return GSUB_E_NOFEATURE;
1451 }
1452
1453 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1454 {
1455     if (i + delta < 0)
1456         return 0;
1457     if ( i+ delta >= cchLen)
1458         return 0;
1459
1460     i += delta;
1461
1462     return chars[i];
1463 }
1464
1465 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1466 {
1467     if (i + delta < 0)
1468     {
1469         if (psa->fLinkBefore)
1470             return jtR;
1471         else
1472             return jtU;
1473     }
1474     if ( i+ delta >= cchLen)
1475     {
1476         if (psa->fLinkAfter)
1477             return jtL;
1478         else
1479             return jtU;
1480     }
1481
1482     i += delta;
1483
1484     if (context_type[i] == jtT)
1485         return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1486     else
1487         return context_type[i];
1488 }
1489
1490 static inline BOOL right_join_causing(CHAR joining_type)
1491 {
1492     return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1493 }
1494
1495 static inline BOOL left_join_causing(CHAR joining_type)
1496 {
1497     return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1498 }
1499
1500 static inline BOOL word_break_causing(WCHAR chr)
1501 {
1502     /* we are working within a string of characters already guareented to
1503        be within one script, Syriac, so we do not worry about any characers
1504        other than the space character outside of that range */
1505     return (chr == 0 || chr == 0x20 );
1506 }
1507
1508 /*
1509  * ContextualShape_Arabic
1510  */
1511 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1512 {
1513     CHAR *context_type;
1514     INT *context_shape;
1515     INT dirR, dirL;
1516     int i;
1517
1518     if (*pcGlyphs != cChars)
1519     {
1520         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1521         return;
1522     }
1523
1524     if (!psa->fLogicalOrder && psa->fRTL)
1525     {
1526         dirR = 1;
1527         dirL = -1;
1528     }
1529     else
1530     {
1531         dirR = -1;
1532         dirL = 1;
1533     }
1534
1535     if (!psc->GSUB_Table)
1536         psc->GSUB_Table = load_gsub_table(hdc);
1537
1538     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1539     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1540
1541     for (i = 0; i < cChars; i++)
1542         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1543
1544     for (i = 0; i < cChars; i++)
1545     {
1546         if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1547             context_shape[i] = Xr;
1548         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1549             context_shape[i] = Xl;
1550         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)))
1551             context_shape[i] = Xm;
1552         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1553             context_shape[i] = Xr;
1554         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1555             context_shape[i] = Xl;
1556         else
1557             context_shape[i] = Xn;
1558     }
1559
1560     /* Contextual Shaping */
1561     i = 0;
1562     while(i < *pcGlyphs)
1563     {
1564         BOOL shaped = FALSE;
1565
1566         if (psc->GSUB_Table)
1567         {
1568             INT nextIndex;
1569             INT prevCount = *pcGlyphs;
1570             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1571             if (nextIndex > GSUB_E_NOGLYPH)
1572             {
1573                 i = nextIndex;
1574                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1575             }
1576             shaped = (nextIndex > GSUB_E_NOGLYPH);
1577         }
1578
1579         if (!shaped)
1580         {
1581             WORD newGlyph = pwOutGlyphs[i];
1582             if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1583             {
1584                 /* fall back to presentation form B */
1585                 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1586                 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1587                     pwOutGlyphs[i] = newGlyph;
1588             }
1589             i++;
1590         }
1591     }
1592
1593     HeapFree(GetProcessHeap(),0,context_shape);
1594     HeapFree(GetProcessHeap(),0,context_type);
1595 }
1596
1597 /*
1598  * ContextualShape_Syriac
1599  */
1600
1601 #define ALAPH 0x710
1602 #define DALATH 0x715
1603 #define RISH 0x72A
1604
1605 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1606 {
1607     CHAR *context_type;
1608     INT *context_shape;
1609     INT dirR, dirL;
1610     int i;
1611
1612     if (*pcGlyphs != cChars)
1613     {
1614         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1615         return;
1616     }
1617
1618     if (!psa->fLogicalOrder && psa->fRTL)
1619     {
1620         dirR = 1;
1621         dirL = -1;
1622     }
1623     else
1624     {
1625         dirR = -1;
1626         dirL = 1;
1627     }
1628
1629     if (!psc->GSUB_Table)
1630         psc->GSUB_Table = load_gsub_table(hdc);
1631
1632     if (!psc->GSUB_Table)
1633         return;
1634
1635     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1636     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1637
1638     for (i = 0; i < cChars; i++)
1639         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1640
1641     for (i = 0; i < cChars; i++)
1642     {
1643         if (pwcChars[i] == ALAPH)
1644         {
1645             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1646
1647             if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1648             context_shape[i] = Afj;
1649             else if ( rchar != DALATH && rchar != RISH &&
1650 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1651 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1652             context_shape[i] = Afn;
1653             else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1654             context_shape[i] = Afx;
1655             else
1656             context_shape[i] = Xn;
1657         }
1658         else if (context_type[i] == jtR &&
1659 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1660             context_shape[i] = Xr;
1661         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1662             context_shape[i] = Xl;
1663         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)))
1664             context_shape[i] = Xm;
1665         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1666             context_shape[i] = Xr;
1667         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1668             context_shape[i] = Xl;
1669         else
1670             context_shape[i] = Xn;
1671     }
1672
1673     /* Contextual Shaping */
1674     i = 0;
1675     while(i < *pcGlyphs)
1676     {
1677         INT nextIndex;
1678         INT prevCount = *pcGlyphs;
1679         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1680         if (nextIndex > GSUB_E_NOGLYPH)
1681         {
1682             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1683             i = nextIndex;
1684         }
1685         else
1686             i++;
1687     }
1688
1689     HeapFree(GetProcessHeap(),0,context_shape);
1690     HeapFree(GetProcessHeap(),0,context_type);
1691 }
1692
1693 /*
1694  * ContextualShape_Phags_pa
1695  */
1696
1697 #define phags_pa_CANDRABINDU  0xA873
1698 #define phags_pa_START 0xA840
1699 #define phags_pa_END  0xA87F
1700
1701 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1702 {
1703     INT *context_shape;
1704     INT dirR, dirL;
1705     int i;
1706
1707     if (*pcGlyphs != cChars)
1708     {
1709         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1710         return;
1711     }
1712
1713     if (!psa->fLogicalOrder && psa->fRTL)
1714     {
1715         dirR = 1;
1716         dirL = -1;
1717     }
1718     else
1719     {
1720         dirR = -1;
1721         dirL = 1;
1722     }
1723
1724     if (!psc->GSUB_Table)
1725         psc->GSUB_Table = load_gsub_table(hdc);
1726
1727     if (!psc->GSUB_Table)
1728         return;
1729
1730     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1731
1732     for (i = 0; i < cChars; i++)
1733     {
1734         if (pwcChars[i] >= phags_pa_START && pwcChars[i] <=  phags_pa_END)
1735         {
1736             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1737             WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1738             BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <=  phags_pa_END);
1739             BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <=  phags_pa_END);
1740
1741             if (jrchar && jlchar)
1742                 context_shape[i] = Xm;
1743             else if (jrchar)
1744                 context_shape[i] = Xr;
1745             else if (jlchar)
1746                 context_shape[i] = Xl;
1747             else
1748                 context_shape[i] = Xn;
1749         }
1750         else
1751             context_shape[i] = -1;
1752     }
1753
1754     /* Contextual Shaping */
1755     i = 0;
1756     while(i < *pcGlyphs)
1757     {
1758         if (context_shape[i] >= 0)
1759         {
1760             INT nextIndex;
1761             INT prevCount = *pcGlyphs;
1762             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1763             if (nextIndex > GSUB_E_NOGLYPH)
1764             {
1765                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1766                 i = nextIndex;
1767             }
1768             else
1769                 i++;
1770         }
1771         else
1772             i++;
1773     }
1774
1775     HeapFree(GetProcessHeap(),0,context_shape);
1776 }
1777
1778 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1779 {
1780     int i;
1781
1782     /* Replace */
1783     pwOutChars[cWalk] = replacements[0];
1784     cWalk=cWalk+1;
1785
1786     /* Insert */
1787     for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1788     {
1789         int j;
1790         for (j = *pcChars; j > cWalk; j--)
1791             pwOutChars[j] = pwOutChars[j-1];
1792         *pcChars= *pcChars+1;
1793         pwOutChars[cWalk] = replacements[i];
1794         cWalk = cWalk+1;
1795     }
1796 }
1797
1798 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1799 {
1800     int i;
1801     int cWalk;
1802
1803     for (cWalk = 0; cWalk < *pcChars; cWalk++)
1804     {
1805         for (i = 0; vowels[i].base != 0x0; i++)
1806         {
1807             if (pwOutChars[cWalk] == vowels[i].base)
1808             {
1809                 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1810                 break;
1811             }
1812         }
1813     }
1814 }
1815
1816 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1817 {
1818     int i;
1819     int cWalk;
1820
1821     for (cWalk = 0; cWalk < *pcChars; cWalk++)
1822     {
1823         for (i = 0; consonants[i].output!= 0x0; i++)
1824         {
1825             int j;
1826             for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1827                 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1828                     break;
1829
1830             if (consonants[i].parts[j]==0x0) /* matched all */
1831             {
1832                 int k;
1833                 j--;
1834                 pwOutChars[cWalk] = consonants[i].output;
1835                 for(k = cWalk+1; k < *pcChars - j; k++)
1836                     pwOutChars[k] = pwOutChars[k+j];
1837                 *pcChars = *pcChars - j;
1838                 break;
1839             }
1840         }
1841         cWalk++;
1842     }
1843 }
1844
1845 static void Reorder_Ra_follows_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1846 {
1847     if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1848     {
1849         int j;
1850         WORD Ra = pwChar[start];
1851         WORD H = pwChar[start+1];
1852
1853         TRACE("Doing reorder of Ra to %i\n",main);
1854         for (j = start; j < main-1; j++)
1855             pwChar[j] = pwChar[j+2];
1856         pwChar[main-1] = Ra;
1857         pwChar[main] = H;
1858     }
1859 }
1860
1861 static void Reorder_Ra_follows_matra_post(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1862 {
1863     if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1864     {
1865         int j,loc;
1866         WORD Ra = pwChar[start];
1867         WORD H = pwChar[start+1];
1868         for (loc = main; loc > end; loc++)
1869             if (lexical(pwChar[loc]) == lex_Matra_post)
1870                 break;
1871         if (loc == end) loc = main;
1872
1873         TRACE("Doing reorder of Ra to %i\n",loc);
1874         for (j = start; j < loc-1; j++)
1875             pwChar[j] = pwChar[j+2];
1876         pwChar[loc-1] = Ra;
1877         pwChar[loc] = H;
1878     }
1879 }
1880
1881 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1882 {
1883     if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1884     {
1885         int j;
1886         WORD Ra = pwChar[start];
1887         WORD H = pwChar[start+1];
1888
1889         TRACE("Doing reorder of Ra to %i\n",end-1);
1890         for (j = start; j < end-1; j++)
1891             pwChar[j] = pwChar[j+2];
1892         pwChar[end-1] = Ra;
1893         pwChar[end] = H;
1894     }
1895 }
1896
1897 static void Reorder_Matra_precede_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1898 {
1899     int i;
1900
1901     /* reorder Matras */
1902     if (end > main)
1903     {
1904         for (i = 1; i <= end-main; i++)
1905         {
1906             if (lexical(pwChar[main+i]) == lex_Matra_pre)
1907             {
1908                 int j;
1909                 WCHAR c = pwChar[main+i];
1910                 TRACE("Doing reorder of %x %x\n",c,pwChar[main]);
1911                 for (j = main+i; j > main; j--)
1912                     pwChar[j] = pwChar[j-1];
1913                 pwChar[main] = c;
1914             }
1915         }
1916     }
1917 }
1918
1919 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1920 {
1921     int i;
1922
1923     /* reorder Matras */
1924     if (end > main)
1925     {
1926         for (i = 1; i <= end-main; i++)
1927         {
1928             if (lexical(pwChar[main+i]) == lex_Matra_pre)
1929             {
1930                 int j;
1931                 WCHAR c = pwChar[main+i];
1932                 TRACE("Doing reorder of %x to %i\n",c,start);
1933                 for (j = main+i; j > start; j--)
1934                     pwChar[j] = pwChar[j-1];
1935                 pwChar[start] = c;
1936             }
1937         }
1938     }
1939 }
1940
1941 static void Reorder_Like_Sinhala(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1942 {
1943     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1944     if (start == main && main == end)  return;
1945
1946     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1947     if (lexical(pwChar[main]) == lex_Vowel) return;
1948
1949     Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1950     Reorder_Matra_precede_base(pwChar, start, main, end, lexical);
1951 }
1952
1953 static void Reorder_Like_Devanagari(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1954 {
1955     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1956     if (start == main && main == end)  return;
1957
1958     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1959     if (lexical(pwChar[main]) == lex_Vowel) return;
1960
1961     Reorder_Ra_follows_matra_post(pwChar, start, main, end, lexical);
1962     Reorder_Matra_precede_syllable(pwChar, start, main, end, lexical);
1963 }
1964
1965 static void Reorder_Like_Bengali(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1966 {
1967     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1968     if (start == main && main == end)  return;
1969
1970     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1971     if (lexical(pwChar[main]) == lex_Vowel) return;
1972
1973     Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1974     Reorder_Matra_precede_syllable(pwChar, start, main, end, lexical);
1975 }
1976
1977 static void Reorder_Like_Kannada(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1978 {
1979     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1980     if (start == main && main == end)  return;
1981
1982     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1983     if (lexical(pwChar[main]) == lex_Vowel) return;
1984
1985     Reorder_Ra_follows_syllable(pwChar, start, main, end, lexical);
1986     Reorder_Matra_precede_syllable(pwChar, start, main, end, lexical);
1987 }
1988
1989 static void Reorder_Like_Malayalam(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1990 {
1991     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1992     if (start == main && main == end)  return;
1993
1994     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1995     if (lexical(pwChar[main]) == lex_Vowel) return;
1996
1997     Reorder_Ra_follows_matra_post(pwChar, start, main, end, lexical);
1998     Reorder_Matra_precede_base(pwChar, start, main, end, lexical);
1999 }
2000
2001 static int sinhala_lex(WCHAR c)
2002 {
2003     switch (c)
2004     {
2005         case 0x0DCA: return lex_Halant;
2006         case 0x0DCF:
2007         case 0x0DDF:
2008         case 0x0DD8: return lex_Matra_post;
2009         case 0x0DD9:
2010         case 0x0DDB: return lex_Matra_pre;
2011         case 0x0DDA:
2012         case 0x0DDC: return lex_Composed_Vowel;
2013         case 0x200D: return lex_ZWJ;
2014         case 0x200C: return lex_ZWNJ;
2015         case 0x00A0: return lex_NBSP;
2016         default:
2017             if (c>=0x0D82 && c <=0x0D83) return lex_Modifier;
2018             else if (c>=0x0D85 && c <=0x0D96) return lex_Vowel;
2019             else if (c>=0x0D96 && c <=0x0DC6) return lex_Consonant;
2020             else if (c>=0x0DD0 && c <=0x0DD1) return lex_Matra_post;
2021             else if (c>=0x0DD2 && c <=0x0DD3) return lex_Matra_above;
2022             else if (c>=0x0DD4 && c <=0x0DD6) return lex_Matra_below;
2023             else if (c>=0x0DDD && c <=0x0DDE) return lex_Composed_Vowel;
2024             else if (c>=0x0DF2 && c <=0x0DF3) return lex_Matra_post;
2025             else return lex_Generic;
2026     }
2027 }
2028
2029 static const VowelComponents Sinhala_vowels[] = {
2030             {0x0DDA, {0x0DD9,0x0DCA,0x0}},
2031             {0x0DDC, {0x0DD9,0x0DCF,0x0}},
2032             {0x0DDD, {0x0DD9,0x0DCF,0x0DCA}},
2033             {0x0DDE, {0x0DD9,0x0DDF,0x0}},
2034             {0x0000, {0x0000,0x0000,0x0}}};
2035
2036 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2037 {
2038     int cCount = cChars;
2039     WCHAR *input;
2040
2041     if (*pcGlyphs != cChars)
2042     {
2043         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2044         return;
2045     }
2046
2047     input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2048
2049     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2050
2051     /* Step 1:  Decompose multi part vowels */
2052     DecomposeVowels(hdc, input,  &cCount, Sinhala_vowels);
2053
2054     TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2055
2056     /* Step 2:  Reorder within Syllables */
2057     Indic_ReorderCharacters( input, cCount, sinhala_lex, Reorder_Like_Sinhala);
2058     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2059
2060     /* Step 3:  Get glyphs */
2061     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2062     *pcGlyphs = cCount;
2063
2064     HeapFree(GetProcessHeap(),0,input);
2065 }
2066
2067 static int devanagari_lex(WCHAR c)
2068 {
2069     switch (c)
2070     {
2071         case 0x0951:
2072         case 0x0952:
2073         case 0x0903: return lex_Modifier;
2074         case 0x0930: return lex_Ra;
2075         case 0x093C: return lex_Nukta;
2076         case 0x0940:
2077         case 0x093E: return lex_Matra_post;
2078         case 0x093F: return lex_Matra_pre;
2079         case 0x094D: return lex_Halant;
2080         case 0x0972: return lex_Vowel;
2081         case 0x200C: return lex_ZWNJ;
2082         case 0x200D: return lex_ZWJ;
2083         default:
2084             if (c>=0x0901 && c<=0x0902) return lex_Matra_above;
2085             else if (c>=0x0904 && c<=0x0914) return lex_Vowel;
2086             else if (c>=0x0915 && c<=0x0939) return lex_Consonant;
2087             else if (c>=0x0941 && c<=0x0944) return lex_Matra_below;
2088             else if (c>=0x0945 && c<=0x0948) return lex_Matra_above;
2089             else if (c>=0x0949 && c<=0x094C) return lex_Matra_post;
2090             else if (c>=0x0953 && c<=0x0954) return lex_Modifier;
2091             else if (c>=0x0958 && c<=0x095F) return lex_Consonant;
2092             else if (c>=0x0960 && c<=0x0961) return lex_Vowel;
2093             else if (c>=0x0962 && c<=0x0963) return lex_Matra_below;
2094             else if (c>=0x097B && c<=0x097C) return lex_Consonant;
2095             else if (c>=0x097E && c<=0x097F) return lex_Consonant;
2096             else return lex_Generic;
2097     }
2098 }
2099
2100 static const ConsonantComponents Devanagari_consonants[] ={
2101     {{0x0928, 0x093C, 0x00000}, 0x0929},
2102     {{0x0930, 0x093C, 0x00000}, 0x0931},
2103     {{0x0933, 0x093C, 0x00000}, 0x0934},
2104     {{0x0915, 0x093C, 0x00000}, 0x0958},
2105     {{0x0916, 0x093C, 0x00000}, 0x0959},
2106     {{0x0917, 0x093C, 0x00000}, 0x095A},
2107     {{0x091C, 0x093C, 0x00000}, 0x095B},
2108     {{0x0921, 0x093C, 0x00000}, 0x095C},
2109     {{0x0922, 0x093C, 0x00000}, 0x095D},
2110     {{0x092B, 0x093C, 0x00000}, 0x095E},
2111     {{0x092F, 0x093C, 0x00000}, 0x095F}};
2112
2113 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2114 {
2115     int cCount = cChars;
2116     WCHAR *input;
2117
2118     if (*pcGlyphs != cChars)
2119     {
2120         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2121         return;
2122     }
2123
2124     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2125     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2126
2127     /* Step 1: Compose Consonant and Nukta */
2128     ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
2129     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2130
2131     /* Step 2: Reorder within Syllables */
2132     Indic_ReorderCharacters( input, cCount, devanagari_lex, Reorder_Like_Devanagari);
2133     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2134     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2135     *pcGlyphs = cCount;
2136
2137     HeapFree(GetProcessHeap(),0,input);
2138 }
2139
2140 static int bengali_lex(WCHAR c)
2141 {
2142     switch (c)
2143     {
2144         case 0x0981: return lex_Modifier;
2145         case 0x09AC:
2146         case 0x09AF:
2147         case 0x09CE: return lex_Consonant;
2148         case 0x09B0: return lex_Ra;
2149         case 0x09BC: return lex_Nukta;
2150         case 0x09BF: return lex_Matra_pre;
2151         case 0x09D7:
2152         case 0x09BE:
2153         case 0x09C0: return lex_Matra_post;
2154         case 0x09CD: return lex_Halant;
2155         case 0x200C: return lex_ZWNJ;
2156         case 0x200D: return lex_ZWJ;
2157         default:
2158             if (c>=0x0982 && c<=0x0983) return lex_Matra_post;
2159             else if (c>=0x0985 && c<=0x0994) return lex_Vowel;
2160             else if (c>=0x0995 && c<=0x09B9) return lex_Consonant;
2161             else if (c>=0x09C1 && c<=0x09C4) return lex_Matra_below;
2162             else if (c>=0x09C7 && c<=0x09C8) return lex_Matra_pre;
2163             else if (c>=0x09DC && c<=0x09DF) return lex_Consonant;
2164             else if (c>=0x09E0 && c<=0x09E1) return lex_Vowel;
2165             else if (c>=0x09E2 && c<=0x09E3) return lex_Matra_below;
2166             else if (c>=0x09F0 && c<=0x09F1) return lex_Consonant;
2167             else return lex_Generic;
2168     }
2169 }
2170
2171 static const VowelComponents Bengali_vowels[] = {
2172             {0x09CB, {0x09C7,0x09BE,0x0000}},
2173             {0x09CC, {0x09C7,0x09D7,0x0000}},
2174             {0x0000, {0x0000,0x0000,0x0000}}};
2175
2176 static const ConsonantComponents Bengali_consonants[] = {
2177             {{0x09A4,0x09CD,0x200D}, 0x09CE},
2178             {{0x09A1,0x09BC,0x0000}, 0x09DC},
2179             {{0x09A2,0x09BC,0x0000}, 0x09DD},
2180             {{0x09AF,0x09BC,0x0000}, 0x09DF},
2181             {{0x0000,0x0000,0x0000}, 0x0000}};
2182
2183 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2184 {
2185     int cCount = cChars;
2186     WCHAR *input;
2187
2188     if (*pcGlyphs != cChars)
2189     {
2190         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2191         return;
2192     }
2193
2194     input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2195     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2196
2197     /* Step 1: Decompose Vowels and Compose Consonents */
2198     DecomposeVowels(hdc, input,  &cCount, Bengali_vowels);
2199     ComposeConsonants(hdc, input, &cCount, Bengali_consonants);
2200     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2201
2202     /* Step 2: Reorder within Syllables */
2203     Indic_ReorderCharacters( input, cCount, bengali_lex, Reorder_Like_Bengali);
2204     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2205     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2206     *pcGlyphs = cCount;
2207
2208     HeapFree(GetProcessHeap(),0,input);
2209 }
2210
2211 static int gurmukhi_lex(WCHAR c)
2212 {
2213     switch (c)
2214     {
2215         case 0x0A30:
2216         case 0x0A35:
2217         case 0x0A39:
2218         case 0x0A2f: return lex_Consonant;
2219         case 0x0A3C: return lex_Nukta;
2220         case 0x0A3F: return lex_Matra_pre;
2221         case 0x0A03:
2222         case 0x0A3E:
2223         case 0x0A40: return lex_Matra_post;
2224         case 0x0A4D: return lex_Halant;
2225         case 0x0A70:
2226         case 0x0A71: return lex_Modifier;
2227         case 0x200C: return lex_ZWNJ;
2228         case 0x200D: return lex_ZWJ;
2229         default:
2230             if (c>=0x0A01 && c<=0x0A02) return lex_Modifier;
2231             else if (c>=0x0A05 && c<=0x0A14) return lex_Vowel;
2232             else if (c>=0x0A15 && c<=0x0A38) return lex_Consonant;
2233             else if (c>=0x0A41 && c<=0x0A42) return lex_Matra_below;
2234             else if (c>=0x0A47 && c<=0x0A4C) return lex_Matra_above;
2235             else if (c>=0x0A59 && c<=0x0A5E) return lex_Consonant;
2236             else return lex_Generic;
2237     }
2238 }
2239
2240 static const ConsonantComponents Gurmukhi_consonants[] = {
2241             {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2242             {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2243             {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2244             {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2245             {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2246             {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2247             {{0x0000,0x0000,0x0000}, 0x0000}};
2248
2249 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2250 {
2251     int cCount = cChars;
2252     WCHAR *input;
2253
2254     if (*pcGlyphs != cChars)
2255     {
2256         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2257         return;
2258     }
2259
2260     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2261     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2262
2263     /* Step 1: Compose Consonents */
2264     ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants);
2265     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2266
2267     /* Step 2: Reorder within Syllables */
2268     Indic_ReorderCharacters( input, cCount, gurmukhi_lex, Reorder_Like_Bengali);
2269     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2270     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2271     *pcGlyphs = cCount;
2272
2273     HeapFree(GetProcessHeap(),0,input);
2274 }
2275
2276 static int gujarati_lex(WCHAR c)
2277 {
2278     switch (c)
2279     {
2280         case 0x0A83: return lex_Modifier;
2281         case 0x0AB0: return lex_Ra;
2282         case 0x0ABC: return lex_Nukta;
2283         case 0x0ABF: return lex_Matra_pre;
2284         case 0x0ABE:
2285         case 0x0AC0: return lex_Matra_post;
2286         case 0x0ACD: return lex_Halant;
2287         case 0x200C: return lex_ZWNJ;
2288         case 0x200D: return lex_ZWJ;
2289         default:
2290             if (c>=0x0A81 && c<=0x0A82) return lex_Modifier;
2291             else if (c>=0x0A85 && c<=0x0A94) return lex_Vowel;
2292             else if (c>=0x0A95 && c<=0x0AB9) return lex_Consonant;
2293             else if (c>=0x0AC1 && c<=0x0AC4) return lex_Matra_below;
2294             else if (c>=0x0AC5 && c<=0x0AC8) return lex_Matra_above;
2295             else if (c>=0x0AC9 && c<=0x0ACC) return lex_Matra_post;
2296             else if (c>=0x0AE0 && c<=0x0AE1) return lex_Vowel;
2297             else if (c>=0x0AE2 && c<=0x0AE3) return lex_Matra_below;
2298             else return lex_Generic;
2299     }
2300 }
2301
2302 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2303 {
2304     int cCount = cChars;
2305     WCHAR *input;
2306
2307     if (*pcGlyphs != cChars)
2308     {
2309         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2310         return;
2311     }
2312
2313     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2314     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2315
2316     /* Step 1: Reorder within Syllables */
2317     Indic_ReorderCharacters( input, cCount, gujarati_lex, Reorder_Like_Devanagari);
2318     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2319     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2320     *pcGlyphs = cCount;
2321
2322     HeapFree(GetProcessHeap(),0,input);
2323 }
2324
2325 static int oriya_lex(WCHAR c)
2326 {
2327     switch (c)
2328     {
2329         case 0x0B24:
2330         case 0x0B28:
2331         case 0x0B2F:
2332         case 0x0B5F:
2333         case 0x0B71:
2334         case 0x0B33: return lex_Consonant;
2335         case 0x0B30: return lex_Ra;
2336         case 0x0B3C: return lex_Nukta;
2337         case 0x0B3F:
2338         case 0x0B56: return lex_Matra_above;
2339         case 0x0B3E:
2340         case 0x0B57:
2341         case 0x0B40: return lex_Matra_post;
2342         case 0x0B47: return lex_Matra_pre;
2343         case 0x0B4D: return lex_Halant;
2344         case 0x200C: return lex_ZWNJ;
2345         case 0x200D: return lex_ZWJ;
2346         default:
2347             if (c>=0x0B01 && c<=0x0B03) return lex_Modifier;
2348             else if (c>=0x0B05 && c<=0x0B14) return lex_Vowel;
2349             else if (c>=0x0B15 && c<=0x0B39) return lex_Consonant;
2350             else if (c>=0x0B2C && c<=0x0B2E) return lex_Consonant;
2351             else if (c>=0x0B32 && c<=0x0B33) return lex_Consonant;
2352             else if (c>=0x0B41 && c<=0x0B44) return lex_Matra_below;
2353             else if (c>=0x0B48 && c<=0x0B4C) return lex_Composed_Vowel;
2354             else if (c>=0x0B5C && c<=0x0B5D) return lex_Consonant;
2355             else if (c>=0x0B60 && c<=0x0B61) return lex_Vowel;
2356             else if (c>=0x0B62 && c<=0x0B63) return lex_Matra_below;
2357             else return lex_Generic;
2358     }
2359 }
2360
2361 static const VowelComponents Oriya_vowels[] = {
2362             {0x0B48, {0x0B47,0x0B56,0x0000}},
2363             {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2364             {0x0B4C, {0x0B47,0x0B57,0x0000}},
2365             {0x0000, {0x0000,0x0000,0x0000}}};
2366
2367 static const ConsonantComponents Oriya_consonants[] = {
2368             {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2369             {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2370             {{0x0000,0x0000,0x0000}, 0x0000}};
2371
2372 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2373 {
2374     int cCount = cChars;
2375     WCHAR *input;
2376
2377     if (*pcGlyphs != cChars)
2378     {
2379         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2380         return;
2381     }
2382
2383     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2384     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2385
2386     /* Step 1: Decompose Vowels and Compose Consonents */
2387     DecomposeVowels(hdc, input,  &cCount, Oriya_vowels);
2388     ComposeConsonants(hdc, input, &cCount, Oriya_consonants);
2389     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2390
2391     /* Step 2: Reorder within Syllables */
2392     Indic_ReorderCharacters( input, cCount, oriya_lex, Reorder_Like_Bengali);
2393     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2394     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2395     *pcGlyphs = cCount;
2396
2397     HeapFree(GetProcessHeap(),0,input);
2398 }
2399
2400 static int tamil_lex(WCHAR c)
2401 {
2402     switch (c)
2403     {
2404         case 0x0BC0: return lex_Matra_above;
2405         case 0x0BCD: return lex_Halant;
2406         case 0x0BD7: return lex_Matra_post;
2407         case 0x200C: return lex_ZWNJ;
2408         case 0x200D: return lex_ZWJ;
2409         default:
2410             if (c>=0x0B95 && c<=0x0BB9) return lex_Consonant;
2411             else if (c>=0x0BBE && c<=0x0BBF) return lex_Matra_post;
2412             else if (c>=0x0BC1 && c<=0x0BC2) return lex_Matra_below;
2413             else if (c>=0x0BC6 && c<=0x0BC8) return lex_Matra_pre;
2414             else return lex_Generic;
2415     }
2416 }
2417
2418 static const VowelComponents Tamil_vowels[] = {
2419             {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2420             {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2421             {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2422             {0x0000, {0x0000,0x0000,0x0000}}};
2423
2424 static const ConsonantComponents Tamil_consonants[] = {
2425             {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2426             {{0x0000,0x0000,0x0000}, 0x0000}};
2427
2428 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2429 {
2430     int cCount = cChars;
2431     WCHAR *input;
2432
2433     if (*pcGlyphs != cChars)
2434     {
2435         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2436         return;
2437     }
2438
2439     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2440     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2441
2442     /* Step 1: Decompose Vowels and Compose Consonents */
2443     DecomposeVowels(hdc, input,  &cCount, Tamil_vowels);
2444     ComposeConsonants(hdc, input, &cCount, Tamil_consonants);
2445     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2446
2447     /* Step 2: Reorder within Syllables */
2448     Indic_ReorderCharacters( input, cCount, tamil_lex, Reorder_Like_Sinhala);
2449     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2450     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2451     *pcGlyphs = cCount;
2452
2453     HeapFree(GetProcessHeap(),0,input);
2454 }
2455
2456 static int telugu_lex(WCHAR c)
2457 {
2458     switch (c)
2459     {
2460         case 0x0C4D: return lex_Halant;
2461         case 0x0C55: return lex_Matra_above;
2462         case 0x0C56: return lex_Matra_below;
2463         case 0x200C: return lex_ZWNJ;
2464         case 0x200D: return lex_ZWJ;
2465         default:
2466             if (c>=0x0C01 && c<=0x0C03) return lex_Matra_post;
2467             else if (c>=0x0C05 && c<=0x0C14) return lex_Vowel;
2468             else if (c>=0x0C15 && c<=0x0C39) return lex_Consonant;
2469             else if (c>=0x0C3E && c<=0x0C40) return lex_Matra_above;
2470             else if (c>=0x0C41 && c<=0x0C44) return lex_Matra_post;
2471             else if (c>=0x0C46 && c<=0x0C47) return lex_Matra_above;
2472             else if (c>=0x0C4A && c<=0x0C4C) return lex_Matra_above;
2473             else if (c>=0x0C58 && c<=0x0C59) return lex_Consonant;
2474             else if (c>=0x0C60 && c<=0x0C61) return lex_Vowel;
2475             else if (c>=0x0C62 && c<=0x0C63) return lex_Matra_below;
2476             else return lex_Generic;
2477     }
2478 }
2479
2480 static const VowelComponents Telugu_vowels[] = {
2481             {0x0C48, {0x0C46,0x0C56,0x0000}},
2482             {0x0000, {0x0000,0x0000,0x0000}}};
2483
2484 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2485 {
2486     int cCount = cChars;
2487     WCHAR *input;
2488
2489     if (*pcGlyphs != cChars)
2490     {
2491         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2492         return;
2493     }
2494
2495     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2496     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2497
2498     /* Step 1: Decompose Vowels */
2499     DecomposeVowels(hdc, input,  &cCount, Telugu_vowels);
2500     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2501
2502     /* Step 2: Reorder within Syllables */
2503     Indic_ReorderCharacters( input, cCount, telugu_lex, Reorder_Like_Bengali);
2504     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2505     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2506     *pcGlyphs = cCount;
2507
2508     HeapFree(GetProcessHeap(),0,input);
2509 }
2510
2511 static int kannada_lex(WCHAR c)
2512 {
2513     switch (c)
2514     {
2515         case 0x0CB0: return lex_Ra;
2516         case 0x0CBC: return lex_Nukta;
2517         case 0x0CBE: return lex_Matra_post;
2518         case 0x0CBF: return lex_Matra_above;
2519         case 0x0CC6: return lex_Matra_above;
2520         case 0x0CCC: return lex_Matra_above;
2521         case 0x0CCD: return lex_Halant;
2522         case 0x0CCE: return lex_Consonant;
2523         case 0x200C: return lex_ZWNJ;
2524         case 0x200D: return lex_ZWJ;
2525         default:
2526             if (c>=0x0C82 && c<=0x0C83) return lex_Modifier;
2527             else if (c>=0x0C85 && c<=0x0C94) return lex_Vowel;
2528             else if (c>=0x0C95 && c<=0x0CB9) return lex_Consonant;
2529             else if (c>=0x0CC1 && c<=0x0CC4) return lex_Matra_post;
2530             else if (c>=0x0CD5 && c<=0x0CD6) return lex_Modifier;
2531             else if (c>=0x0CE0 && c<=0x0CE1) return lex_Vowel;
2532             else if (c>=0x0CE2 && c<=0x0CE3) return lex_Matra_below;
2533             else return lex_Generic;
2534     }
2535 }
2536
2537 static const VowelComponents Kannada_vowels[] = {
2538             {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2539             {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2540             {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2541             {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2542             {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2543             {0x0000, {0x0000,0x0000,0x0000}}};
2544
2545 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2546 {
2547     int cCount = cChars;
2548     WCHAR *input;
2549
2550     if (*pcGlyphs != cChars)
2551     {
2552         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2553         return;
2554     }
2555
2556     input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2557     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2558
2559     /* Step 1: Decompose Vowels */
2560     DecomposeVowels(hdc, input,  &cCount, Kannada_vowels);
2561     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2562
2563     /* Step 2: Reorder within Syllables */
2564     Indic_ReorderCharacters( input, cCount, kannada_lex, Reorder_Like_Kannada);
2565     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2566     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2567     *pcGlyphs = cCount;
2568
2569     HeapFree(GetProcessHeap(),0,input);
2570 }
2571
2572 static int malayalam_lex(WCHAR c)
2573 {
2574     switch (c)
2575     {
2576         case 0x0D35: return lex_Consonant;
2577         case 0x0D4D: return lex_Halant;
2578         case 0x0D57: return lex_Matra_post;
2579         case 0x200C: return lex_ZWNJ;
2580         case 0x200D: return lex_ZWJ;
2581         default:
2582             if (c>=0x0D02 && c<=0x0D03) return lex_Modifier;
2583             else if (c>=0x0D05 && c<=0x0D14) return lex_Vowel;
2584             else if (c>=0x0D15 && c<=0x0D39) return lex_Consonant;
2585             else if (c>=0x0D3E && c<=0x0D44) return lex_Matra_post;
2586             else if (c>=0x0D46 && c<=0x0D48) return lex_Matra_pre;
2587             else if (c>=0x0D60 && c<=0x0D61) return lex_Vowel;
2588             else if (c>=0x0D62 && c<=0x0D63) return lex_Matra_below;
2589             else return lex_Generic;
2590     }
2591 }
2592
2593 static const VowelComponents Malayalam_vowels[] = {
2594             {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2595             {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2596             {0x0D4C, {0x0D46,0x0D57,0x0000}},
2597             {0x0000, {0x0000,0x0000,0x0000}}};
2598
2599 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2600 {
2601     int cCount = cChars;
2602     WCHAR *input;
2603
2604     if (*pcGlyphs != cChars)
2605     {
2606         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2607         return;
2608     }
2609
2610     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2611     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2612
2613     /* Step 1: Decompose Vowels */
2614     DecomposeVowels(hdc, input,  &cCount, Malayalam_vowels);
2615     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2616
2617     /* Step 2: Reorder within Syllables */
2618     Indic_ReorderCharacters( input, cCount, malayalam_lex, Reorder_Like_Malayalam);
2619     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2620     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2621     *pcGlyphs = cCount;
2622
2623     HeapFree(GetProcessHeap(),0,input);
2624 }
2625
2626 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)
2627 {
2628     int i,k;
2629
2630     for (i = 0; i < cGlyphs; i++)
2631     {
2632         int char_index[20];
2633         int char_count = 0;
2634
2635         for (k = 0; k < cChars; k++)
2636         {
2637             if (pwLogClust[k] == i)
2638             {
2639                 char_index[char_count] = k;
2640                 char_count++;
2641             }
2642         }
2643
2644         if (char_count == 0)
2645         {
2646             FIXME("No chars in this glyph?  Must be an error\n");
2647             continue;
2648         }
2649
2650         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2651         {
2652             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2653             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2654         }
2655         else
2656             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2657     }
2658
2659     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2660     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2661 }
2662
2663 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 )
2664 {
2665     int i,k;
2666     int initGlyph, finaGlyph;
2667     INT dirR, dirL;
2668     BYTE *spaces;
2669
2670     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2671     memset(spaces,0,cGlyphs);
2672
2673     if (!psa->fLogicalOrder && psa->fRTL)
2674     {
2675         initGlyph = cGlyphs-1;
2676         finaGlyph = 0;
2677         dirR = 1;
2678         dirL = -1;
2679     }
2680     else
2681     {
2682         initGlyph = 0;
2683         finaGlyph = cGlyphs-1;
2684         dirR = -1;
2685         dirL = 1;
2686     }
2687
2688     for (i = 0; i < cGlyphs; i++)
2689     {
2690         for (k = 0; k < cChars; k++)
2691             if (pwLogClust[k] == i)
2692             {
2693                 if (pwcChars[k] == 0x0020)
2694                     spaces[i] = 1;
2695             }
2696     }
2697
2698     for (i = 0; i < cGlyphs; i++)
2699     {
2700         int char_index[20];
2701         int char_count = 0;
2702         BOOL isInit, isFinal;
2703
2704         for (k = 0; k < cChars; k++)
2705         {
2706             if (pwLogClust[k] == i)
2707             {
2708                 char_index[char_count] = k;
2709                 char_count++;
2710             }
2711         }
2712
2713         isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2714         isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2715
2716         if (char_count == 0)
2717         {
2718             FIXME("No chars in this glyph?  Must be an error\n");
2719             continue;
2720         }
2721
2722         if (char_count == 1)
2723         {
2724             if (pwcChars[char_index[0]] == 0x0020)  /* space */
2725             {
2726                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2727                 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2728             }
2729             else if (pwcChars[char_index[0]] == 0x0640)  /* kashida */
2730                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2731             else if (pwcChars[char_index[0]] == 0x0633)  /* SEEN */
2732             {
2733                 if (!isInit && !isFinal)
2734                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2735                 else if (isInit)
2736                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2737                 else
2738                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2739             }
2740             else if (!isInit)
2741             {
2742                 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2743                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2744                 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2745                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2746                 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2747                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2748                 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2749                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2750                 else
2751                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2752             }
2753             else if (!isInit && !isFinal)
2754                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2755             else
2756                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2757         }
2758         else if (char_count == 2)
2759         {
2760             if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) ||  (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2761                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2762             else if (!isInit)
2763                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2764             else
2765                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2766         }
2767         else if (!isInit && !isFinal)
2768             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2769         else
2770             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2771     }
2772
2773     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2774     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2775     HeapFree(GetProcessHeap(),0,spaces);
2776 }
2777
2778 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 )
2779 {
2780     int i,k;
2781     int finaGlyph;
2782     INT dirL;
2783     BYTE *spaces;
2784
2785     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2786     memset(spaces,0,cGlyphs);
2787
2788     if (!psa->fLogicalOrder && psa->fRTL)
2789     {
2790         finaGlyph = 0;
2791         dirL = -1;
2792     }
2793     else
2794     {
2795         finaGlyph = cGlyphs-1;
2796         dirL = 1;
2797     }
2798
2799     for (i = 0; i < cGlyphs; i++)
2800     {
2801         for (k = 0; k < cChars; k++)
2802             if (pwLogClust[k] == i)
2803             {
2804                 if (pwcChars[k] == 0x0020)
2805                     spaces[i] = 1;
2806             }
2807     }
2808
2809     for (i = 0; i < cGlyphs; i++)
2810     {
2811         int char_index[20];
2812         int char_count = 0;
2813
2814         for (k = 0; k < cChars; k++)
2815         {
2816             if (pwLogClust[k] == i)
2817             {
2818                 char_index[char_count] = k;
2819                 char_count++;
2820             }
2821         }
2822
2823         if (char_count == 0)
2824         {
2825             FIXME("No chars in this glyph?  Must be an error\n");
2826             continue;
2827         }
2828
2829         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2830         {
2831             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2832             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2833         }
2834         else if (i == finaGlyph)
2835             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2836         else
2837             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2838     }
2839
2840     HeapFree(GetProcessHeap(),0,spaces);
2841     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2842     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2843
2844     /* Do not allow justification between marks and their base */
2845     for (i = 0; i < cGlyphs; i++)
2846     {
2847         if (!pGlyphProp[i].sva.fClusterStart)
2848             pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2849     }
2850 }
2851
2852 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)
2853 {
2854     int i,k;
2855
2856     for (i = 0; i < cGlyphs; i++)
2857     {
2858         int char_index[20];
2859         int char_count = 0;
2860
2861         for (k = 0; k < cChars; k++)
2862         {
2863             if (pwLogClust[k] == i)
2864             {
2865                 char_index[char_count] = k;
2866                 char_count++;
2867             }
2868         }
2869
2870         if (char_count == 0)
2871         {
2872             FIXME("No chars in this glyph?  Must be an error\n");
2873             continue;
2874         }
2875
2876         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2877         {
2878             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2879             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2880         }
2881         else
2882             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2883     }
2884     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2885     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2886 }
2887
2888 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)
2889 {
2890     int i,k;
2891
2892     for (i = 0; i < cGlyphs; i++)
2893     {
2894         int char_index[20];
2895         int char_count = 0;
2896
2897         for (k = 0; k < cChars; k++)
2898         {
2899             if (pwLogClust[k] == i)
2900             {
2901                 char_index[char_count] = k;
2902                 char_count++;
2903             }
2904         }
2905
2906         if (char_count == 0)
2907         {
2908             FIXME("No chars in this glyph?  Must be an error\n");
2909             continue;
2910         }
2911
2912         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2913         {
2914             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2915             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2916         }
2917         else
2918             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2919     }
2920     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2921     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2922
2923     /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2924     for (i = 0; i < cGlyphs; i++)
2925     {
2926         if (!pGlyphProp[i].sva.fClusterStart)
2927         {
2928             pGlyphProp[i].sva.fDiacritic = 0;
2929             pGlyphProp[i].sva.fZeroWidth = 0;
2930         }
2931     }
2932 }
2933
2934 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)
2935 {
2936     int i,k;
2937
2938     for (i = 0; i < cGlyphs; i++)
2939     {
2940         int char_index[20];
2941         int char_count = 0;
2942
2943         for (k = 0; k < cChars; k++)
2944         {
2945             if (pwLogClust[k] == i)
2946             {
2947                 char_index[char_count] = k;
2948                 char_count++;
2949             }
2950         }
2951
2952         if (char_count == 0)
2953         {
2954             FIXME("No chars in this glyph?  Must be an error\n");
2955             continue;
2956         }
2957
2958         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2959         {
2960             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2961             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2962         }
2963         else
2964             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2965
2966         pGlyphProp[i].sva.fClusterStart = 0;
2967         for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
2968             switch (lexical(pwcChars[char_index[k]]))
2969             {
2970                 case lex_Matra_pre:
2971                 case lex_Matra_post:
2972                 case lex_Matra_above:
2973                 case lex_Matra_below:
2974                 case lex_Modifier:
2975                     break;
2976                 default:
2977                     pGlyphProp[i].sva.fClusterStart = 1;
2978                     break;
2979             }
2980     }
2981     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2982 }
2983
2984 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 )
2985 {
2986     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
2987 }
2988
2989 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 )
2990 {
2991     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
2992 }
2993
2994 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 )
2995 {
2996     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
2997 }
2998
2999 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 )
3000 {
3001     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3002 }
3003
3004 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 )
3005 {
3006     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3007 }
3008
3009 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 )
3010 {
3011     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3012 }
3013
3014 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 )
3015 {
3016     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3017 }
3018
3019 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 )
3020 {
3021     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3022 }
3023
3024 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 )
3025 {
3026     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3027 }
3028
3029 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)
3030 {
3031     if (ShapingData[psa->eScript].charGlyphPropProc)
3032         ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3033     else
3034         ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3035 }
3036
3037 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3038 {
3039     if (ShapingData[psa->eScript].contextProc)
3040         ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3041 }
3042
3043 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)
3044 {
3045     int i;
3046     INT dirL;
3047
3048     if (!rpRangeProperties)
3049         return;
3050
3051     if (!psc->GSUB_Table)
3052         psc->GSUB_Table = load_gsub_table(hdc);
3053
3054     if (!psc->GSUB_Table)
3055         return;
3056
3057     if (!psa->fLogicalOrder && psa->fRTL)
3058         dirL = -1;
3059     else
3060         dirL = 1;
3061
3062     for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3063     {
3064         if (rpRangeProperties->potfRecords[i].lParameter > 0)
3065         apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3066     }
3067 }
3068
3069 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3070 {
3071 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3072 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3073
3074     SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3075 }
3076
3077 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3078 {
3079     const GSUB_Feature *feature;
3080     int i;
3081
3082     if (!ShapingData[psa->eScript].requiredFeatures)
3083         return S_OK;
3084
3085     if (!psc->GSUB_Table)
3086         psc->GSUB_Table = load_gsub_table(hdc);
3087
3088     /* we need to have at least one of the required features */
3089     i = 0;
3090     while (ShapingData[psa->eScript].requiredFeatures[i])
3091     {
3092         feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3093         if (feature)
3094             return S_OK;
3095         i++;
3096     }
3097
3098     return USP_E_SCRIPT_NOT_IN_FONT;
3099 }