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