dinput: Fix printing NULL strings.
[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[])
1787 {
1788     int i;
1789     int cWalk;
1790
1791     for (cWalk = 0; cWalk < *pcChars; cWalk++)
1792     {
1793         for (i = 0; vowels[i].base != 0x0; i++)
1794         {
1795             if (pwOutChars[cWalk] == vowels[i].base)
1796             {
1797                 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1798                 if (vowels[i].parts[1]) cWalk++;
1799                 if (vowels[i].parts[2]) cWalk++;
1800                 break;
1801             }
1802         }
1803     }
1804 }
1805
1806 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1807 {
1808     int i;
1809     int cWalk;
1810
1811     for (cWalk = 0; cWalk < *pcChars; cWalk++)
1812     {
1813         for (i = 0; consonants[i].output!= 0x0; i++)
1814         {
1815             int j;
1816             for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1817                 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1818                     break;
1819
1820             if (consonants[i].parts[j]==0x0) /* matched all */
1821             {
1822                 int k;
1823                 j--;
1824                 pwOutChars[cWalk] = consonants[i].output;
1825                 for(k = cWalk+1; k < *pcChars - j; k++)
1826                     pwOutChars[k] = pwOutChars[k+j];
1827                 *pcChars = *pcChars - j;
1828                 break;
1829             }
1830         }
1831         cWalk++;
1832     }
1833 }
1834
1835 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1836 {
1837     if (s->ralf >= 0)
1838     {
1839         int j;
1840         WORD Ra = pwChar[s->start];
1841         WORD H = pwChar[s->start+1];
1842
1843         TRACE("Doing reorder of Ra to %i\n",s->base);
1844         for (j = s->start; j < s->base-1; j++)
1845             pwChar[j] = pwChar[j+2];
1846         pwChar[s->base-1] = Ra;
1847         pwChar[s->base] = H;
1848
1849         s->ralf = s->base-1;
1850         s->base -= 2;
1851     }
1852 }
1853
1854 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1855 {
1856     if (s->ralf >= 0)
1857     {
1858         int j,loc;
1859         int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1860         WORD Ra = pwChar[s->start];
1861         WORD H = pwChar[s->start+1];
1862         for (loc = s->end; loc > stop; loc--)
1863             if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1864                 break;
1865
1866         TRACE("Doing reorder of Ra to %i\n",loc);
1867         for (j = s->start; j < loc-1; j++)
1868             pwChar[j] = pwChar[j+2];
1869         pwChar[loc-1] = Ra;
1870         pwChar[loc] = H;
1871
1872         s->ralf = loc-1;
1873         s->base -= 2;
1874         if (s->blwf >= 0) s->blwf -= 2;
1875         if (s->pref >= 0) s->pref -= 2;
1876     }
1877 }
1878
1879 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1880 {
1881     if (s->ralf >= 0)
1882     {
1883         int j;
1884         WORD Ra = pwChar[s->start];
1885         WORD H = pwChar[s->start+1];
1886
1887         TRACE("Doing reorder of Ra to %i\n",s->end-1);
1888         for (j = s->start; j < s->end-1; j++)
1889             pwChar[j] = pwChar[j+2];
1890         pwChar[s->end-1] = Ra;
1891         pwChar[s->end] = H;
1892
1893         s->ralf = s->end-1;
1894         s->base -= 2;
1895         if (s->blwf >= 0) s->blwf -= 2;
1896         if (s->pref >= 0) s->pref -= 2;
1897     }
1898 }
1899
1900 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1901 {
1902     int i;
1903
1904     /* reorder Matras */
1905     if (s->end > s->base)
1906     {
1907         for (i = 1; i <= s->end-s->base; i++)
1908         {
1909             if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1910             {
1911                 int j;
1912                 WCHAR c = pwChar[s->base+i];
1913                 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1914                 for (j = s->base+i; j > s->base; j--)
1915                     pwChar[j] = pwChar[j-1];
1916                 pwChar[s->base] = c;
1917
1918                 if (s->ralf >= s->base) s->ralf++;
1919                 if (s->blwf >= s->base) s->blwf++;
1920                 if (s->pref >= s->base) s->pref++;
1921                 s->base ++;
1922             }
1923         }
1924     }
1925 }
1926
1927 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1928 {
1929     int i;
1930
1931     /* reorder Matras */
1932     if (s->end > s->base)
1933     {
1934         for (i = 1; i <= s->end-s->base; i++)
1935         {
1936             if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1937             {
1938                 int j;
1939                 WCHAR c = pwChar[s->base+i];
1940                 TRACE("Doing reorder of %x to %i\n",c,s->start);
1941                 for (j = s->base+i; j > s->start; j--)
1942                     pwChar[j] = pwChar[j-1];
1943                 pwChar[s->start] = c;
1944
1945                 if (s->ralf >= 0) s->ralf++;
1946                 if (s->blwf >= 0) s->blwf++;
1947                 if (s->pref >= 0) s->pref++;
1948                 s->base ++;
1949             }
1950         }
1951     }
1952 }
1953
1954 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1955 {
1956     if (s->blwf >= 0 && g->blwf > g->base)
1957     {
1958         int j,loc;
1959         int g_offset;
1960         for (loc = s->end; loc > s->blwf; loc--)
1961             if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1962                 break;
1963
1964         g_offset = (loc - s->blwf) - 1;
1965
1966         if (loc != s->blwf)
1967         {
1968             WORD blwf = glyphs[g->blwf];
1969             TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1970             /* do not care about the pwChar array anymore, just the glyphs */
1971             for (j = 0; j < g_offset; j++)
1972                 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1973             glyphs[g->blwf + g_offset] = blwf;
1974         }
1975     }
1976 }
1977
1978 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1979 {
1980     int i;
1981
1982     /* reorder previously moved Matras to correct position*/
1983     for (i = s->start; i < s->base; i++)
1984     {
1985         if (lexical(pwChar[i]) == lex_Matra_pre)
1986         {
1987             int j;
1988             int g_start = g->start + i - s->start;
1989             if (g_start < g->base -1 )
1990             {
1991                 WCHAR og = glyphs[g_start];
1992                 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1993                 for (j = g_start; j < g->base-1; j++)
1994                     glyphs[j] = glyphs[j+1];
1995                 glyphs[g->base-1] = og;
1996             }
1997         }
1998     }
1999 }
2000
2001 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2002 {
2003     if (s->pref >= 0 && g->pref > g->base)
2004     {
2005         int j;
2006         WCHAR og = glyphs[g->pref];
2007         TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2008         for (j = g->pref; j > g->base; j--)
2009             glyphs[j] = glyphs[j-1];
2010         glyphs[g->base] = og;
2011     }
2012 }
2013
2014 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2015 {
2016     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2017     if (s->start == s->base && s->base == s->end)  return;
2018     if (lexical(pwChar[s->base]) == lex_Vowel) return;
2019
2020     Reorder_Ra_follows_base(pwChar, s, lexical);
2021     Reorder_Matra_precede_base(pwChar, s, lexical);
2022 }
2023
2024 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2025 {
2026     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2027     if (s->start == s->base && s->base == s->end)  return;
2028     if (lexical(pwChar[s->base]) == lex_Vowel) return;
2029
2030     Reorder_Ra_follows_matra(pwChar, s, lexical);
2031     Reorder_Matra_precede_syllable(pwChar, s, lexical);
2032 }
2033
2034 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2035 {
2036     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2037     if (s->start == s->base && s->base == s->end)  return;
2038     if (lexical(pwChar[s->base]) == lex_Vowel) return;
2039
2040     Reorder_Ra_follows_base(pwChar, s, lexical);
2041     Reorder_Matra_precede_syllable(pwChar, s, lexical);
2042 }
2043
2044 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2045 {
2046     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2047     if (s->start == s->base && s->base == s->end)  return;
2048     if (lexical(pwChar[s->base]) == lex_Vowel) return;
2049
2050     Reorder_Ra_follows_syllable(pwChar, s, lexical);
2051     Reorder_Matra_precede_syllable(pwChar, s, lexical);
2052 }
2053
2054 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2055 {
2056     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2057     TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2058     if (s->start == s->base && s->base == s->end)  return;
2059     if (lexical(pwChar[s->base]) == lex_Vowel) return;
2060
2061     SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2062 }
2063
2064 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2065 {
2066     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2067     TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2068     if (s->start == s->base && s->base == s->end)  return;
2069     if (lexical(pwChar[s->base]) == lex_Vowel) return;
2070
2071     SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2072     SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2073 }
2074
2075
2076 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2077 {
2078     if (shift == 0)
2079         return;
2080
2081     if (glyph_index->start > index)
2082         glyph_index->start += shift;
2083     if (glyph_index->base > index)
2084         glyph_index->base+= shift;
2085     if (glyph_index->end > index)
2086         glyph_index->end+= shift;
2087     if (glyph_index->ralf > index)
2088         glyph_index->ralf+= shift;
2089     if (glyph_index->blwf > index)
2090         glyph_index->blwf+= shift;
2091     if (glyph_index->pref > index)
2092         glyph_index->pref+= shift;
2093 }
2094
2095 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 )
2096 {
2097     int index = glyph_index->start;
2098
2099     if (!feature)
2100         return;
2101
2102     while(index <= glyph_index->end)
2103     {
2104             INT nextIndex;
2105             INT prevCount = *pcGlyphs;
2106             nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2107             if (nextIndex > GSUB_E_NOGLYPH)
2108             {
2109                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2110                 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2111                 index = nextIndex;
2112             }
2113             else
2114                 index++;
2115     }
2116 }
2117
2118 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2119 {
2120     int i = 0;
2121     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)))))
2122         i++;
2123     if (index + i <= end-1)
2124         return index + i;
2125     else
2126         return -1;
2127 }
2128
2129 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)
2130 {
2131     INT index, nextIndex;
2132     INT count,g_offset;
2133
2134     count = syllable->base - syllable->start;
2135
2136     g_offset = 0;
2137     index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2138     while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2139     {
2140         INT prevCount = *pcGlyphs;
2141         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2142         if (nextIndex > GSUB_E_NOGLYPH)
2143         {
2144             UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2145             shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2146             g_offset += (*pcGlyphs - prevCount);
2147         }
2148
2149         index+=2;
2150         index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2151     }
2152 }
2153
2154 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)
2155 {
2156     INT nextIndex;
2157     INT prevCount = *pcGlyphs;
2158
2159     if (syllable->ralf >= 0)
2160     {
2161         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2162         if (nextIndex > GSUB_E_NOGLYPH)
2163         {
2164             UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2165             shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2166         }
2167     }
2168 }
2169
2170 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2171 {
2172     int i = 0;
2173     while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2174              ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2175               is_consonant(lexical(pwChars[index+i+1])))))
2176         i++;
2177     if (index + i <= end-1)
2178         return index+i;
2179     else
2180         return -1;
2181 }
2182
2183 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)
2184 {
2185     INT index, nextIndex;
2186     INT count, g_offset=0;
2187     INT ralf = syllable->ralf;
2188
2189     count = syllable->end - syllable->base;
2190
2191     index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2192
2193     while (index >= 0)
2194     {
2195         INT prevCount = *pcGlyphs;
2196         if (ralf >=0 && ralf < index)
2197         {
2198             g_offset--;
2199             ralf = -1;
2200         }
2201
2202         if (!modern)
2203         {
2204             WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2205             pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2206             pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2207         }
2208
2209         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2210         if (nextIndex > GSUB_E_NOGLYPH)
2211         {
2212             UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2213             shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2214             g_offset += (*pcGlyphs - prevCount);
2215         }
2216         else if (!modern)
2217         {
2218             WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2219             pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2220             pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2221         }
2222
2223         index+=2;
2224         index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2225     }
2226 }
2227
2228 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)
2229 {
2230     int c;
2231     int overall_shift = 0;
2232     const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2233     const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2234     const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2235     const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2236     const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2237     const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2238     const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2239     BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2240     BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2241     BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2242     BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2243     IndicSyllable glyph_indexs;
2244
2245     for (c = 0; c < syllable_count; c++)
2246     {
2247         int old_end;
2248         memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2249         shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2250         old_end = glyph_indexs.end;
2251
2252         if (locl)
2253         {
2254             TRACE("applying feature locl\n");
2255             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2256         }
2257         if (nukt)
2258         {
2259             TRACE("applying feature nukt\n");
2260             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2261         }
2262         if (akhn)
2263         {
2264             TRACE("applying feature akhn\n");
2265             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2266         }
2267
2268         if (rphf)
2269             Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2270         if (rkrf)
2271         {
2272             TRACE("applying feature rkrf\n");
2273             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2274         }
2275         if (pref)
2276             Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2277         if (blwf)
2278         {
2279             if (!modern)
2280                 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2281
2282             Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2283
2284         }
2285         if (half)
2286             Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2287         if (pstf)
2288         {
2289             TRACE("applying feature pstf\n");
2290             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2291         }
2292         if (vatu)
2293         {
2294             TRACE("applying feature vatu\n");
2295             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2296         }
2297         if (cjct)
2298         {
2299             TRACE("applying feature cjct\n");
2300             Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2301         }
2302
2303         if (second_reorder)
2304             second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2305
2306         overall_shift += glyph_indexs.end - old_end;
2307     }
2308 }
2309
2310 static inline int unicode_lex(WCHAR c)
2311 {
2312     int type;
2313
2314     if (!c) return lex_Generic;
2315     if (c == 0x200D) return lex_ZWJ;
2316     if (c == 0x200C) return lex_ZWNJ;
2317     if (c == 0x00A0) return lex_NBSP;
2318
2319     type = get_table_entry( indic_syllabic_table, c );
2320
2321     if ((type & 0x00ff) != 0x0007)  type = type & 0x00ff;
2322
2323     switch( type )
2324     {
2325         case 0x0d07: /* Unknown */
2326         case 0x0e07: /* Unknwon */
2327         default: return lex_Generic;
2328         case 0x0001:
2329         case 0x0002:
2330         case 0x0011:
2331         case 0x0012:
2332         case 0x0013:
2333         case 0x0014: return lex_Modifier;
2334         case 0x0003:
2335         case 0x0009:
2336         case 0x000a:
2337         case 0x000b:
2338         case 0x000d:
2339         case 0x000e:
2340         case 0x000f:
2341         case 0x0010: return lex_Consonant;
2342         case 0x0004: return lex_Nukta;
2343         case 0x0005: return lex_Halant;
2344         case 0x0006:
2345         case 0x0008: return lex_Vowel;
2346         case 0x0007:
2347         case 0x0107: return lex_Matra_post;
2348         case 0x0207:
2349         case 0x0307: return lex_Matra_pre;
2350         case 0x0807:
2351         case 0x0907:
2352         case 0x0a07:
2353         case 0x0b07:
2354         case 0x0c07:
2355         case 0x0407: return lex_Composed_Vowel;
2356         case 0x0507: return lex_Matra_above;
2357         case 0x0607: return lex_Matra_below;
2358         case 0x000c: return lex_Ra;
2359     };
2360 }
2361
2362 static int sinhala_lex(WCHAR c)
2363 {
2364     switch (c)
2365     {
2366         case 0x0DDA:
2367         case 0x0DDD:
2368         case 0x0DDC:
2369         case 0x0DDE: return lex_Matra_post;
2370         default:
2371             return unicode_lex(c);
2372     }
2373 }
2374
2375 static const VowelComponents Sinhala_vowels[] = {
2376             {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2377             {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2378             {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2379             {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2380             {0x0000, {0x0000,0x0000,0x0}}};
2381
2382 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2383 {
2384     int cCount = cChars;
2385     int i;
2386     WCHAR *input;
2387     IndicSyllable *syllables = NULL;
2388     int syllable_count = 0;
2389
2390     if (*pcGlyphs != cChars)
2391     {
2392         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2393         return;
2394     }
2395
2396     input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2397
2398     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2399
2400     /* Step 1:  Decompose multi part vowels */
2401     DecomposeVowels(hdc, input,  &cCount, Sinhala_vowels);
2402
2403     TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2404
2405     /* Step 2:  Reorder within Syllables */
2406     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2407     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2408
2409     /* Step 3:  Strip dangling joiners */
2410     for (i = 0; i < cCount; i++)
2411     {
2412         if ((input[i] == 0x200D || input[i] == 0x200C) &&
2413             (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2414             input[i] = 0x0020;
2415     }
2416
2417     /* Step 4: Base Form application to syllables */
2418     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2419     *pcGlyphs = cCount;
2420     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2421
2422     HeapFree(GetProcessHeap(),0,input);
2423     HeapFree(GetProcessHeap(),0,syllables);
2424 }
2425
2426 static int devanagari_lex(WCHAR c)
2427 {
2428     switch (c)
2429     {
2430         case 0x0930: return lex_Ra;
2431         default:
2432             return unicode_lex(c);
2433     }
2434 }
2435
2436 static const ConsonantComponents Devanagari_consonants[] ={
2437     {{0x0928, 0x093C, 0x00000}, 0x0929},
2438     {{0x0930, 0x093C, 0x00000}, 0x0931},
2439     {{0x0933, 0x093C, 0x00000}, 0x0934},
2440     {{0x0915, 0x093C, 0x00000}, 0x0958},
2441     {{0x0916, 0x093C, 0x00000}, 0x0959},
2442     {{0x0917, 0x093C, 0x00000}, 0x095A},
2443     {{0x091C, 0x093C, 0x00000}, 0x095B},
2444     {{0x0921, 0x093C, 0x00000}, 0x095C},
2445     {{0x0922, 0x093C, 0x00000}, 0x095D},
2446     {{0x092B, 0x093C, 0x00000}, 0x095E},
2447     {{0x092F, 0x093C, 0x00000}, 0x095F}};
2448
2449 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2450 {
2451     int cCount = cChars;
2452     WCHAR *input;
2453     IndicSyllable *syllables = NULL;
2454     int syllable_count = 0;
2455     BOOL modern = get_GSUB_Indic2(psa, psc);
2456
2457     if (*pcGlyphs != cChars)
2458     {
2459         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2460         return;
2461     }
2462
2463     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2464     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2465
2466     /* Step 1: Compose Consonant and Nukta */
2467     ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
2468     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2469
2470     /* Step 2: Reorder within Syllables */
2471     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2472     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2473     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2474     *pcGlyphs = cCount;
2475
2476     /* Step 3: Base Form application to syllables */
2477     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2478
2479     HeapFree(GetProcessHeap(),0,input);
2480     HeapFree(GetProcessHeap(),0,syllables);
2481 }
2482
2483 static int bengali_lex(WCHAR c)
2484 {
2485     switch (c)
2486     {
2487         case 0x09B0: return lex_Ra;
2488         default:
2489             return unicode_lex(c);
2490     }
2491 }
2492
2493 static const VowelComponents Bengali_vowels[] = {
2494             {0x09CB, {0x09C7,0x09BE,0x0000}},
2495             {0x09CC, {0x09C7,0x09D7,0x0000}},
2496             {0x0000, {0x0000,0x0000,0x0000}}};
2497
2498 static const ConsonantComponents Bengali_consonants[] = {
2499             {{0x09A4,0x09CD,0x200D}, 0x09CE},
2500             {{0x09A1,0x09BC,0x0000}, 0x09DC},
2501             {{0x09A2,0x09BC,0x0000}, 0x09DD},
2502             {{0x09AF,0x09BC,0x0000}, 0x09DF},
2503             {{0x0000,0x0000,0x0000}, 0x0000}};
2504
2505 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2506 {
2507     int cCount = cChars;
2508     WCHAR *input;
2509     IndicSyllable *syllables = NULL;
2510     int syllable_count = 0;
2511     BOOL modern = get_GSUB_Indic2(psa, psc);
2512
2513     if (*pcGlyphs != cChars)
2514     {
2515         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2516         return;
2517     }
2518
2519     input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2520     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2521
2522     /* Step 1: Decompose Vowels and Compose Consonents */
2523     DecomposeVowels(hdc, input,  &cCount, Bengali_vowels);
2524     ComposeConsonants(hdc, input, &cCount, Bengali_consonants);
2525     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2526
2527     /* Step 2: Reorder within Syllables */
2528     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2529     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2530     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2531     *pcGlyphs = cCount;
2532
2533     /* Step 3: Initial form is only applied to the beginning of words */
2534     for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2535     {
2536         if (cCount == 0 || input[cCount] == 0x0020) /* space */
2537         {
2538             int index = cCount;
2539             int gCount = 1;
2540             if (index > 0) index++;
2541
2542             apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2543         }
2544     }
2545
2546     /* Step 4: Base Form application to syllables */
2547     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2548
2549     HeapFree(GetProcessHeap(),0,input);
2550     HeapFree(GetProcessHeap(),0,syllables);
2551 }
2552
2553 static int gurmukhi_lex(WCHAR c)
2554 {
2555     return unicode_lex(c);
2556 }
2557
2558 static const ConsonantComponents Gurmukhi_consonants[] = {
2559             {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2560             {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2561             {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2562             {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2563             {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2564             {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2565             {{0x0000,0x0000,0x0000}, 0x0000}};
2566
2567 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2568 {
2569     int cCount = cChars;
2570     WCHAR *input;
2571     IndicSyllable *syllables = NULL;
2572     int syllable_count = 0;
2573     BOOL modern = get_GSUB_Indic2(psa, psc);
2574
2575     if (*pcGlyphs != cChars)
2576     {
2577         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2578         return;
2579     }
2580
2581     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2582     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2583
2584     /* Step 1: Compose Consonents */
2585     ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants);
2586     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2587
2588     /* Step 2: Reorder within Syllables */
2589     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2590     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2591     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2592     *pcGlyphs = cCount;
2593
2594     /* Step 3: Base Form application to syllables */
2595     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2596
2597     HeapFree(GetProcessHeap(),0,input);
2598     HeapFree(GetProcessHeap(),0,syllables);
2599 }
2600
2601 static int gujarati_lex(WCHAR c)
2602 {
2603     switch (c)
2604     {
2605         case 0x0AB0: return lex_Ra;
2606         default:
2607             return unicode_lex(c);
2608     }
2609 }
2610
2611 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2612 {
2613     int cCount = cChars;
2614     WCHAR *input;
2615     IndicSyllable *syllables = NULL;
2616     int syllable_count = 0;
2617     BOOL modern = get_GSUB_Indic2(psa, psc);
2618
2619     if (*pcGlyphs != cChars)
2620     {
2621         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2622         return;
2623     }
2624
2625     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2626     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2627
2628     /* Step 1: Reorder within Syllables */
2629     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2630     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2631     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2632     *pcGlyphs = cCount;
2633
2634     /* Step 2: Base Form application to syllables */
2635     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2636
2637     HeapFree(GetProcessHeap(),0,input);
2638     HeapFree(GetProcessHeap(),0,syllables);
2639 }
2640
2641 static int oriya_lex(WCHAR c)
2642 {
2643     switch (c)
2644     {
2645         case 0x0B30: return lex_Ra;
2646         default:
2647             return unicode_lex(c);
2648     }
2649 }
2650
2651 static const VowelComponents Oriya_vowels[] = {
2652             {0x0B48, {0x0B47,0x0B56,0x0000}},
2653             {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2654             {0x0B4C, {0x0B47,0x0B57,0x0000}},
2655             {0x0000, {0x0000,0x0000,0x0000}}};
2656
2657 static const ConsonantComponents Oriya_consonants[] = {
2658             {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2659             {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2660             {{0x0000,0x0000,0x0000}, 0x0000}};
2661
2662 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2663 {
2664     int cCount = cChars;
2665     WCHAR *input;
2666     IndicSyllable *syllables = NULL;
2667     int syllable_count = 0;
2668     BOOL modern = get_GSUB_Indic2(psa, psc);
2669
2670     if (*pcGlyphs != cChars)
2671     {
2672         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2673         return;
2674     }
2675
2676     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2677     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2678
2679     /* Step 1: Decompose Vowels and Compose Consonents */
2680     DecomposeVowels(hdc, input,  &cCount, Oriya_vowels);
2681     ComposeConsonants(hdc, input, &cCount, Oriya_consonants);
2682     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2683
2684     /* Step 2: Reorder within Syllables */
2685     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2686     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2687     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2688     *pcGlyphs = cCount;
2689
2690     /* Step 3: Base Form application to syllables */
2691     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2692
2693     HeapFree(GetProcessHeap(),0,input);
2694     HeapFree(GetProcessHeap(),0,syllables);
2695 }
2696
2697 static int tamil_lex(WCHAR c)
2698 {
2699     return unicode_lex(c);
2700 }
2701
2702 static const VowelComponents Tamil_vowels[] = {
2703             {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2704             {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2705             {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2706             {0x0000, {0x0000,0x0000,0x0000}}};
2707
2708 static const ConsonantComponents Tamil_consonants[] = {
2709             {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2710             {{0x0000,0x0000,0x0000}, 0x0000}};
2711
2712 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2713 {
2714     int cCount = cChars;
2715     WCHAR *input;
2716     IndicSyllable *syllables = NULL;
2717     int syllable_count = 0;
2718     BOOL modern = get_GSUB_Indic2(psa, psc);
2719
2720     if (*pcGlyphs != cChars)
2721     {
2722         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2723         return;
2724     }
2725
2726     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2727     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2728
2729     /* Step 1: Decompose Vowels and Compose Consonents */
2730     DecomposeVowels(hdc, input,  &cCount, Tamil_vowels);
2731     ComposeConsonants(hdc, input, &cCount, Tamil_consonants);
2732     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2733
2734     /* Step 2: Reorder within Syllables */
2735     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2736     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2737     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2738     *pcGlyphs = cCount;
2739
2740     /* Step 3: Base Form application to syllables */
2741     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2742
2743     HeapFree(GetProcessHeap(),0,input);
2744     HeapFree(GetProcessHeap(),0,syllables);
2745 }
2746
2747 static int telugu_lex(WCHAR c)
2748 {
2749     switch (c)
2750     {
2751         case 0x0C43:
2752         case 0x0C44: return lex_Modifier;
2753         default:
2754             return unicode_lex(c);
2755     }
2756 }
2757
2758 static const VowelComponents Telugu_vowels[] = {
2759             {0x0C48, {0x0C46,0x0C56,0x0000}},
2760             {0x0000, {0x0000,0x0000,0x0000}}};
2761
2762 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2763 {
2764     int cCount = cChars;
2765     WCHAR *input;
2766     IndicSyllable *syllables = NULL;
2767     int syllable_count = 0;
2768     BOOL modern = get_GSUB_Indic2(psa, psc);
2769
2770     if (*pcGlyphs != cChars)
2771     {
2772         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2773         return;
2774     }
2775
2776     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2777     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2778
2779     /* Step 1: Decompose Vowels */
2780     DecomposeVowels(hdc, input,  &cCount, Telugu_vowels);
2781     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2782
2783     /* Step 2: Reorder within Syllables */
2784     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2785     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2786     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2787     *pcGlyphs = cCount;
2788
2789     /* Step 3: Base Form application to syllables */
2790     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2791
2792     HeapFree(GetProcessHeap(),0,input);
2793     HeapFree(GetProcessHeap(),0,syllables);
2794 }
2795
2796 static int kannada_lex(WCHAR c)
2797 {
2798     switch (c)
2799     {
2800         case 0x0CB0: return lex_Ra;
2801         default:
2802             return unicode_lex(c);
2803     }
2804 }
2805
2806 static const VowelComponents Kannada_vowels[] = {
2807             {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2808             {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2809             {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2810             {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2811             {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2812             {0x0000, {0x0000,0x0000,0x0000}}};
2813
2814 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2815 {
2816     int cCount = cChars;
2817     WCHAR *input;
2818     IndicSyllable *syllables = NULL;
2819     int syllable_count = 0;
2820     BOOL modern = get_GSUB_Indic2(psa, psc);
2821
2822     if (*pcGlyphs != cChars)
2823     {
2824         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2825         return;
2826     }
2827
2828     input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2829     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2830
2831     /* Step 1: Decompose Vowels */
2832     DecomposeVowels(hdc, input,  &cCount, Kannada_vowels);
2833     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2834
2835     /* Step 2: Reorder within Syllables */
2836     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2837     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2838     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2839     *pcGlyphs = cCount;
2840
2841     /* Step 3: Base Form application to syllables */
2842     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2843
2844     HeapFree(GetProcessHeap(),0,input);
2845     HeapFree(GetProcessHeap(),0,syllables);
2846 }
2847
2848 static int malayalam_lex(WCHAR c)
2849 {
2850     return unicode_lex(c);
2851 }
2852
2853 static const VowelComponents Malayalam_vowels[] = {
2854             {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2855             {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2856             {0x0D4C, {0x0D46,0x0D57,0x0000}},
2857             {0x0000, {0x0000,0x0000,0x0000}}};
2858
2859 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2860 {
2861     int cCount = cChars;
2862     WCHAR *input;
2863     IndicSyllable *syllables = NULL;
2864     int syllable_count = 0;
2865     BOOL modern = get_GSUB_Indic2(psa, psc);
2866
2867     if (*pcGlyphs != cChars)
2868     {
2869         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2870         return;
2871     }
2872
2873     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2874     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2875
2876     /* Step 1: Decompose Vowels */
2877     DecomposeVowels(hdc, input,  &cCount, Malayalam_vowels);
2878     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2879
2880     /* Step 2: Reorder within Syllables */
2881     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2882     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2883     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2884     *pcGlyphs = cCount;
2885
2886     /* Step 3: Base Form application to syllables */
2887     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2888
2889     HeapFree(GetProcessHeap(),0,input);
2890     HeapFree(GetProcessHeap(),0,syllables);
2891 }
2892
2893 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)
2894 {
2895     int i,k;
2896
2897     for (i = 0; i < cGlyphs; i++)
2898     {
2899         int char_index[20];
2900         int char_count = 0;
2901
2902         for (k = 0; k < cChars; k++)
2903         {
2904             if (pwLogClust[k] == i)
2905             {
2906                 char_index[char_count] = k;
2907                 char_count++;
2908             }
2909         }
2910
2911         if (char_count == 0)
2912         {
2913             FIXME("No chars in this glyph?  Must be an error\n");
2914             continue;
2915         }
2916
2917         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2918         {
2919             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2920             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2921         }
2922         else
2923             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2924     }
2925
2926     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2927     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2928 }
2929
2930 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 )
2931 {
2932     int i,k;
2933     int initGlyph, finaGlyph;
2934     INT dirR, dirL;
2935     BYTE *spaces;
2936
2937     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2938     memset(spaces,0,cGlyphs);
2939
2940     if (!psa->fLogicalOrder && psa->fRTL)
2941     {
2942         initGlyph = cGlyphs-1;
2943         finaGlyph = 0;
2944         dirR = 1;
2945         dirL = -1;
2946     }
2947     else
2948     {
2949         initGlyph = 0;
2950         finaGlyph = cGlyphs-1;
2951         dirR = -1;
2952         dirL = 1;
2953     }
2954
2955     for (i = 0; i < cGlyphs; i++)
2956     {
2957         for (k = 0; k < cChars; k++)
2958             if (pwLogClust[k] == i)
2959             {
2960                 if (pwcChars[k] == 0x0020)
2961                     spaces[i] = 1;
2962             }
2963     }
2964
2965     for (i = 0; i < cGlyphs; i++)
2966     {
2967         int char_index[20];
2968         int char_count = 0;
2969         BOOL isInit, isFinal;
2970
2971         for (k = 0; k < cChars; k++)
2972         {
2973             if (pwLogClust[k] == i)
2974             {
2975                 char_index[char_count] = k;
2976                 char_count++;
2977             }
2978         }
2979
2980         isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2981         isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2982
2983         if (char_count == 0)
2984         {
2985             FIXME("No chars in this glyph?  Must be an error\n");
2986             continue;
2987         }
2988
2989         if (char_count == 1)
2990         {
2991             if (pwcChars[char_index[0]] == 0x0020)  /* space */
2992             {
2993                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2994                 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2995             }
2996             else if (pwcChars[char_index[0]] == 0x0640)  /* kashida */
2997                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2998             else if (pwcChars[char_index[0]] == 0x0633)  /* SEEN */
2999             {
3000                 if (!isInit && !isFinal)
3001                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3002                 else if (isInit)
3003                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3004                 else
3005                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3006             }
3007             else if (!isInit)
3008             {
3009                 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3010                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3011                 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3012                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3013                 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3014                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3015                 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3016                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3017                 else
3018                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3019             }
3020             else if (!isInit && !isFinal)
3021                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3022             else
3023                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3024         }
3025         else if (char_count == 2)
3026         {
3027             if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) ||  (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3028                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3029             else if (!isInit)
3030                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3031             else
3032                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3033         }
3034         else if (!isInit && !isFinal)
3035             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3036         else
3037             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3038     }
3039
3040     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3041     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3042     HeapFree(GetProcessHeap(),0,spaces);
3043 }
3044
3045 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 )
3046 {
3047     int i,k;
3048     int finaGlyph;
3049     INT dirL;
3050     BYTE *spaces;
3051
3052     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3053     memset(spaces,0,cGlyphs);
3054
3055     if (!psa->fLogicalOrder && psa->fRTL)
3056     {
3057         finaGlyph = 0;
3058         dirL = -1;
3059     }
3060     else
3061     {
3062         finaGlyph = cGlyphs-1;
3063         dirL = 1;
3064     }
3065
3066     for (i = 0; i < cGlyphs; i++)
3067     {
3068         for (k = 0; k < cChars; k++)
3069             if (pwLogClust[k] == i)
3070             {
3071                 if (pwcChars[k] == 0x0020)
3072                     spaces[i] = 1;
3073             }
3074     }
3075
3076     for (i = 0; i < cGlyphs; i++)
3077     {
3078         int char_index[20];
3079         int char_count = 0;
3080
3081         for (k = 0; k < cChars; k++)
3082         {
3083             if (pwLogClust[k] == i)
3084             {
3085                 char_index[char_count] = k;
3086                 char_count++;
3087             }
3088         }
3089
3090         if (char_count == 0)
3091         {
3092             FIXME("No chars in this glyph?  Must be an error\n");
3093             continue;
3094         }
3095
3096         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
3097         {
3098             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3099             pCharProp[char_index[0]].fCanGlyphAlone = 1;
3100         }
3101         else if (i == finaGlyph)
3102             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3103         else
3104             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3105     }
3106
3107     HeapFree(GetProcessHeap(),0,spaces);
3108     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3109     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3110
3111     /* Do not allow justification between marks and their base */
3112     for (i = 0; i < cGlyphs; i++)
3113     {
3114         if (!pGlyphProp[i].sva.fClusterStart)
3115             pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3116     }
3117 }
3118
3119 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)
3120 {
3121     int i,k;
3122
3123     for (i = 0; i < cGlyphs; i++)
3124     {
3125         int char_index[20];
3126         int char_count = 0;
3127
3128         for (k = 0; k < cChars; k++)
3129         {
3130             if (pwLogClust[k] == i)
3131             {
3132                 char_index[char_count] = k;
3133                 char_count++;
3134             }
3135         }
3136
3137         if (char_count == 0)
3138         {
3139             FIXME("No chars in this glyph?  Must be an error\n");
3140             continue;
3141         }
3142
3143         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
3144         {
3145             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3146             pCharProp[char_index[0]].fCanGlyphAlone = 1;
3147         }
3148         else
3149             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3150     }
3151     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3152     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3153 }
3154
3155 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)
3156 {
3157     int i,k;
3158
3159     for (i = 0; i < cGlyphs; i++)
3160     {
3161         int char_index[20];
3162         int char_count = 0;
3163
3164         for (k = 0; k < cChars; k++)
3165         {
3166             if (pwLogClust[k] == i)
3167             {
3168                 char_index[char_count] = k;
3169                 char_count++;
3170             }
3171         }
3172
3173         if (char_count == 0)
3174         {
3175             FIXME("No chars in this glyph?  Must be an error\n");
3176             continue;
3177         }
3178
3179         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
3180         {
3181             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3182             pCharProp[char_index[0]].fCanGlyphAlone = 1;
3183         }
3184         else
3185             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3186     }
3187     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3188     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3189
3190     /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3191     for (i = 0; i < cGlyphs; i++)
3192     {
3193         if (!pGlyphProp[i].sva.fClusterStart)
3194         {
3195             pGlyphProp[i].sva.fDiacritic = 0;
3196             pGlyphProp[i].sva.fZeroWidth = 0;
3197         }
3198     }
3199 }
3200
3201 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)
3202 {
3203     int i,k;
3204
3205     for (i = 0; i < cGlyphs; i++)
3206     {
3207         int char_index[20];
3208         int char_count = 0;
3209
3210         for (k = 0; k < cChars; k++)
3211         {
3212             if (pwLogClust[k] == i)
3213             {
3214                 char_index[char_count] = k;
3215                 char_count++;
3216             }
3217         }
3218
3219         if (char_count == 0)
3220         {
3221             FIXME("No chars in this glyph?  Must be an error\n");
3222             continue;
3223         }
3224
3225         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
3226         {
3227             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3228             pCharProp[char_index[0]].fCanGlyphAlone = 1;
3229         }
3230         else
3231             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3232
3233         pGlyphProp[i].sva.fClusterStart = 0;
3234         for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3235             switch (lexical(pwcChars[char_index[k]]))
3236             {
3237                 case lex_Matra_pre:
3238                 case lex_Matra_post:
3239                 case lex_Matra_above:
3240                 case lex_Matra_below:
3241                 case lex_Modifier:
3242                     break;
3243                 default:
3244                     pGlyphProp[i].sva.fClusterStart = 1;
3245                     break;
3246             }
3247     }
3248     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3249 }
3250
3251 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 )
3252 {
3253     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3254 }
3255
3256 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 )
3257 {
3258     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3259 }
3260
3261 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 )
3262 {
3263     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3264 }
3265
3266 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 )
3267 {
3268     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3269 }
3270
3271 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 )
3272 {
3273     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3274 }
3275
3276 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 )
3277 {
3278     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3279 }
3280
3281 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 )
3282 {
3283     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3284 }
3285
3286 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 )
3287 {
3288     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3289 }
3290
3291 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 )
3292 {
3293     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3294 }
3295
3296 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)
3297 {
3298     if (ShapingData[psa->eScript].charGlyphPropProc)
3299         ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3300     else
3301         ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3302 }
3303
3304 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3305 {
3306     if (ShapingData[psa->eScript].contextProc)
3307         ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3308 }
3309
3310 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)
3311 {
3312     int i;
3313     INT dirL;
3314
3315     if (!rpRangeProperties)
3316         return;
3317
3318     if (!psc->GSUB_Table)
3319         psc->GSUB_Table = load_gsub_table(hdc);
3320
3321     if (!psc->GSUB_Table)
3322         return;
3323
3324     if (!psa->fLogicalOrder && psa->fRTL)
3325         dirL = -1;
3326     else
3327         dirL = 1;
3328
3329     for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3330     {
3331         if (rpRangeProperties->potfRecords[i].lParameter > 0)
3332         apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3333     }
3334 }
3335
3336 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3337 {
3338 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3339 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3340
3341     SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3342 }
3343
3344 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3345 {
3346     const GSUB_Feature *feature;
3347     int i;
3348
3349     if (!ShapingData[psa->eScript].requiredFeatures)
3350         return S_OK;
3351
3352     if (!psc->GSUB_Table)
3353         psc->GSUB_Table = load_gsub_table(hdc);
3354
3355     /* we need to have at least one of the required features */
3356     i = 0;
3357     while (ShapingData[psa->eScript].requiredFeatures[i])
3358     {
3359         feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3360         if (feature)
3361             return S_OK;
3362         i++;
3363     }
3364
3365     return USP_E_SCRIPT_NOT_IN_FONT;
3366 }