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