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