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