usp10: Fix memory leaks.
[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         int top_logclust = 0;
1363
1364         if (changeCount > 0)
1365         {
1366             if (write_dir > 0)
1367                 target_glyph = nextIndex - changeCount;
1368             else
1369                 target_glyph = nextIndex + (changeCount + 1);
1370         }
1371
1372         seeking_glyph = target_glyph;
1373         for (i = 0; i < chars; i++)
1374             if (pwLogClust[i] > top_logclust)
1375                 top_logclust = pwLogClust[i];
1376
1377         do {
1378             if (write_dir > 0)
1379                 for (i = 0; i < chars; i++)
1380                 {
1381                     if (pwLogClust[i] == seeking_glyph)
1382                     {
1383                         target_index = i;
1384                         break;
1385                     }
1386                 }
1387             else
1388                 for (i = chars - 1; i >= 0; i--)
1389                 {
1390                     if (pwLogClust[i] == seeking_glyph)
1391                     {
1392                         target_index = i;
1393                         break;
1394                     }
1395                 }
1396             if (target_index == -1)
1397                 seeking_glyph ++;
1398         }
1399         while (target_index == -1 && seeking_glyph <= top_logclust);
1400
1401         if (target_index == -1)
1402         {
1403             ERR("Unable to find target glyph\n");
1404             return;
1405         }
1406
1407         if (changeCount < 0)
1408         {
1409             /* merge glyphs */
1410             for(i = target_index; i < chars && i >= 0; i+=write_dir)
1411             {
1412                 if (pwLogClust[i] == target_glyph)
1413                     continue;
1414                 if(pwLogClust[i] == replacing_glyph)
1415                     pwLogClust[i] = target_glyph;
1416                 else
1417                 {
1418                     changed--;
1419                     if (changed >= changeCount)
1420                     {
1421                         replacing_glyph = pwLogClust[i];
1422                         pwLogClust[i] = target_glyph;
1423                     }
1424                     else
1425                         break;
1426                 }
1427             }
1428
1429             /* renumber trailing indexes*/
1430             for(i = target_index; i < chars && i >= 0; i+=write_dir)
1431             {
1432                 if (pwLogClust[i] != target_glyph)
1433                     pwLogClust[i] += changeCount;
1434             }
1435         }
1436         else
1437         {
1438             for(i = target_index; i < chars && i >= 0; i+=write_dir)
1439                     pwLogClust[i] += changeCount;
1440         }
1441     }
1442 }
1443
1444 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 )
1445 {
1446     if (psc->GSUB_Table)
1447     {
1448         const GSUB_Feature *feature;
1449         const GSUB_LookupList *lookup;
1450         const GSUB_Header *header = psc->GSUB_Table;
1451         int lookup_index, lookup_count;
1452
1453         feature = load_GSUB_feature(hdc, psa, psc, feat);
1454         if (!feature)
1455             return GSUB_E_NOFEATURE;
1456
1457         TRACE("applying feature %s\n",debugstr_an(feat,4));
1458         lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1459         lookup_count = GET_BE_WORD(feature->LookupCount);
1460         TRACE("%i lookups\n", lookup_count);
1461         for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1462         {
1463             int i;
1464
1465             if (write_dir > 0)
1466                 i = 0;
1467             else
1468                 i = *pcGlyphs-1;
1469             TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1470             while(i < *pcGlyphs && i >= 0)
1471             {
1472                 INT nextIndex;
1473                 INT prevCount = *pcGlyphs;
1474
1475                 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1476                 if (*pcGlyphs != prevCount)
1477                 {
1478                     UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1479                     i = nextIndex;
1480                 }
1481                 else
1482                     i+=write_dir;
1483             }
1484         }
1485         return *pcGlyphs;
1486     }
1487     return GSUB_E_NOFEATURE;
1488 }
1489
1490 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1491 {
1492     return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1493 }
1494
1495 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1496 {
1497     if (i + delta < 0)
1498         return 0;
1499     if ( i+ delta >= cchLen)
1500         return 0;
1501
1502     i += delta;
1503
1504     return chars[i];
1505 }
1506
1507 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1508 {
1509     if (i + delta < 0)
1510     {
1511         if (psa->fLinkBefore)
1512             return jtR;
1513         else
1514             return jtU;
1515     }
1516     if ( i+ delta >= cchLen)
1517     {
1518         if (psa->fLinkAfter)
1519             return jtL;
1520         else
1521             return jtU;
1522     }
1523
1524     i += delta;
1525
1526     if (context_type[i] == jtT)
1527         return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1528     else
1529         return context_type[i];
1530 }
1531
1532 static inline BOOL right_join_causing(CHAR joining_type)
1533 {
1534     return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1535 }
1536
1537 static inline BOOL left_join_causing(CHAR joining_type)
1538 {
1539     return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1540 }
1541
1542 static inline BOOL word_break_causing(WCHAR chr)
1543 {
1544     /* we are working within a string of characters already guareented to
1545        be within one script, Syriac, so we do not worry about any character
1546        other than the space character outside of that range */
1547     return (chr == 0 || chr == 0x20 );
1548 }
1549
1550 /*
1551  * ContextualShape_Arabic
1552  */
1553 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1554 {
1555     CHAR *context_type;
1556     INT *context_shape;
1557     INT dirR, dirL;
1558     int i;
1559
1560     if (*pcGlyphs != cChars)
1561     {
1562         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1563         return;
1564     }
1565
1566     if (!psa->fLogicalOrder && psa->fRTL)
1567     {
1568         dirR = 1;
1569         dirL = -1;
1570     }
1571     else
1572     {
1573         dirR = -1;
1574         dirL = 1;
1575     }
1576
1577     if (!psc->GSUB_Table)
1578         psc->GSUB_Table = load_gsub_table(hdc);
1579
1580     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1581     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1582
1583     for (i = 0; i < cChars; i++)
1584         context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1585
1586     for (i = 0; i < cChars; i++)
1587     {
1588         if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1589             context_shape[i] = Xr;
1590         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1591             context_shape[i] = Xl;
1592         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)))
1593             context_shape[i] = Xm;
1594         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1595             context_shape[i] = Xr;
1596         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1597             context_shape[i] = Xl;
1598         else
1599             context_shape[i] = Xn;
1600     }
1601
1602     /* Contextual Shaping */
1603     i = 0;
1604     while(i < *pcGlyphs)
1605     {
1606         BOOL shaped = FALSE;
1607
1608         if (psc->GSUB_Table)
1609         {
1610             INT nextIndex;
1611             INT prevCount = *pcGlyphs;
1612             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1613             if (nextIndex > GSUB_E_NOGLYPH)
1614             {
1615                 i = nextIndex;
1616                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1617             }
1618             shaped = (nextIndex > GSUB_E_NOGLYPH);
1619         }
1620
1621         if (!shaped)
1622         {
1623             if (context_shape[i] == Xn)
1624             {
1625                 WORD newGlyph = pwOutGlyphs[i];
1626                 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1627                 {
1628                     /* fall back to presentation form B */
1629                     WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1630                     if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1631                         pwOutGlyphs[i] = newGlyph;
1632                 }
1633             }
1634             i++;
1635         }
1636     }
1637
1638     HeapFree(GetProcessHeap(),0,context_shape);
1639     HeapFree(GetProcessHeap(),0,context_type);
1640 }
1641
1642 /*
1643  * ContextualShape_Syriac
1644  */
1645
1646 #define ALAPH 0x710
1647 #define DALATH 0x715
1648 #define RISH 0x72A
1649
1650 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1651 {
1652     CHAR *context_type;
1653     INT *context_shape;
1654     INT dirR, dirL;
1655     int i;
1656
1657     if (*pcGlyphs != cChars)
1658     {
1659         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1660         return;
1661     }
1662
1663     if (!psa->fLogicalOrder && psa->fRTL)
1664     {
1665         dirR = 1;
1666         dirL = -1;
1667     }
1668     else
1669     {
1670         dirR = -1;
1671         dirL = 1;
1672     }
1673
1674     if (!psc->GSUB_Table)
1675         psc->GSUB_Table = load_gsub_table(hdc);
1676
1677     if (!psc->GSUB_Table)
1678         return;
1679
1680     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1681     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1682
1683     for (i = 0; i < cChars; i++)
1684         context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1685
1686     for (i = 0; i < cChars; i++)
1687     {
1688         if (pwcChars[i] == ALAPH)
1689         {
1690             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1691
1692             if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1693             context_shape[i] = Afj;
1694             else if ( rchar != DALATH && rchar != RISH &&
1695 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1696 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1697             context_shape[i] = Afn;
1698             else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1699             context_shape[i] = Afx;
1700             else
1701             context_shape[i] = Xn;
1702         }
1703         else if (context_type[i] == jtR &&
1704 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1705             context_shape[i] = Xr;
1706         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1707             context_shape[i] = Xl;
1708         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)))
1709             context_shape[i] = Xm;
1710         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1711             context_shape[i] = Xr;
1712         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1713             context_shape[i] = Xl;
1714         else
1715             context_shape[i] = Xn;
1716     }
1717
1718     /* Contextual Shaping */
1719     i = 0;
1720     while(i < *pcGlyphs)
1721     {
1722         INT nextIndex;
1723         INT prevCount = *pcGlyphs;
1724         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1725         if (nextIndex > GSUB_E_NOGLYPH)
1726         {
1727             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1728             i = nextIndex;
1729         }
1730         else
1731             i++;
1732     }
1733
1734     HeapFree(GetProcessHeap(),0,context_shape);
1735     HeapFree(GetProcessHeap(),0,context_type);
1736 }
1737
1738 /*
1739  * ContextualShape_Phags_pa
1740  */
1741
1742 #define phags_pa_CANDRABINDU  0xA873
1743 #define phags_pa_START 0xA840
1744 #define phags_pa_END  0xA87F
1745
1746 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1747 {
1748     INT *context_shape;
1749     INT dirR, dirL;
1750     int i;
1751
1752     if (*pcGlyphs != cChars)
1753     {
1754         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1755         return;
1756     }
1757
1758     if (!psa->fLogicalOrder && psa->fRTL)
1759     {
1760         dirR = 1;
1761         dirL = -1;
1762     }
1763     else
1764     {
1765         dirR = -1;
1766         dirL = 1;
1767     }
1768
1769     if (!psc->GSUB_Table)
1770         psc->GSUB_Table = load_gsub_table(hdc);
1771
1772     if (!psc->GSUB_Table)
1773         return;
1774
1775     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1776
1777     for (i = 0; i < cChars; i++)
1778     {
1779         if (pwcChars[i] >= phags_pa_START && pwcChars[i] <=  phags_pa_END)
1780         {
1781             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1782             WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1783             BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <=  phags_pa_END);
1784             BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <=  phags_pa_END);
1785
1786             if (jrchar && jlchar)
1787                 context_shape[i] = Xm;
1788             else if (jrchar)
1789                 context_shape[i] = Xr;
1790             else if (jlchar)
1791                 context_shape[i] = Xl;
1792             else
1793                 context_shape[i] = Xn;
1794         }
1795         else
1796             context_shape[i] = -1;
1797     }
1798
1799     /* Contextual Shaping */
1800     i = 0;
1801     while(i < *pcGlyphs)
1802     {
1803         if (context_shape[i] >= 0)
1804         {
1805             INT nextIndex;
1806             INT prevCount = *pcGlyphs;
1807             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1808             if (nextIndex > GSUB_E_NOGLYPH)
1809             {
1810                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1811                 i = nextIndex;
1812             }
1813             else
1814                 i++;
1815         }
1816         else
1817             i++;
1818     }
1819
1820     HeapFree(GetProcessHeap(),0,context_shape);
1821 }
1822
1823 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1824 {
1825     int i;
1826
1827     /* Replace */
1828     pwOutChars[cWalk] = replacements[0];
1829     cWalk=cWalk+1;
1830
1831     /* Insert */
1832     for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1833     {
1834         int j;
1835         for (j = *pcChars; j > cWalk; j--)
1836             pwOutChars[j] = pwOutChars[j-1];
1837         *pcChars= *pcChars+1;
1838         pwOutChars[cWalk] = replacements[i];
1839         cWalk = cWalk+1;
1840     }
1841 }
1842
1843 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1844 {
1845     int i;
1846     int cWalk;
1847
1848     for (cWalk = 0; cWalk < *pcChars; cWalk++)
1849     {
1850         for (i = 0; vowels[i].base != 0x0; i++)
1851         {
1852             if (pwOutChars[cWalk] == vowels[i].base)
1853             {
1854                 int o = 0;
1855                 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1856                 if (vowels[i].parts[1]) { cWalk++; o++; }
1857                 if (vowels[i].parts[2]) { cWalk++; o++; }
1858                 UpdateClusters(cWalk, o, 1,  cChars,  pwLogClust);
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, cChars);
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, cChars);
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             {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2629             {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2630             {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2631             {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2632             {{0x0000,0x0000,0x0000}, 0x0000}};
2633
2634 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2635 {
2636     int cCount = cChars;
2637     WCHAR *input;
2638     IndicSyllable *syllables = NULL;
2639     int syllable_count = 0;
2640     BOOL modern = get_GSUB_Indic2(psa, psc);
2641
2642     if (*pcGlyphs != cChars)
2643     {
2644         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2645         return;
2646     }
2647
2648     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2649     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2650
2651     /* Step 1: Compose Consonents */
2652     ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2653     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2654
2655     /* Step 2: Reorder within Syllables */
2656     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2657     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2658     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2659     *pcGlyphs = cCount;
2660
2661     /* Step 3: Base Form application to syllables */
2662     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2663
2664     HeapFree(GetProcessHeap(),0,input);
2665     HeapFree(GetProcessHeap(),0,syllables);
2666 }
2667
2668 static int gujarati_lex(WCHAR c)
2669 {
2670     switch (c)
2671     {
2672         case 0x0AB0: return lex_Ra;
2673         default:
2674             return unicode_lex(c);
2675     }
2676 }
2677
2678 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2679 {
2680     int cCount = cChars;
2681     WCHAR *input;
2682     IndicSyllable *syllables = NULL;
2683     int syllable_count = 0;
2684     BOOL modern = get_GSUB_Indic2(psa, psc);
2685
2686     if (*pcGlyphs != cChars)
2687     {
2688         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2689         return;
2690     }
2691
2692     input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2693     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2694
2695     /* Step 1: Reorder within Syllables */
2696     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2697     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2698     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2699     *pcGlyphs = cCount;
2700
2701     /* Step 2: Base Form application to syllables */
2702     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2703
2704     HeapFree(GetProcessHeap(),0,input);
2705     HeapFree(GetProcessHeap(),0,syllables);
2706 }
2707
2708 static int oriya_lex(WCHAR c)
2709 {
2710     switch (c)
2711     {
2712         case 0x0B30: return lex_Ra;
2713         default:
2714             return unicode_lex(c);
2715     }
2716 }
2717
2718 static const VowelComponents Oriya_vowels[] = {
2719             {0x0B48, {0x0B47,0x0B56,0x0000}},
2720             {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2721             {0x0B4C, {0x0B47,0x0B57,0x0000}},
2722             {0x0000, {0x0000,0x0000,0x0000}}};
2723
2724 static const ConsonantComponents Oriya_consonants[] = {
2725             {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2726             {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2727             {{0x0000,0x0000,0x0000}, 0x0000}};
2728
2729 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2730 {
2731     int cCount = cChars;
2732     WCHAR *input;
2733     IndicSyllable *syllables = NULL;
2734     int syllable_count = 0;
2735     BOOL modern = get_GSUB_Indic2(psa, psc);
2736
2737     if (*pcGlyphs != cChars)
2738     {
2739         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2740         return;
2741     }
2742
2743     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2744     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2745
2746     /* Step 1: Decompose Vowels and Compose Consonents */
2747     DecomposeVowels(hdc, input,  &cCount, Oriya_vowels, pwLogClust, cChars);
2748     ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2749     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2750
2751     /* Step 2: Reorder within Syllables */
2752     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2753     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2754     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2755     *pcGlyphs = cCount;
2756
2757     /* Step 3: Base Form application to syllables */
2758     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2759
2760     HeapFree(GetProcessHeap(),0,input);
2761     HeapFree(GetProcessHeap(),0,syllables);
2762 }
2763
2764 static int tamil_lex(WCHAR c)
2765 {
2766     return unicode_lex(c);
2767 }
2768
2769 static const VowelComponents Tamil_vowels[] = {
2770             {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2771             {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2772             {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2773             {0x0000, {0x0000,0x0000,0x0000}}};
2774
2775 static const ConsonantComponents Tamil_consonants[] = {
2776             {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2777             {{0x0000,0x0000,0x0000}, 0x0000}};
2778
2779 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2780 {
2781     int cCount = cChars;
2782     WCHAR *input;
2783     IndicSyllable *syllables = NULL;
2784     int syllable_count = 0;
2785     BOOL modern = get_GSUB_Indic2(psa, psc);
2786
2787     if (*pcGlyphs != cChars)
2788     {
2789         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2790         return;
2791     }
2792
2793     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2794     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2795
2796     /* Step 1: Decompose Vowels and Compose Consonents */
2797     DecomposeVowels(hdc, input,  &cCount, Tamil_vowels, pwLogClust, cChars);
2798     ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2799     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2800
2801     /* Step 2: Reorder within Syllables */
2802     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2803     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2804     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2805     *pcGlyphs = cCount;
2806
2807     /* Step 3: Base Form application to syllables */
2808     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2809
2810     HeapFree(GetProcessHeap(),0,input);
2811     HeapFree(GetProcessHeap(),0,syllables);
2812 }
2813
2814 static int telugu_lex(WCHAR c)
2815 {
2816     switch (c)
2817     {
2818         case 0x0C43:
2819         case 0x0C44: return lex_Modifier;
2820         default:
2821             return unicode_lex(c);
2822     }
2823 }
2824
2825 static const VowelComponents Telugu_vowels[] = {
2826             {0x0C48, {0x0C46,0x0C56,0x0000}},
2827             {0x0000, {0x0000,0x0000,0x0000}}};
2828
2829 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2830 {
2831     int cCount = cChars;
2832     WCHAR *input;
2833     IndicSyllable *syllables = NULL;
2834     int syllable_count = 0;
2835     BOOL modern = get_GSUB_Indic2(psa, psc);
2836
2837     if (*pcGlyphs != cChars)
2838     {
2839         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2840         return;
2841     }
2842
2843     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2844     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2845
2846     /* Step 1: Decompose Vowels */
2847     DecomposeVowels(hdc, input,  &cCount, Telugu_vowels, pwLogClust, cChars);
2848     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2849
2850     /* Step 2: Reorder within Syllables */
2851     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2852     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2853     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2854     *pcGlyphs = cCount;
2855
2856     /* Step 3: Base Form application to syllables */
2857     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2858
2859     HeapFree(GetProcessHeap(),0,input);
2860     HeapFree(GetProcessHeap(),0,syllables);
2861 }
2862
2863 static int kannada_lex(WCHAR c)
2864 {
2865     switch (c)
2866     {
2867         case 0x0CB0: return lex_Ra;
2868         default:
2869             return unicode_lex(c);
2870     }
2871 }
2872
2873 static const VowelComponents Kannada_vowels[] = {
2874             {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2875             {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2876             {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2877             {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2878             {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2879             {0x0000, {0x0000,0x0000,0x0000}}};
2880
2881 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2882 {
2883     int cCount = cChars;
2884     WCHAR *input;
2885     IndicSyllable *syllables = NULL;
2886     int syllable_count = 0;
2887     BOOL modern = get_GSUB_Indic2(psa, psc);
2888
2889     if (*pcGlyphs != cChars)
2890     {
2891         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2892         return;
2893     }
2894
2895     input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2896     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2897
2898     /* Step 1: Decompose Vowels */
2899     DecomposeVowels(hdc, input,  &cCount, Kannada_vowels, pwLogClust, cChars);
2900     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2901
2902     /* Step 2: Reorder within Syllables */
2903     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2904     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2905     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2906     *pcGlyphs = cCount;
2907
2908     /* Step 3: Base Form application to syllables */
2909     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2910
2911     HeapFree(GetProcessHeap(),0,input);
2912     HeapFree(GetProcessHeap(),0,syllables);
2913 }
2914
2915 static int malayalam_lex(WCHAR c)
2916 {
2917     return unicode_lex(c);
2918 }
2919
2920 static const VowelComponents Malayalam_vowels[] = {
2921             {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2922             {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2923             {0x0D4C, {0x0D46,0x0D57,0x0000}},
2924             {0x0000, {0x0000,0x0000,0x0000}}};
2925
2926 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2927 {
2928     int cCount = cChars;
2929     WCHAR *input;
2930     IndicSyllable *syllables = NULL;
2931     int syllable_count = 0;
2932     BOOL modern = get_GSUB_Indic2(psa, psc);
2933
2934     if (*pcGlyphs != cChars)
2935     {
2936         ERR("Number of Glyphs and Chars need to match at the beginning\n");
2937         return;
2938     }
2939
2940     input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2941     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2942
2943     /* Step 1: Decompose Vowels */
2944     DecomposeVowels(hdc, input,  &cCount, Malayalam_vowels, pwLogClust, cChars);
2945     TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2946
2947     /* Step 2: Reorder within Syllables */
2948     Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2949     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2950     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2951     *pcGlyphs = cCount;
2952
2953     /* Step 3: Base Form application to syllables */
2954     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2955
2956     HeapFree(GetProcessHeap(),0,input);
2957     HeapFree(GetProcessHeap(),0,syllables);
2958 }
2959
2960 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)
2961 {
2962     int i,k;
2963
2964     for (i = 0; i < cGlyphs; i++)
2965     {
2966         int char_index[20];
2967         int char_count = 0;
2968
2969         for (k = 0; k < cChars; k++)
2970         {
2971             if (pwLogClust[k] == i)
2972             {
2973                 char_index[char_count] = k;
2974                 char_count++;
2975             }
2976         }
2977
2978         if (char_count == 0)
2979             continue;
2980
2981         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
2982         {
2983             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2984             pCharProp[char_index[0]].fCanGlyphAlone = 1;
2985         }
2986         else
2987             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2988     }
2989
2990     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2991     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2992 }
2993
2994 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 )
2995 {
2996     int i,k;
2997     int initGlyph, finaGlyph;
2998     INT dirR, dirL;
2999     BYTE *spaces;
3000
3001     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3002     memset(spaces,0,cGlyphs);
3003
3004     if (!psa->fLogicalOrder && psa->fRTL)
3005     {
3006         initGlyph = cGlyphs-1;
3007         finaGlyph = 0;
3008         dirR = 1;
3009         dirL = -1;
3010     }
3011     else
3012     {
3013         initGlyph = 0;
3014         finaGlyph = cGlyphs-1;
3015         dirR = -1;
3016         dirL = 1;
3017     }
3018
3019     for (i = 0; i < cGlyphs; i++)
3020     {
3021         for (k = 0; k < cChars; k++)
3022             if (pwLogClust[k] == i)
3023             {
3024                 if (pwcChars[k] == 0x0020)
3025                     spaces[i] = 1;
3026             }
3027     }
3028
3029     for (i = 0; i < cGlyphs; i++)
3030     {
3031         int char_index[20];
3032         int char_count = 0;
3033         BOOL isInit, isFinal;
3034
3035         for (k = 0; k < cChars; k++)
3036         {
3037             if (pwLogClust[k] == i)
3038             {
3039                 char_index[char_count] = k;
3040                 char_count++;
3041             }
3042         }
3043
3044         isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3045         isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3046
3047         if (char_count == 0)
3048             continue;
3049
3050         if (char_count == 1)
3051         {
3052             if (pwcChars[char_index[0]] == 0x0020)  /* space */
3053             {
3054                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3055                 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3056             }
3057             else if (pwcChars[char_index[0]] == 0x0640)  /* kashida */
3058                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3059             else if (pwcChars[char_index[0]] == 0x0633)  /* SEEN */
3060             {
3061                 if (!isInit && !isFinal)
3062                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3063                 else if (isInit)
3064                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3065                 else
3066                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3067             }
3068             else if (!isInit)
3069             {
3070                 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3071                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3072                 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3073                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3074                 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3075                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3076                 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3077                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3078                 else
3079                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3080             }
3081             else if (!isInit && !isFinal)
3082                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3083             else
3084                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3085         }
3086         else if (char_count == 2)
3087         {
3088             if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) ||  (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3089                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3090             else if (!isInit)
3091                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3092             else
3093                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3094         }
3095         else if (!isInit && !isFinal)
3096             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3097         else
3098             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3099     }
3100
3101     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3102     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3103     HeapFree(GetProcessHeap(),0,spaces);
3104 }
3105
3106 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 )
3107 {
3108     int i,k;
3109     int finaGlyph;
3110     INT dirL;
3111     BYTE *spaces;
3112
3113     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3114     memset(spaces,0,cGlyphs);
3115
3116     if (!psa->fLogicalOrder && psa->fRTL)
3117     {
3118         finaGlyph = 0;
3119         dirL = -1;
3120     }
3121     else
3122     {
3123         finaGlyph = cGlyphs-1;
3124         dirL = 1;
3125     }
3126
3127     for (i = 0; i < cGlyphs; i++)
3128     {
3129         for (k = 0; k < cChars; k++)
3130             if (pwLogClust[k] == i)
3131             {
3132                 if (pwcChars[k] == 0x0020)
3133                     spaces[i] = 1;
3134             }
3135     }
3136
3137     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3138
3139     for (i = 0; i < cGlyphs; i++)
3140     {
3141         int char_index[20];
3142         int char_count = 0;
3143
3144         for (k = 0; k < cChars; k++)
3145         {
3146             if (pwLogClust[k] == i)
3147             {
3148                 char_index[char_count] = k;
3149                 char_count++;
3150             }
3151         }
3152
3153         if (char_count == 0)
3154             continue;
3155
3156         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
3157         {
3158             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3159             pCharProp[char_index[0]].fCanGlyphAlone = 1;
3160         }
3161         else if (i == finaGlyph)
3162             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3163         else
3164             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3165
3166         /* handle Thai SARA AM (U+0E33) differently than GDEF */
3167         if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3168             pGlyphProp[i].sva.fClusterStart = 0;
3169     }
3170
3171     HeapFree(GetProcessHeap(),0,spaces);
3172     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3173
3174     /* Do not allow justification between marks and their base */
3175     for (i = 0; i < cGlyphs; i++)
3176     {
3177         if (!pGlyphProp[i].sva.fClusterStart)
3178             pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3179     }
3180 }
3181
3182 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)
3183 {
3184     int i,k;
3185
3186     for (i = 0; i < cGlyphs; i++)
3187     {
3188         int char_index[20];
3189         int char_count = 0;
3190
3191         for (k = 0; k < cChars; k++)
3192         {
3193             if (pwLogClust[k] == i)
3194             {
3195                 char_index[char_count] = k;
3196                 char_count++;
3197             }
3198         }
3199
3200         if (char_count == 0)
3201             continue;
3202
3203         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
3204         {
3205             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3206             pCharProp[char_index[0]].fCanGlyphAlone = 1;
3207         }
3208         else
3209             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3210     }
3211     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3212     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3213 }
3214
3215 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)
3216 {
3217     int i,k;
3218
3219     for (i = 0; i < cGlyphs; i++)
3220     {
3221         int char_index[20];
3222         int char_count = 0;
3223
3224         for (k = 0; k < cChars; k++)
3225         {
3226             if (pwLogClust[k] == i)
3227             {
3228                 char_index[char_count] = k;
3229                 char_count++;
3230             }
3231         }
3232
3233         if (char_count == 0)
3234             continue;
3235
3236         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
3237         {
3238             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3239             pCharProp[char_index[0]].fCanGlyphAlone = 1;
3240         }
3241         else
3242             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3243     }
3244     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3245     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3246
3247     /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3248     for (i = 0; i < cGlyphs; i++)
3249     {
3250         if (!pGlyphProp[i].sva.fClusterStart)
3251         {
3252             pGlyphProp[i].sva.fDiacritic = 0;
3253             pGlyphProp[i].sva.fZeroWidth = 0;
3254         }
3255     }
3256 }
3257
3258 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, BOOL use_syllables)
3259 {
3260     int i,k;
3261
3262     GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3263     for (i = 0; i < cGlyphs; i++)
3264     {
3265         int char_index[20];
3266         int char_count = 0;
3267
3268         for (k = 0; k < cChars; k++)
3269         {
3270             if (pwLogClust[k] == i)
3271             {
3272                 char_index[char_count] = k;
3273                 char_count++;
3274             }
3275         }
3276
3277         /* Indic scripts do not set fDiacritic or fZeroWidth */
3278         pGlyphProp[i].sva.fDiacritic = FALSE;
3279         pGlyphProp[i].sva.fZeroWidth = FALSE;
3280
3281         if (char_count == 0)
3282             continue;
3283
3284         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
3285         {
3286             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3287             pCharProp[char_index[0]].fCanGlyphAlone = 1;
3288         }
3289         else
3290             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3291
3292         pGlyphProp[i].sva.fClusterStart = 0;
3293         for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3294             switch (lexical(pwcChars[char_index[k]]))
3295             {
3296                 case lex_Matra_pre:
3297                 case lex_Matra_post:
3298                 case lex_Matra_above:
3299                 case lex_Matra_below:
3300                 case lex_Modifier:
3301                 case lex_Halant:
3302                     break;
3303                 case lex_ZWJ:
3304                 case lex_ZWNJ:
3305                     k = char_count;
3306                     break;
3307                 default:
3308                     pGlyphProp[i].sva.fClusterStart = 1;
3309                     break;
3310             }
3311     }
3312
3313     if (use_syllables)
3314     {
3315         IndicSyllable *syllables = NULL;
3316         int syllable_count = 0;
3317         BOOL modern = get_GSUB_Indic2(psa, psc);
3318
3319         Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3320
3321         for (i = 0; i < syllable_count; i++)
3322         {
3323             int j;
3324             WORD g = pwLogClust[syllables[i].start];
3325             for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3326             {
3327                 if (pwLogClust[j] != g)
3328                 {
3329                     pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3330                     pwLogClust[j] = g;
3331                 }
3332             }
3333         }
3334
3335         HeapFree(GetProcessHeap(), 0, syllables);
3336     }
3337
3338     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3339 }
3340
3341 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 )
3342 {
3343     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE);
3344 }
3345
3346 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 )
3347 {
3348     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE);
3349 }
3350
3351 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 )
3352 {
3353     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE);
3354 }
3355
3356 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 )
3357 {
3358     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE);
3359 }
3360
3361 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 )
3362 {
3363     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE);
3364 }
3365
3366 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 )
3367 {
3368     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE);
3369 }
3370
3371 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 )
3372 {
3373     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE);
3374 }
3375
3376 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 )
3377 {
3378     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE);
3379 }
3380
3381 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 )
3382 {
3383     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE);
3384 }
3385
3386 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 )
3387 {
3388     ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE);
3389 }
3390
3391 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)
3392 {
3393     if (ShapingData[psa->eScript].charGlyphPropProc)
3394         ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3395     else
3396         ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3397 }
3398
3399 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3400 {
3401     if (!psc->GSUB_Table)
3402         psc->GSUB_Table = load_gsub_table(hdc);
3403
3404     if (ShapingData[psa->eScript].contextProc)
3405         ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3406 }
3407
3408 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)
3409 {
3410     int i;
3411     INT dirL;
3412
3413     if (!rpRangeProperties)
3414         return;
3415
3416     if (!psc->GSUB_Table)
3417         psc->GSUB_Table = load_gsub_table(hdc);
3418
3419     if (!psc->GSUB_Table)
3420         return;
3421
3422     if (!psa->fLogicalOrder && psa->fRTL)
3423         dirL = -1;
3424     else
3425         dirL = 1;
3426
3427     for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3428     {
3429         if (rpRangeProperties->potfRecords[i].lParameter > 0)
3430         apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3431     }
3432 }
3433
3434 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3435 {
3436 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3437 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3438
3439     SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3440 }
3441
3442 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3443 {
3444     const GSUB_Feature *feature;
3445     int i;
3446
3447     if (!ShapingData[psa->eScript].requiredFeatures)
3448         return S_OK;
3449
3450     if (!psc->GSUB_Table)
3451         psc->GSUB_Table = load_gsub_table(hdc);
3452
3453     /* we need to have at least one of the required features */
3454     i = 0;
3455     while (ShapingData[psa->eScript].requiredFeatures[i])
3456     {
3457         feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3458         if (feature)
3459             return S_OK;
3460         i++;
3461     }
3462
3463     return USP_E_SCRIPT_NOT_IN_FONT;
3464 }