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