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