usp10: Improve Sinhala shaping using Indic rules.
[wine] / dlls / usp10 / shape.c
1 /*
2  * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
3  *
4  * Copyright 2010 CodeWeavers, Aric Stewart
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  */
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "usp10.h"
29 #include "winternl.h"
30
31 #include "usp10_internal.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
36
37 #define FIRST_ARABIC_CHAR 0x0600
38 #define LAST_ARABIC_CHAR  0x06ff
39
40 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
41                                       WCHAR*, INT, WORD*, INT*, INT, WORD*);
42
43 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
44 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47
48
49 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
50
51 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);
52 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 );
53 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 );
54 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 );
55 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 );
56
57 extern const unsigned short wine_shaping_table[];
58 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
59
60 enum joining_types {
61     jtU,
62     jtT,
63     jtR,
64     jtL,
65     jtD,
66     jtC
67 };
68
69 enum joined_forms {
70     Xn=0,
71     Xr,
72     Xl,
73     Xm,
74     /* Syriac Alaph */
75     Afj,
76     Afn,
77     Afx
78 };
79
80 #ifdef WORDS_BIGENDIAN
81 #define GET_BE_WORD(x) (x)
82 #else
83 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
84 #endif
85
86 /* These are all structures needed for the GSUB table */
87 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
88 #define GSUB_E_NOFEATURE -2
89 #define GSUB_E_NOGLYPH -1
90
91 typedef struct {
92     DWORD version;
93     WORD ScriptList;
94     WORD FeatureList;
95     WORD LookupList;
96 } GSUB_Header;
97
98 typedef struct {
99     CHAR ScriptTag[4];
100     WORD Script;
101 } GSUB_ScriptRecord;
102
103 typedef struct {
104     WORD ScriptCount;
105     GSUB_ScriptRecord ScriptRecord[1];
106 } GSUB_ScriptList;
107
108 typedef struct {
109     CHAR LangSysTag[4];
110     WORD LangSys;
111 } GSUB_LangSysRecord;
112
113 typedef struct {
114     WORD DefaultLangSys;
115     WORD LangSysCount;
116     GSUB_LangSysRecord LangSysRecord[1];
117 } GSUB_Script;
118
119 typedef struct {
120     WORD LookupOrder; /* Reserved */
121     WORD ReqFeatureIndex;
122     WORD FeatureCount;
123     WORD FeatureIndex[1];
124 } GSUB_LangSys;
125
126 typedef struct {
127     CHAR FeatureTag[4];
128     WORD Feature;
129 } GSUB_FeatureRecord;
130
131 typedef struct {
132     WORD FeatureCount;
133     GSUB_FeatureRecord FeatureRecord[1];
134 } GSUB_FeatureList;
135
136 typedef struct {
137     WORD FeatureParams; /* Reserved */
138     WORD LookupCount;
139     WORD LookupListIndex[1];
140 } GSUB_Feature;
141
142 typedef struct {
143     WORD LookupCount;
144     WORD Lookup[1];
145 } GSUB_LookupList;
146
147 typedef struct {
148     WORD LookupType;
149     WORD LookupFlag;
150     WORD SubTableCount;
151     WORD SubTable[1];
152 } GSUB_LookupTable;
153
154 typedef struct {
155     WORD CoverageFormat;
156     WORD GlyphCount;
157     WORD GlyphArray[1];
158 } GSUB_CoverageFormat1;
159
160 typedef struct {
161     WORD Start;
162     WORD End;
163     WORD StartCoverageIndex;
164 } GSUB_RangeRecord;
165
166 typedef struct {
167     WORD CoverageFormat;
168     WORD RangeCount;
169     GSUB_RangeRecord RangeRecord[1];
170 } GSUB_CoverageFormat2;
171
172 typedef struct {
173     WORD SubstFormat; /* = 1 */
174     WORD Coverage;
175     WORD DeltaGlyphID;
176 } GSUB_SingleSubstFormat1;
177
178 typedef struct {
179     WORD SubstFormat; /* = 2 */
180     WORD Coverage;
181     WORD GlyphCount;
182     WORD Substitute[1];
183 }GSUB_SingleSubstFormat2;
184
185 typedef struct {
186     WORD SubstFormat; /* = 1 */
187     WORD Coverage;
188     WORD LigSetCount;
189     WORD LigatureSet[1];
190 }GSUB_LigatureSubstFormat1;
191
192 typedef struct {
193     WORD LigatureCount;
194     WORD Ligature[1];
195 }GSUB_LigatureSet;
196
197 typedef struct{
198     WORD LigGlyph;
199     WORD CompCount;
200     WORD Component[1];
201 }GSUB_Ligature;
202
203 typedef struct{
204     WORD SequenceIndex;
205     WORD LookupListIndex;
206
207 }GSUB_SubstLookupRecord;
208
209 typedef struct{
210     WORD SubstFormat; /* = 1 */
211     WORD Coverage;
212     WORD ChainSubRuleSetCount;
213     WORD ChainSubRuleSet[1];
214 }GSUB_ChainContextSubstFormat1;
215
216 typedef struct {
217     WORD SubstFormat; /* = 3 */
218     WORD BacktrackGlyphCount;
219     WORD Coverage[1];
220 }GSUB_ChainContextSubstFormat3_1;
221
222 typedef struct{
223     WORD InputGlyphCount;
224     WORD Coverage[1];
225 }GSUB_ChainContextSubstFormat3_2;
226
227 typedef struct{
228     WORD LookaheadGlyphCount;
229     WORD Coverage[1];
230 }GSUB_ChainContextSubstFormat3_3;
231
232 typedef struct{
233     WORD SubstCount;
234     GSUB_SubstLookupRecord SubstLookupRecord[1];
235 }GSUB_ChainContextSubstFormat3_4;
236
237 typedef struct {
238     WORD SubstFormat; /* = 1 */
239     WORD Coverage;
240     WORD AlternateSetCount;
241     WORD AlternateSet[1];
242 } GSUB_AlternateSubstFormat1;
243
244 typedef struct{
245     WORD GlyphCount;
246     WORD Alternate[1];
247 } GSUB_AlternateSet;
248
249 /* These are all structures needed for the GDEF table */
250 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
251
252 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
253
254 typedef struct {
255     DWORD Version;
256     WORD GlyphClassDef;
257     WORD AttachList;
258     WORD LigCaretList;
259     WORD MarkAttachClassDef;
260 } GDEF_Header;
261
262 typedef struct {
263     WORD ClassFormat;
264     WORD StartGlyph;
265     WORD GlyphCount;
266     WORD ClassValueArray[1];
267 } GDEF_ClassDefFormat1;
268
269 typedef struct {
270     WORD Start;
271     WORD End;
272     WORD Class;
273 } GDEF_ClassRangeRecord;
274
275 typedef struct {
276     WORD ClassFormat;
277     WORD ClassRangeCount;
278     GDEF_ClassRangeRecord ClassRangeRecord[1];
279 } GDEF_ClassDefFormat2;
280
281 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
282
283 typedef struct tagVowelComponents
284 {
285     WCHAR base;
286     WCHAR parts[3];
287 } VowelComponents;
288
289 /* the orders of joined_forms and contextual_features need to line up */
290 static const char* contextual_features[] =
291 {
292     "isol",
293     "fina",
294     "init",
295     "medi",
296     /* Syriac Alaph */
297     "med2",
298     "fin2",
299     "fin3"
300 };
301
302 static OPENTYPE_FEATURE_RECORD standard_features[] =
303 {
304     { MS_MAKE_TAG('l','i','g','a'), 1},
305     { MS_MAKE_TAG('c','l','i','g'), 1},
306 };
307
308 static OPENTYPE_FEATURE_RECORD arabic_features[] =
309 {
310     { MS_MAKE_TAG('r','l','i','g'), 1},
311     { MS_MAKE_TAG('c','a','l','t'), 1},
312     { MS_MAKE_TAG('l','i','g','a'), 1},
313     { MS_MAKE_TAG('d','l','i','g'), 1},
314     { MS_MAKE_TAG('c','s','w','h'), 1},
315     { MS_MAKE_TAG('m','s','e','t'), 1},
316 };
317
318 static const char* required_arabic_features[] =
319 {
320     "fina",
321     "init",
322     "medi",
323     "rlig",
324     NULL
325 };
326
327 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
328 {
329     { MS_MAKE_TAG('d','l','i','g'), 1},
330 };
331
332 static OPENTYPE_FEATURE_RECORD syriac_features[] =
333 {
334     { MS_MAKE_TAG('r','l','i','g'), 1},
335     { MS_MAKE_TAG('c','a','l','t'), 1},
336     { MS_MAKE_TAG('l','i','g','a'), 1},
337     { MS_MAKE_TAG('d','l','i','g'), 1},
338 };
339
340 static const char* required_syriac_features[] =
341 {
342     "fina",
343     "fin2",
344     "fin3",
345     "init",
346     "medi",
347     "med2",
348     "rlig",
349     NULL
350 };
351
352 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
353 {
354     /* Base forms */
355     { MS_MAKE_TAG('a','k','h','n'), 1},
356     { MS_MAKE_TAG('r','p','h','f'), 1},
357     { MS_MAKE_TAG('v','a','t','u'), 1},
358     { MS_MAKE_TAG('p','s','t','f'), 1},
359     /* Presentation forms */
360     { MS_MAKE_TAG('b','l','w','s'), 1},
361     { MS_MAKE_TAG('a','b','v','s'), 1},
362     { MS_MAKE_TAG('p','s','t','s'), 1},
363 };
364
365 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
366 {
367     { MS_MAKE_TAG('a','b','v','s'), 1},
368     { MS_MAKE_TAG('b','l','w','s'), 1},
369 };
370
371 static OPENTYPE_FEATURE_RECORD thai_features[] =
372 {
373     { MS_MAKE_TAG('c','c','m','p'), 1},
374 };
375
376 static const char* required_lao_features[] =
377 {
378     "ccmp",
379     NULL
380 };
381
382 typedef struct ScriptShapeDataTag {
383     TEXTRANGE_PROPERTIES   defaultTextRange;
384     const char**           requiredFeatures;
385     CHAR                   otTag[5];
386     CHAR                   newOtTag[5];
387     ContextualShapingProc  contextProc;
388     ShapeCharGlyphPropProc charGlyphPropProc;
389 } ScriptShapeData;
390
391 /* in order of scripts */
392 static const ScriptShapeData ShapingData[] =
393 {
394     {{ standard_features, 2}, NULL, "", "", NULL, NULL},
395     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
396     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
397     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
398     {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
399     {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
400     {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
401     {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
402     {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
403     {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
404     {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
405     {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
406     {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
407     {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
408     {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
409     {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
410     {{ sinhala_features, 7}, NULL, "sinh", "", ContextualShape_Sinhala, NULL},
411     {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
412     {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
413     {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
414     {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
415     {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
416     {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
417     {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
418 };
419
420 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
421 {
422     const GSUB_CoverageFormat1* cf1;
423
424     cf1 = table;
425
426     if (GET_BE_WORD(cf1->CoverageFormat) == 1)
427     {
428         int count = GET_BE_WORD(cf1->GlyphCount);
429         int i;
430         TRACE("Coverage Format 1, %i glyphs\n",count);
431         for (i = 0; i < count; i++)
432             if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
433                 return i;
434         return -1;
435     }
436     else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
437     {
438         const GSUB_CoverageFormat2* cf2;
439         int i;
440         int count;
441         cf2 = (const GSUB_CoverageFormat2*)cf1;
442
443         count = GET_BE_WORD(cf2->RangeCount);
444         TRACE("Coverage Format 2, %i ranges\n",count);
445         for (i = 0; i < count; i++)
446         {
447             if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
448                 return -1;
449             if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
450                 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
451             {
452                 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
453                     glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
454             }
455         }
456         return -1;
457     }
458     else
459         ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
460
461     return -1;
462 }
463
464 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
465 {
466     const GSUB_ScriptList *script;
467     const GSUB_Script *deflt = NULL;
468     int i;
469     script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
470
471     TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
472     for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
473     {
474         const GSUB_Script *scr;
475         int offset;
476
477         offset = GET_BE_WORD(script->ScriptRecord[i].Script);
478         scr = (const GSUB_Script*)((const BYTE*)script + offset);
479
480         if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
481             return scr;
482         if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
483             deflt = scr;
484     }
485     return deflt;
486 }
487
488 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
489 {
490     int i;
491     int offset;
492     const GSUB_LangSys *Lang;
493
494     TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
495
496     for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
497     {
498         offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
499         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
500
501         if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
502             return Lang;
503     }
504     offset = GET_BE_WORD(script->DefaultLangSys);
505     if (offset)
506     {
507         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
508         return Lang;
509     }
510     return NULL;
511 }
512
513 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
514 {
515     int i;
516     const GSUB_FeatureList *feature;
517     feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
518
519     TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
520     for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
521     {
522         int index = GET_BE_WORD(lang->FeatureIndex[i]);
523         if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
524         {
525             const GSUB_Feature *feat;
526             feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
527             return feat;
528         }
529     }
530     return NULL;
531 }
532
533 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
534 {
535     int j;
536     TRACE("Single Substitution Subtable\n");
537
538     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
539     {
540         int offset;
541         const GSUB_SingleSubstFormat1 *ssf1;
542         offset = GET_BE_WORD(look->SubTable[j]);
543         ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
544         if (GET_BE_WORD(ssf1->SubstFormat) == 1)
545         {
546             int offset = GET_BE_WORD(ssf1->Coverage);
547             TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
548             if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
549             {
550                 TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
551                 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
552                 TRACE(" 0x%x\n",glyphs[glyph_index]);
553                 return glyph_index + 1;
554             }
555         }
556         else
557         {
558             const GSUB_SingleSubstFormat2 *ssf2;
559             INT index;
560             INT offset;
561
562             ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
563             offset = GET_BE_WORD(ssf1->Coverage);
564             TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
565             index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
566             TRACE("  Coverage index %i\n",index);
567             if (index != -1)
568             {
569                 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
570                     return GSUB_E_NOGLYPH;
571
572                 TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
573                 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
574                 TRACE("0x%x\n",glyphs[glyph_index]);
575                 return glyph_index + 1;
576             }
577         }
578     }
579     return GSUB_E_NOGLYPH;
580 }
581
582 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
583 {
584     int j;
585     TRACE("Alternate Substitution Subtable\n");
586
587     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
588     {
589         int offset;
590         const GSUB_AlternateSubstFormat1 *asf1;
591         INT index;
592
593         offset = GET_BE_WORD(look->SubTable[j]);
594         asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
595         offset = GET_BE_WORD(asf1->Coverage);
596
597         index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
598         if (index != -1)
599         {
600             const GSUB_AlternateSet *as;
601             offset =  GET_BE_WORD(asf1->AlternateSet[index]);
602             as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
603             FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
604             if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
605                 return GSUB_E_NOGLYPH;
606
607             TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
608             glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
609             TRACE(" 0x%x\n",glyphs[glyph_index]);
610             return glyph_index + 1;
611         }
612     }
613     return GSUB_E_NOGLYPH;
614 }
615
616 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
617 {
618     int j;
619
620     TRACE("Ligature Substitution Subtable\n");
621     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
622     {
623         const GSUB_LigatureSubstFormat1 *lsf1;
624         int offset,index;
625
626         offset = GET_BE_WORD(look->SubTable[j]);
627         lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
628         offset = GET_BE_WORD(lsf1->Coverage);
629         index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
630         TRACE("  Coverage index %i\n",index);
631         if (index != -1)
632         {
633             const GSUB_LigatureSet *ls;
634             int k, count;
635
636             offset = GET_BE_WORD(lsf1->LigatureSet[index]);
637             ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
638             count = GET_BE_WORD(ls->LigatureCount);
639             TRACE("  LigatureSet has %i members\n",count);
640             for (k = 0; k < count; k++)
641             {
642                 const GSUB_Ligature *lig;
643                 int CompCount,l,CompIndex;
644
645                 offset = GET_BE_WORD(ls->Ligature[k]);
646                 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
647                 CompCount = GET_BE_WORD(lig->CompCount) - 1;
648                 CompIndex = glyph_index+write_dir;
649                 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
650                 {
651                     int CompGlyph;
652                     CompGlyph = GET_BE_WORD(lig->Component[l]);
653                     if (CompGlyph != glyphs[CompIndex])
654                         break;
655                     CompIndex += write_dir;
656                 }
657                 if (l == CompCount)
658                 {
659                     int replaceIdx = glyph_index;
660                     if (write_dir < 0)
661                         replaceIdx = glyph_index - CompCount;
662
663                     TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
664                     glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
665                     TRACE("0x%x\n",glyphs[replaceIdx]);
666                     if (CompCount > 0)
667                     {
668                         int j;
669                         for (j = replaceIdx + 1; j < *glyph_count; j++)
670                             glyphs[j] =glyphs[j+CompCount];
671                         *glyph_count = *glyph_count - CompCount;
672                     }
673                     return replaceIdx + 1;
674                 }
675             }
676         }
677     }
678     return GSUB_E_NOGLYPH;
679 }
680
681 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
682 {
683     int j;
684     BOOL done = FALSE;
685
686     TRACE("Chaining Contextual Substitution Subtable\n");
687     for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
688     {
689         const GSUB_ChainContextSubstFormat1 *ccsf1;
690         int offset;
691         int dirLookahead = write_dir;
692         int dirBacktrack = -1 * write_dir;
693
694         offset = GET_BE_WORD(look->SubTable[j]);
695         ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
696         if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
697         {
698             FIXME("  TODO: subtype 1 (Simple context glyph substitution)\n");
699             return -1;
700         }
701         else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
702         {
703             FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
704             return -1;
705         }
706         else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
707         {
708             int k;
709             int indexGlyphs;
710             const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
711             const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
712             const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
713             const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
714             int newIndex = glyph_index;
715
716             ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
717
718             TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
719
720             for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
721             {
722                 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
723                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
724                     break;
725             }
726             if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
727                 return -1;
728             TRACE("Matched Backtrack\n");
729
730             ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
731
732             indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
733             for (k = 0; k < indexGlyphs; k++)
734             {
735                 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
736                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
737                     break;
738             }
739             if (k != indexGlyphs)
740                 return -1;
741             TRACE("Matched IndexGlyphs\n");
742
743             ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
744
745             for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
746             {
747                 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
748                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
749                     break;
750             }
751             if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
752                 return -1;
753             TRACE("Matched LookAhead\n");
754
755             ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
756
757             for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
758             {
759                 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
760                 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
761
762                 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
763                 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
764                 if (newIndex == -1)
765                 {
766                     ERR("Chain failed to generate a glyph\n");
767                     return -1;
768                 }
769             }
770             return newIndex + 1;
771         }
772     }
773     return -1;
774 }
775
776 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
777 {
778     int offset;
779     const GSUB_LookupTable *look;
780
781     offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
782     look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
783     TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
784     switch(GET_BE_WORD(look->LookupType))
785     {
786         case 1:
787             return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
788         case 3:
789             return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
790         case 4:
791             return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
792         case 6:
793             return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
794         default:
795             FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
796     }
797     return GSUB_E_NOGLYPH;
798 }
799
800 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
801 {
802     int i;
803     int out_index = GSUB_E_NOGLYPH;
804     const GSUB_LookupList *lookup;
805
806     lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
807
808     TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
809     for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
810     {
811         out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
812         if (out_index != GSUB_E_NOGLYPH)
813             break;
814     }
815     if (out_index == GSUB_E_NOGLYPH)
816         TRACE("lookups found no glyphs\n");
817     else
818     {
819         int out2;
820         out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
821         if (out2!=GSUB_E_NOGLYPH)
822             out_index = out2;
823     }
824     return out_index;
825 }
826
827 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
828 {
829     UINT charset;
830
831     if (psc->userScript != 0)
832     {
833         if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
834             return ShapingData[psa->eScript].newOtTag;
835         else
836             return (char*)&psc->userScript;
837     }
838
839     if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
840         return ShapingData[psa->eScript].newOtTag;
841
842     if (ShapingData[psa->eScript].otTag[0] != 0)
843         return ShapingData[psa->eScript].otTag;
844
845     /*
846      * fall back to the font charset
847      */
848     charset = GetTextCharsetInfo(hdc, NULL, 0x0);
849     switch (charset)
850     {
851         case ANSI_CHARSET: return "latn";
852         case BALTIC_CHARSET: return "latn"; /* ?? */
853         case CHINESEBIG5_CHARSET: return "hani";
854         case EASTEUROPE_CHARSET: return "latn"; /* ?? */
855         case GB2312_CHARSET: return "hani";
856         case GREEK_CHARSET: return "grek";
857         case HANGUL_CHARSET: return "hang";
858         case RUSSIAN_CHARSET: return "cyrl";
859         case SHIFTJIS_CHARSET: return "kana";
860         case TURKISH_CHARSET: return "latn"; /* ?? */
861         case VIETNAMESE_CHARSET: return "latn";
862         case JOHAB_CHARSET: return "latn"; /* ?? */
863         case ARABIC_CHARSET: return "arab";
864         case HEBREW_CHARSET: return "hebr";
865         case THAI_CHARSET: return "thai";
866         default: return "latn";
867     }
868 }
869
870 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
871 {
872     const GSUB_Feature *feature;
873     int i;
874
875     for (i = 0; i <  psc->feature_count; i++)
876         if (strncmp(psc->features[i].tag,feat,4)==0)
877             return psc->features[i].feature;
878
879     feature = NULL;
880
881     if (psc->GSUB_Table)
882     {
883         const GSUB_Script *script;
884         const GSUB_LangSys *language;
885         int attempt = 2;
886
887         do
888         {
889             script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
890             attempt--;
891             if (script)
892             {
893                 if (psc->userLang != 0)
894                     language = GSUB_get_lang_table(script,(char*)&psc->userLang);
895                 else
896                     language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
897                 if (language)
898                     feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
899             }
900         } while(attempt && !feature);
901
902         /* try in the default (latin) table */
903         if (!feature)
904         {
905             script = GSUB_get_script_table(psc->GSUB_Table, "latn");
906             if (script)
907             {
908                 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
909                 if (language)
910                     feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
911             }
912         }
913     }
914
915     TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
916
917     psc->feature_count++;
918
919     if (psc->features)
920         psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
921     else
922         psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
923
924     lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
925     psc->features[psc->feature_count - 1].feature = feature;
926     return feature;
927 }
928
929 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)
930 {
931     const GSUB_Feature *feature;
932
933     feature = load_GSUB_feature(hdc, psa, psc, feat);
934     if (!feature)
935         return GSUB_E_NOFEATURE;
936
937     TRACE("applying feature %s\n",feat);
938     return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
939 }
940
941 static VOID *load_gsub_table(HDC hdc)
942 {
943     VOID* GSUB_Table = NULL;
944     int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
945     if (length != GDI_ERROR)
946     {
947         GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
948         GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
949         TRACE("Loaded GSUB table of %i bytes\n",length);
950     }
951     return GSUB_Table;
952 }
953
954 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
955 {
956     int offset;
957     WORD class = 0;
958     const GDEF_ClassDefFormat1 *cf1;
959
960     if (!header)
961         return 0;
962
963     offset = GET_BE_WORD(header->GlyphClassDef);
964     if (!offset)
965         return 0;
966
967     cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
968     if (GET_BE_WORD(cf1->ClassFormat) == 1)
969     {
970         if (glyph >= GET_BE_WORD(cf1->StartGlyph))
971         {
972             int index = glyph - GET_BE_WORD(cf1->StartGlyph);
973             if (index < GET_BE_WORD(cf1->GlyphCount))
974                 class = GET_BE_WORD(cf1->ClassValueArray[index]);
975         }
976     }
977     else if (GET_BE_WORD(cf1->ClassFormat) == 2)
978     {
979         const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
980         int i, top;
981         top = GET_BE_WORD(cf2->ClassRangeCount);
982         for (i = 0; i < top; i++)
983         {
984             if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
985                 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
986             {
987                 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
988                 break;
989             }
990         }
991     }
992     else
993         ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
994
995     return class;
996 }
997
998 static VOID *load_gdef_table(HDC hdc)
999 {
1000     VOID* GDEF_Table = NULL;
1001     int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1002     if (length != GDI_ERROR)
1003     {
1004         GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1005         GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1006         TRACE("Loaded GDEF table of %i bytes\n",length);
1007     }
1008     return GDEF_Table;
1009 }
1010
1011 static void GDEF_UpdateGlyphProps(HDC hdc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1012 {
1013     VOID* header = load_gdef_table(hdc);
1014     int i;
1015
1016     for (i = 0; i < cGlyphs; i++)
1017     {
1018         WORD class;
1019
1020         class = GDEF_get_glyph_class(header, pwGlyphs[i]);
1021
1022         switch (class)
1023         {
1024             case 0:
1025             case BaseGlyph:
1026                 pGlyphProp[i].sva.fClusterStart = 1;
1027                 pGlyphProp[i].sva.fDiacritic = 0;
1028                 pGlyphProp[i].sva.fZeroWidth = 0;
1029                 break;
1030             case LigatureGlyph:
1031                 pGlyphProp[i].sva.fClusterStart = 1;
1032                 pGlyphProp[i].sva.fDiacritic = 0;
1033                 pGlyphProp[i].sva.fZeroWidth = 0;
1034                 break;
1035             case MarkGlyph:
1036                 pGlyphProp[i].sva.fClusterStart = 0;
1037                 pGlyphProp[i].sva.fDiacritic = 1;
1038                 pGlyphProp[i].sva.fZeroWidth = 1;
1039                 break;
1040             case ComponentGlyph:
1041                 pGlyphProp[i].sva.fClusterStart = 0;
1042                 pGlyphProp[i].sva.fDiacritic = 0;
1043                 pGlyphProp[i].sva.fZeroWidth = 0;
1044                 break;
1045             default:
1046                 ERR("Unknown glyph class %i\n",class);
1047                 pGlyphProp[i].sva.fClusterStart = 1;
1048                 pGlyphProp[i].sva.fDiacritic = 0;
1049                 pGlyphProp[i].sva.fZeroWidth = 0;
1050         }
1051     }
1052 }
1053
1054 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1055 {
1056     int i;
1057
1058     for (i = 0; i < cGlyphs; i++)
1059     {
1060         if (!pGlyphProp[i].sva.fClusterStart)
1061         {
1062             int j;
1063             for (j = 0; j < cChars; j++)
1064             {
1065                 if (pwLogClust[j] == i)
1066                 {
1067                     int k = j;
1068                     while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1069                         k-=1;
1070                     if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1071                         pwLogClust[j] = pwLogClust[k];
1072                 }
1073             }
1074         }
1075     }
1076 }
1077
1078 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1079 {
1080     if (changeCount == 0)
1081         return;
1082     else
1083     {
1084         int i;
1085         int target_glyph = nextIndex - 1;
1086         int target_index = -1;
1087         int replacing_glyph = -1;
1088         int changed = 0;
1089
1090         if (write_dir > 0)
1091             for (i = 0; i < chars; i++)
1092             {
1093                 if (pwLogClust[i] == target_glyph)
1094                 {
1095                     target_index = i;
1096                     break;
1097                 }
1098             }
1099         else
1100             for (i = chars - 1; i >= 0; i--)
1101             {
1102                 if (pwLogClust[i] == target_glyph)
1103                 {
1104                     target_index = i;
1105                     break;
1106                 }
1107             }
1108         if (target_index == -1)
1109         {
1110             ERR("Unable to find target glyph\n");
1111             return;
1112         }
1113
1114         if (changeCount < 0)
1115         {
1116             /* merge glyphs */
1117             for(i = target_index; i < chars && i >= 0; i+=write_dir)
1118             {
1119                 if (pwLogClust[i] == target_glyph)
1120                     continue;
1121                 if(pwLogClust[i] == replacing_glyph)
1122                     pwLogClust[i] = target_glyph;
1123                 else
1124                 {
1125                     changed--;
1126                     if (changed >= changeCount)
1127                     {
1128                         replacing_glyph = pwLogClust[i];
1129                         pwLogClust[i] = target_glyph;
1130                     }
1131                     else
1132                         break;
1133                 }
1134             }
1135         }
1136
1137         /* renumber trailing indexes*/
1138         for(i = target_index; i < chars && i >= 0; i+=write_dir)
1139         {
1140             if (pwLogClust[i] != target_glyph)
1141                 pwLogClust[i] += changeCount;
1142         }
1143     }
1144 }
1145
1146 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 )
1147 {
1148     int i;
1149
1150     if (psc->GSUB_Table)
1151     {
1152         const GSUB_Feature *feature;
1153
1154         feature = load_GSUB_feature(hdc, psa, psc, feat);
1155         if (!feature)
1156             return GSUB_E_NOFEATURE;
1157
1158         i = 0;
1159         TRACE("applying feature %s\n",debugstr_an(feat,4));
1160         while(i < *pcGlyphs)
1161         {
1162                 INT nextIndex;
1163                 INT prevCount = *pcGlyphs;
1164                 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1165                 if (nextIndex > GSUB_E_NOGLYPH)
1166                 {
1167                     UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1168                     i = nextIndex;
1169                 }
1170                 else
1171                     i++;
1172         }
1173         return *pcGlyphs;
1174     }
1175     return GSUB_E_NOFEATURE;
1176 }
1177
1178 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1179 {
1180     if (i + delta < 0)
1181         return 0;
1182     if ( i+ delta >= cchLen)
1183         return 0;
1184
1185     i += delta;
1186
1187     return chars[i];
1188 }
1189
1190 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1191 {
1192     if (i + delta < 0)
1193     {
1194         if (psa->fLinkBefore)
1195             return jtR;
1196         else
1197             return jtU;
1198     }
1199     if ( i+ delta >= cchLen)
1200     {
1201         if (psa->fLinkAfter)
1202             return jtL;
1203         else
1204             return jtU;
1205     }
1206
1207     i += delta;
1208
1209     if (context_type[i] == jtT)
1210         return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1211     else
1212         return context_type[i];
1213 }
1214
1215 static inline BOOL right_join_causing(CHAR joining_type)
1216 {
1217     return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1218 }
1219
1220 static inline BOOL left_join_causing(CHAR joining_type)
1221 {
1222     return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1223 }
1224
1225 static inline BOOL word_break_causing(WCHAR chr)
1226 {
1227     /* we are working within a string of characters already guareented to
1228        be within one script, Syriac, so we do not worry about any characers
1229        other than the space character outside of that range */
1230     return (chr == 0 || chr == 0x20 );
1231 }
1232
1233 /*
1234  * ContextualShape_Arabic
1235  */
1236 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1237 {
1238     CHAR *context_type;
1239     INT *context_shape;
1240     INT dirR, dirL;
1241     int i;
1242
1243     if (*pcGlyphs != cChars)
1244     {
1245         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1246         return;
1247     }
1248
1249     if (!psa->fLogicalOrder && psa->fRTL)
1250     {
1251         dirR = 1;
1252         dirL = -1;
1253     }
1254     else
1255     {
1256         dirR = -1;
1257         dirL = 1;
1258     }
1259
1260     if (!psc->GSUB_Table)
1261         psc->GSUB_Table = load_gsub_table(hdc);
1262
1263     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1264     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1265
1266     for (i = 0; i < cChars; i++)
1267         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1268
1269     for (i = 0; i < cChars; i++)
1270     {
1271         if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1272             context_shape[i] = Xr;
1273         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1274             context_shape[i] = Xl;
1275         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)))
1276             context_shape[i] = Xm;
1277         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1278             context_shape[i] = Xr;
1279         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1280             context_shape[i] = Xl;
1281         else
1282             context_shape[i] = Xn;
1283     }
1284
1285     /* Contextual Shaping */
1286     i = 0;
1287     while(i < *pcGlyphs)
1288     {
1289         BOOL shaped = FALSE;
1290
1291         if (psc->GSUB_Table)
1292         {
1293             INT nextIndex;
1294             INT prevCount = *pcGlyphs;
1295             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1296             if (nextIndex > GSUB_E_NOGLYPH)
1297             {
1298                 i = nextIndex;
1299                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1300             }
1301             shaped = (nextIndex > GSUB_E_NOGLYPH);
1302         }
1303
1304         if (!shaped)
1305         {
1306             WORD newGlyph = pwOutGlyphs[i];
1307             if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1308             {
1309                 /* fall back to presentation form B */
1310                 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1311                 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1312                     pwOutGlyphs[i] = newGlyph;
1313             }
1314             i++;
1315         }
1316     }
1317
1318     HeapFree(GetProcessHeap(),0,context_shape);
1319     HeapFree(GetProcessHeap(),0,context_type);
1320 }
1321
1322 /*
1323  * ContextualShape_Syriac
1324  */
1325
1326 #define ALAPH 0x710
1327 #define DALATH 0x715
1328 #define RISH 0x72A
1329
1330 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1331 {
1332     CHAR *context_type;
1333     INT *context_shape;
1334     INT dirR, dirL;
1335     int i;
1336
1337     if (*pcGlyphs != cChars)
1338     {
1339         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1340         return;
1341     }
1342
1343     if (!psa->fLogicalOrder && psa->fRTL)
1344     {
1345         dirR = 1;
1346         dirL = -1;
1347     }
1348     else
1349     {
1350         dirR = -1;
1351         dirL = 1;
1352     }
1353
1354     if (!psc->GSUB_Table)
1355         psc->GSUB_Table = load_gsub_table(hdc);
1356
1357     if (!psc->GSUB_Table)
1358         return;
1359
1360     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1361     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1362
1363     for (i = 0; i < cChars; i++)
1364         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1365
1366     for (i = 0; i < cChars; i++)
1367     {
1368         if (pwcChars[i] == ALAPH)
1369         {
1370             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1371
1372             if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1373             context_shape[i] = Afj;
1374             else if ( rchar != DALATH && rchar != RISH &&
1375 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1376 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1377             context_shape[i] = Afn;
1378             else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1379             context_shape[i] = Afx;
1380             else
1381             context_shape[i] = Xn;
1382         }
1383         else if (context_type[i] == jtR &&
1384 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1385             context_shape[i] = Xr;
1386         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1387             context_shape[i] = Xl;
1388         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)))
1389             context_shape[i] = Xm;
1390         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1391             context_shape[i] = Xr;
1392         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1393             context_shape[i] = Xl;
1394         else
1395             context_shape[i] = Xn;
1396     }
1397
1398     /* Contextual Shaping */
1399     i = 0;
1400     while(i < *pcGlyphs)
1401     {
1402         INT nextIndex;
1403         INT prevCount = *pcGlyphs;
1404         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1405         if (nextIndex > GSUB_E_NOGLYPH)
1406         {
1407             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1408             i = nextIndex;
1409         }
1410         else
1411             i++;
1412     }
1413
1414     HeapFree(GetProcessHeap(),0,context_shape);
1415     HeapFree(GetProcessHeap(),0,context_type);
1416 }
1417
1418 /*
1419  * ContextualShape_Phags_pa
1420  */
1421
1422 #define phags_pa_CANDRABINDU  0xA873
1423 #define phags_pa_START 0xA840
1424 #define phags_pa_END  0xA87F
1425
1426 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1427 {
1428     INT *context_shape;
1429     INT dirR, dirL;
1430     int i;
1431
1432     if (*pcGlyphs != cChars)
1433     {
1434         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1435         return;
1436     }
1437
1438     if (!psa->fLogicalOrder && psa->fRTL)
1439     {
1440         dirR = 1;
1441         dirL = -1;
1442     }
1443     else
1444     {
1445         dirR = -1;
1446         dirL = 1;
1447     }
1448
1449     if (!psc->GSUB_Table)
1450         psc->GSUB_Table = load_gsub_table(hdc);
1451
1452     if (!psc->GSUB_Table)
1453         return;
1454
1455     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1456
1457     for (i = 0; i < cChars; i++)
1458     {
1459         if (pwcChars[i] >= phags_pa_START && pwcChars[i] <=  phags_pa_END)
1460         {
1461             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1462             WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1463             BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <=  phags_pa_END);
1464             BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <=  phags_pa_END);
1465
1466             if (jrchar && jlchar)
1467                 context_shape[i] = Xm;
1468             else if (jrchar)
1469                 context_shape[i] = Xr;
1470             else if (jlchar)
1471                 context_shape[i] = Xl;
1472             else
1473                 context_shape[i] = Xn;
1474         }
1475         else
1476             context_shape[i] = -1;
1477     }
1478
1479     /* Contextual Shaping */
1480     i = 0;
1481     while(i < *pcGlyphs)
1482     {
1483         if (context_shape[i] >= 0)
1484         {
1485             INT nextIndex;
1486             INT prevCount = *pcGlyphs;
1487             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1488             if (nextIndex > GSUB_E_NOGLYPH)
1489             {
1490                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1491                 i = nextIndex;
1492             }
1493             else
1494                 i++;
1495         }
1496         else
1497             i++;
1498     }
1499
1500     HeapFree(GetProcessHeap(),0,context_shape);
1501 }
1502
1503 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1504 {
1505     int i;
1506
1507     /* Replace */
1508     pwOutChars[cWalk] = replacements[0];
1509     cWalk=cWalk+1;
1510
1511     /* Insert */
1512     for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1513     {
1514         int j;
1515         for (j = *pcChars; j > cWalk; j--)
1516             pwOutChars[j] = pwOutChars[j-1];
1517         *pcChars= *pcChars+1;
1518         pwOutChars[cWalk] = replacements[i];
1519         cWalk = cWalk+1;
1520     }
1521 }
1522
1523 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1524 {
1525     int i;
1526     int cWalk;
1527
1528     for (cWalk = 0; cWalk < *pcChars; cWalk++)
1529     {
1530         for (i = 0; vowels[i].base != 0x0; i++)
1531         {
1532             if (pwOutChars[cWalk] == vowels[i].base)
1533             {
1534                 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1535                 break;
1536             }
1537         }
1538     }
1539 }
1540
1541 static void Reorder_Ra_follows_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1542 {
1543     if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1544     {
1545         int j;
1546         WORD Ra = pwChar[start];
1547         WORD H = pwChar[start+1];
1548
1549         TRACE("Doing reorder of Ra to %i\n",main);
1550         for (j = start; j < main-1; j++)
1551             pwChar[j] = pwChar[j+2];
1552         pwChar[main-1] = Ra;
1553         pwChar[main] = H;
1554     }
1555 }
1556
1557 static void Reorder_Mantra_precede_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1558 {
1559     int i;
1560
1561     /* reorder Mantras */
1562     if (end > main)
1563     {
1564         for (i = 1; i <= end-main; i++)
1565         {
1566             if (lexical(pwChar[main+i]) == lex_Mantra_pre)
1567             {
1568                 int j;
1569                 WCHAR c = pwChar[main+i];
1570                 TRACE("Doing reorder of %x %x\n",c,pwChar[main]);
1571                 for (j = main+i; j > main; j--)
1572                     pwChar[j] = pwChar[j-1];
1573                 pwChar[main] = c;
1574             }
1575         }
1576     }
1577 }
1578
1579 static void Reorder_Like_Sinhala(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1580 {
1581     TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1582     if (start == main && main == end)  return;
1583
1584     main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1585     if (lexical(pwChar[main]) == lex_Vowel) return;
1586
1587     Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1588     Reorder_Mantra_precede_base(pwChar, start, main, end, lexical);
1589 }
1590
1591 static int sinhala_lex(WCHAR c)
1592 {
1593     switch (c)
1594     {
1595         case 0x0DCA: return lex_Halant;
1596         case 0x0DCF:
1597         case 0x0DDF:
1598         case 0x0DD8: return lex_Mantra_post;
1599         case 0x0DD9:
1600         case 0x0DDB: return lex_Mantra_pre;
1601         case 0x0DDA:
1602         case 0x0DDC: return lex_Composed_Vowel;
1603         case 0x200D: return lex_ZWJ;
1604         case 0x200C: return lex_ZWNJ;
1605         case 0x00A0: return lex_NBSP;
1606         default:
1607             if (c>=0x0D82 && c <=0x0D83) return lex_Modifier;
1608             else if (c>=0x0D85 && c <=0x0D96) return lex_Vowel;
1609             else if (c>=0x0D96 && c <=0x0DC6) return lex_Consonant;
1610             else if (c>=0x0DD0 && c <=0x0DD1) return lex_Mantra_post;
1611             else if (c>=0x0DD2 && c <=0x0DD3) return lex_Mantra_above;
1612             else if (c>=0x0DD4 && c <=0x0DD6) return lex_Mantra_below;
1613             else if (c>=0x0DDD && c <=0x0DDE) return lex_Composed_Vowel;
1614             else if (c>=0x0DF2 && c <=0x0DF3) return lex_Mantra_post;
1615             else return lex_Generic;
1616     }
1617 }
1618
1619 static const VowelComponents Sinhala_vowels[] = {
1620             {0x0DDA, {0x0DD9,0x0DCA,0x0}},
1621             {0x0DDC, {0x0DD9,0x0DCF,0x0}},
1622             {0x0DDD, {0x0DD9,0x0DCF,0x0DCA}},
1623             {0x0DDE, {0x0DD9,0x0DDF,0x0}},
1624             {0x0000, {0x0000,0x0000,0x0}}};
1625
1626 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1627 {
1628     int cCount = cChars;
1629     WCHAR *input;
1630
1631     if (*pcGlyphs != cChars)
1632     {
1633         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1634         return;
1635     }
1636
1637     input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
1638
1639     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1640
1641     /* Step 1:  Decompose multi part vowels */
1642     DecomposeVowels(hdc, input,  &cCount, Sinhala_vowels);
1643
1644     TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1645
1646     /* Step 2:  Reorder within Syllables */
1647     Indic_ReorderCharacters( input, cCount, sinhala_lex, Reorder_Like_Sinhala);
1648     TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1649
1650     /* Step 3:  Get glyphs */
1651     GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1652     *pcGlyphs = cCount;
1653
1654     HeapFree(GetProcessHeap(),0,input);
1655 }
1656
1657 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)
1658 {
1659     int i,k;
1660
1661     for (i = 0; i < cGlyphs; i++)
1662     {
1663         int char_index[20];
1664         int char_count = 0;
1665
1666         for (k = 0; k < cChars; k++)
1667         {
1668             if (pwLogClust[k] == i)
1669             {
1670                 char_index[char_count] = k;
1671                 char_count++;
1672             }
1673         }
1674
1675         if (char_count == 0)
1676         {
1677             FIXME("No chars in this glyph?  Must be an error\n");
1678             continue;
1679         }
1680
1681         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
1682         {
1683             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
1684             pCharProp[char_index[0]].fCanGlyphAlone = 1;
1685         }
1686         else
1687             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
1688     }
1689
1690     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1691     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1692 }
1693
1694 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 )
1695 {
1696     int i,k;
1697     int initGlyph, finaGlyph;
1698     INT dirR, dirL;
1699     BYTE *spaces;
1700
1701     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
1702     memset(spaces,0,cGlyphs);
1703
1704     if (!psa->fLogicalOrder && psa->fRTL)
1705     {
1706         initGlyph = cGlyphs-1;
1707         finaGlyph = 0;
1708         dirR = 1;
1709         dirL = -1;
1710     }
1711     else
1712     {
1713         initGlyph = 0;
1714         finaGlyph = cGlyphs-1;
1715         dirR = -1;
1716         dirL = 1;
1717     }
1718
1719     for (i = 0; i < cGlyphs; i++)
1720     {
1721         for (k = 0; k < cChars; k++)
1722             if (pwLogClust[k] == i)
1723             {
1724                 if (pwcChars[k] == 0x0020)
1725                     spaces[i] = 1;
1726             }
1727     }
1728
1729     for (i = 0; i < cGlyphs; i++)
1730     {
1731         int char_index[20];
1732         int char_count = 0;
1733         BOOL isInit, isFinal;
1734
1735         for (k = 0; k < cChars; k++)
1736         {
1737             if (pwLogClust[k] == i)
1738             {
1739                 char_index[char_count] = k;
1740                 char_count++;
1741             }
1742         }
1743
1744         isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
1745         isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
1746
1747         if (char_count == 0)
1748         {
1749             FIXME("No chars in this glyph?  Must be an error\n");
1750             continue;
1751         }
1752
1753         if (char_count == 1)
1754         {
1755             if (pwcChars[char_index[0]] == 0x0020)  /* space */
1756             {
1757                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
1758                 pCharProp[char_index[0]].fCanGlyphAlone = 1;
1759             }
1760             else if (pwcChars[char_index[0]] == 0x0640)  /* kashida */
1761                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
1762             else if (pwcChars[char_index[0]] == 0x0633)  /* SEEN */
1763             {
1764                 if (!isInit && !isFinal)
1765                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
1766                 else if (isInit)
1767                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
1768                 else
1769                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1770             }
1771             else if (!isInit)
1772             {
1773                 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
1774                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
1775                 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
1776                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
1777                 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
1778                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
1779                 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
1780                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
1781                 else
1782                     pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1783             }
1784             else if (!isInit && !isFinal)
1785                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
1786             else
1787                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1788         }
1789         else if (char_count == 2)
1790         {
1791             if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) ||  (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
1792                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
1793             else if (!isInit)
1794                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
1795             else
1796                 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1797         }
1798         else if (!isInit && !isFinal)
1799             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
1800         else
1801             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1802     }
1803
1804     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1805     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1806     HeapFree(GetProcessHeap(),0,spaces);
1807 }
1808
1809 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 )
1810 {
1811     int i,k;
1812     int finaGlyph;
1813     INT dirL;
1814     BYTE *spaces;
1815
1816     spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
1817     memset(spaces,0,cGlyphs);
1818
1819     if (!psa->fLogicalOrder && psa->fRTL)
1820     {
1821         finaGlyph = 0;
1822         dirL = -1;
1823     }
1824     else
1825     {
1826         finaGlyph = cGlyphs-1;
1827         dirL = 1;
1828     }
1829
1830     for (i = 0; i < cGlyphs; i++)
1831     {
1832         for (k = 0; k < cChars; k++)
1833             if (pwLogClust[k] == i)
1834             {
1835                 if (pwcChars[k] == 0x0020)
1836                     spaces[i] = 1;
1837             }
1838     }
1839
1840     for (i = 0; i < cGlyphs; i++)
1841     {
1842         int char_index[20];
1843         int char_count = 0;
1844
1845         for (k = 0; k < cChars; k++)
1846         {
1847             if (pwLogClust[k] == i)
1848             {
1849                 char_index[char_count] = k;
1850                 char_count++;
1851             }
1852         }
1853
1854         if (char_count == 0)
1855         {
1856             FIXME("No chars in this glyph?  Must be an error\n");
1857             continue;
1858         }
1859
1860         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
1861         {
1862             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
1863             pCharProp[char_index[0]].fCanGlyphAlone = 1;
1864         }
1865         else if (i == finaGlyph)
1866             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1867         else
1868             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
1869     }
1870
1871     HeapFree(GetProcessHeap(),0,spaces);
1872     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1873     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1874
1875     /* Do not allow justification between marks and their base */
1876     for (i = 0; i < cGlyphs; i++)
1877     {
1878         if (!pGlyphProp[i].sva.fClusterStart)
1879             pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1880     }
1881 }
1882
1883 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)
1884 {
1885     int i,k;
1886
1887     for (i = 0; i < cGlyphs; i++)
1888     {
1889         int char_index[20];
1890         int char_count = 0;
1891
1892         for (k = 0; k < cChars; k++)
1893         {
1894             if (pwLogClust[k] == i)
1895             {
1896                 char_index[char_count] = k;
1897                 char_count++;
1898             }
1899         }
1900
1901         if (char_count == 0)
1902         {
1903             FIXME("No chars in this glyph?  Must be an error\n");
1904             continue;
1905         }
1906
1907         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
1908         {
1909             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
1910             pCharProp[char_index[0]].fCanGlyphAlone = 1;
1911         }
1912         else
1913             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1914     }
1915     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1916     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1917 }
1918
1919 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)
1920 {
1921     int i,k;
1922
1923     for (i = 0; i < cGlyphs; i++)
1924     {
1925         int char_index[20];
1926         int char_count = 0;
1927
1928         for (k = 0; k < cChars; k++)
1929         {
1930             if (pwLogClust[k] == i)
1931             {
1932                 char_index[char_count] = k;
1933                 char_count++;
1934             }
1935         }
1936
1937         if (char_count == 0)
1938         {
1939             FIXME("No chars in this glyph?  Must be an error\n");
1940             continue;
1941         }
1942
1943         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
1944         {
1945             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
1946             pCharProp[char_index[0]].fCanGlyphAlone = 1;
1947         }
1948         else
1949             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1950     }
1951     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1952     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1953
1954     /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
1955     for (i = 0; i < cGlyphs; i++)
1956     {
1957         if (!pGlyphProp[i].sva.fClusterStart)
1958         {
1959             pGlyphProp[i].sva.fDiacritic = 0;
1960             pGlyphProp[i].sva.fZeroWidth = 0;
1961         }
1962     }
1963 }
1964
1965 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)
1966 {
1967     if (ShapingData[psa->eScript].charGlyphPropProc)
1968         ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
1969     else
1970         ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
1971 }
1972
1973 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1974 {
1975     if (ShapingData[psa->eScript].contextProc)
1976         ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
1977 }
1978
1979 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)
1980 {
1981     int i;
1982     INT dirL;
1983
1984     if (!rpRangeProperties)
1985         return;
1986
1987     if (!psc->GSUB_Table)
1988         psc->GSUB_Table = load_gsub_table(hdc);
1989
1990     if (!psc->GSUB_Table)
1991         return;
1992
1993     if (!psa->fLogicalOrder && psa->fRTL)
1994         dirL = -1;
1995     else
1996         dirL = 1;
1997
1998     for (i = 0; i < rpRangeProperties->cotfRecords; i++)
1999     {
2000         if (rpRangeProperties->potfRecords[i].lParameter > 0)
2001         apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
2002     }
2003 }
2004
2005 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
2006 {
2007 const TEXTRANGE_PROPERTIES *rpRangeProperties;
2008 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
2009
2010     SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
2011 }
2012
2013 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
2014 {
2015     const GSUB_Feature *feature;
2016     int i;
2017
2018     if (!ShapingData[psa->eScript].requiredFeatures)
2019         return S_OK;
2020
2021     if (!psc->GSUB_Table)
2022         psc->GSUB_Table = load_gsub_table(hdc);
2023
2024     /* we need to have at least one of the required features */
2025     i = 0;
2026     while (ShapingData[psa->eScript].requiredFeatures[i])
2027     {
2028         feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
2029         if (feature)
2030             return S_OK;
2031         i++;
2032     }
2033
2034     return USP_E_SCRIPT_NOT_IN_FONT;
2035 }