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