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