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