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