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