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