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