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