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