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