usp10: Update LogClust from glyph properties.
[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
47
48 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
49
50 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);
51
52 extern const unsigned short wine_shaping_table[];
53 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
54
55 enum joining_types {
56     jtU,
57     jtT,
58     jtR,
59     jtL,
60     jtD,
61     jtC
62 };
63
64 enum joined_forms {
65     Xn=0,
66     Xr,
67     Xl,
68     Xm,
69     /* Syriac Alaph */
70     Afj,
71     Afn,
72     Afx
73 };
74
75 #ifdef WORDS_BIGENDIAN
76 #define GET_BE_WORD(x) (x)
77 #else
78 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
79 #endif
80
81 /* These are all structures needed for the GSUB table */
82 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
83 #define GSUB_E_NOFEATURE -2
84 #define GSUB_E_NOGLYPH -1
85
86 typedef struct {
87     DWORD version;
88     WORD ScriptList;
89     WORD FeatureList;
90     WORD LookupList;
91 } GSUB_Header;
92
93 typedef struct {
94     CHAR ScriptTag[4];
95     WORD Script;
96 } GSUB_ScriptRecord;
97
98 typedef struct {
99     WORD ScriptCount;
100     GSUB_ScriptRecord ScriptRecord[1];
101 } GSUB_ScriptList;
102
103 typedef struct {
104     CHAR LangSysTag[4];
105     WORD LangSys;
106 } GSUB_LangSysRecord;
107
108 typedef struct {
109     WORD DefaultLangSys;
110     WORD LangSysCount;
111     GSUB_LangSysRecord LangSysRecord[1];
112 } GSUB_Script;
113
114 typedef struct {
115     WORD LookupOrder; /* Reserved */
116     WORD ReqFeatureIndex;
117     WORD FeatureCount;
118     WORD FeatureIndex[1];
119 } GSUB_LangSys;
120
121 typedef struct {
122     CHAR FeatureTag[4];
123     WORD Feature;
124 } GSUB_FeatureRecord;
125
126 typedef struct {
127     WORD FeatureCount;
128     GSUB_FeatureRecord FeatureRecord[1];
129 } GSUB_FeatureList;
130
131 typedef struct {
132     WORD FeatureParams; /* Reserved */
133     WORD LookupCount;
134     WORD LookupListIndex[1];
135 } GSUB_Feature;
136
137 typedef struct {
138     WORD LookupCount;
139     WORD Lookup[1];
140 } GSUB_LookupList;
141
142 typedef struct {
143     WORD LookupType;
144     WORD LookupFlag;
145     WORD SubTableCount;
146     WORD SubTable[1];
147 } GSUB_LookupTable;
148
149 typedef struct {
150     WORD CoverageFormat;
151     WORD GlyphCount;
152     WORD GlyphArray[1];
153 } GSUB_CoverageFormat1;
154
155 typedef struct {
156     WORD Start;
157     WORD End;
158     WORD StartCoverageIndex;
159 } GSUB_RangeRecord;
160
161 typedef struct {
162     WORD CoverageFormat;
163     WORD RangeCount;
164     GSUB_RangeRecord RangeRecord[1];
165 } GSUB_CoverageFormat2;
166
167 typedef struct {
168     WORD SubstFormat; /* = 1 */
169     WORD Coverage;
170     WORD DeltaGlyphID;
171 } GSUB_SingleSubstFormat1;
172
173 typedef struct {
174     WORD SubstFormat; /* = 2 */
175     WORD Coverage;
176     WORD GlyphCount;
177     WORD Substitute[1];
178 }GSUB_SingleSubstFormat2;
179
180 typedef struct {
181     WORD SubstFormat; /* = 1 */
182     WORD Coverage;
183     WORD LigSetCount;
184     WORD LigatureSet[1];
185 }GSUB_LigatureSubstFormat1;
186
187 typedef struct {
188     WORD LigatureCount;
189     WORD Ligature[1];
190 }GSUB_LigatureSet;
191
192 typedef struct{
193     WORD LigGlyph;
194     WORD CompCount;
195     WORD Component[1];
196 }GSUB_Ligature;
197
198 typedef struct{
199     WORD SequenceIndex;
200     WORD LookupListIndex;
201
202 }GSUB_SubstLookupRecord;
203
204 typedef struct{
205     WORD SubstFormat; /* = 1 */
206     WORD Coverage;
207     WORD ChainSubRuleSetCount;
208     WORD ChainSubRuleSet[1];
209 }GSUB_ChainContextSubstFormat1;
210
211 typedef struct {
212     WORD SubstFormat; /* = 3 */
213     WORD BacktrackGlyphCount;
214     WORD Coverage[1];
215 }GSUB_ChainContextSubstFormat3_1;
216
217 typedef struct{
218     WORD InputGlyphCount;
219     WORD Coverage[1];
220 }GSUB_ChainContextSubstFormat3_2;
221
222 typedef struct{
223     WORD LookaheadGlyphCount;
224     WORD Coverage[1];
225 }GSUB_ChainContextSubstFormat3_3;
226
227 typedef struct{
228     WORD SubstCount;
229     GSUB_SubstLookupRecord SubstLookupRecord[1];
230 }GSUB_ChainContextSubstFormat3_4;
231
232 typedef struct {
233     WORD SubstFormat; /* = 1 */
234     WORD Coverage;
235     WORD AlternateSetCount;
236     WORD AlternateSet[1];
237 } GSUB_AlternateSubstFormat1;
238
239 typedef struct{
240     WORD GlyphCount;
241     WORD Alternate[1];
242 } GSUB_AlternateSet;
243
244 /* These are all structures needed for the GDEF table */
245 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
246
247 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
248
249 typedef struct {
250     DWORD Version;
251     WORD GlyphClassDef;
252     WORD AttachList;
253     WORD LigCaretList;
254     WORD MarkAttachClassDef;
255 } GDEF_Header;
256
257 typedef struct {
258     WORD ClassFormat;
259     WORD StartGlyph;
260     WORD GlyphCount;
261     WORD ClassValueArray[1];
262 } GDEF_ClassDefFormat1;
263
264 typedef struct {
265     WORD Start;
266     WORD End;
267     WORD Class;
268 } GDEF_ClassRangeRecord;
269
270 typedef struct {
271     WORD ClassFormat;
272     WORD ClassRangeCount;
273     GDEF_ClassRangeRecord ClassRangeRecord[1];
274 } GDEF_ClassDefFormat2;
275
276 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
277
278 /* the orders of joined_forms and contextual_features need to line up */
279 static const char* contextual_features[] =
280 {
281     "isol",
282     "fina",
283     "init",
284     "medi",
285     /* Syriac Alaph */
286     "med2",
287     "fin2",
288     "fin3"
289 };
290
291 static OPENTYPE_FEATURE_RECORD standard_features[] =
292 {
293     { MS_MAKE_TAG('l','i','g','a'), 1},
294     { MS_MAKE_TAG('c','l','i','g'), 1},
295 };
296
297 static OPENTYPE_FEATURE_RECORD arabic_features[] =
298 {
299     { MS_MAKE_TAG('r','l','i','g'), 1},
300     { MS_MAKE_TAG('c','a','l','t'), 1},
301     { MS_MAKE_TAG('l','i','g','a'), 1},
302     { MS_MAKE_TAG('d','l','i','g'), 1},
303     { MS_MAKE_TAG('c','s','w','h'), 1},
304     { MS_MAKE_TAG('m','s','e','t'), 1},
305 };
306
307 static const char* required_arabic_features[] =
308 {
309     "fina",
310     "init",
311     "medi",
312     "rlig",
313     NULL
314 };
315
316 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
317 {
318     { MS_MAKE_TAG('d','l','i','g'), 1},
319 };
320
321 static OPENTYPE_FEATURE_RECORD syriac_features[] =
322 {
323     { MS_MAKE_TAG('r','l','i','g'), 1},
324     { MS_MAKE_TAG('c','a','l','t'), 1},
325     { MS_MAKE_TAG('l','i','g','a'), 1},
326     { MS_MAKE_TAG('d','l','i','g'), 1},
327 };
328
329 static const char* required_syriac_features[] =
330 {
331     "fina",
332     "fin2",
333     "fin3",
334     "init",
335     "medi",
336     "med2",
337     "rlig",
338     NULL
339 };
340
341 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
342 {
343     /* Base forms */
344     { MS_MAKE_TAG('a','k','h','n'), 1},
345     { MS_MAKE_TAG('r','p','h','f'), 1},
346     { MS_MAKE_TAG('v','a','t','u'), 1},
347     { MS_MAKE_TAG('p','s','t','f'), 1},
348     /* Presentation forms */
349     { MS_MAKE_TAG('b','l','w','s'), 1},
350     { MS_MAKE_TAG('a','b','v','s'), 1},
351     { MS_MAKE_TAG('p','s','t','s'), 1},
352 };
353
354 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
355 {
356     { MS_MAKE_TAG('a','b','v','s'), 1},
357     { MS_MAKE_TAG('b','l','w','s'), 1},
358 };
359
360 static OPENTYPE_FEATURE_RECORD thai_features[] =
361 {
362     { MS_MAKE_TAG('c','c','m','p'), 1},
363 };
364
365 static const char* required_lao_features[] =
366 {
367     "ccmp",
368     NULL
369 };
370
371 typedef struct ScriptShapeDataTag {
372     TEXTRANGE_PROPERTIES   defaultTextRange;
373     const char**           requiredFeatures;
374     CHAR                   otTag[5];
375     ContextualShapingProc  contextProc;
376     ShapeCharGlyphPropProc charGlyphPropProc;
377 } ScriptShapeData;
378
379 /* in order of scripts */
380 static const ScriptShapeData ShapingData[] =
381 {
382     {{ standard_features, 2}, NULL, "", NULL, NULL},
383     {{ standard_features, 2}, NULL, "latn", NULL, NULL},
384     {{ standard_features, 2}, NULL, "latn", NULL, NULL},
385     {{ standard_features, 2}, NULL, "latn", NULL, NULL},
386     {{ standard_features, 2}, NULL, "" , NULL, NULL},
387     {{ standard_features, 2}, NULL, "latn", NULL, NULL},
388     {{ arabic_features, 6}, required_arabic_features, "arab", ContextualShape_Arabic, NULL},
389     {{ arabic_features, 6}, required_arabic_features, "arab", ContextualShape_Arabic, NULL},
390     {{ hebrew_features, 1}, NULL, "hebr", NULL, NULL},
391     {{ syriac_features, 4}, required_syriac_features, "syrc", ContextualShape_Syriac, NULL},
392     {{ arabic_features, 6}, required_arabic_features, "arab", ContextualShape_Arabic, NULL},
393     {{ NULL, 0}, NULL, "thaa", NULL, NULL},
394     {{ standard_features, 2}, NULL, "grek", NULL, NULL},
395     {{ standard_features, 2}, NULL, "cyrl", NULL, NULL},
396     {{ standard_features, 2}, NULL, "armn", NULL, NULL},
397     {{ standard_features, 2}, NULL, "geor", NULL, NULL},
398     {{ sinhala_features, 7}, NULL, "sinh", NULL, NULL},
399     {{ tibetan_features, 2}, NULL, "tibt", NULL, NULL},
400     {{ tibetan_features, 2}, NULL, "tibt", NULL, NULL},
401     {{ tibetan_features, 2}, NULL, "phag", ContextualShape_Phags_pa, NULL},
402     {{ thai_features, 1}, NULL, "thai", NULL, NULL},
403     {{ thai_features, 1}, NULL, "thai", NULL, NULL},
404     {{ thai_features, 1}, required_lao_features, "lao", NULL, NULL},
405     {{ thai_features, 1}, required_lao_features, "lao", NULL, NULL},
406 };
407
408 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
409 {
410     const GSUB_CoverageFormat1* cf1;
411
412     cf1 = table;
413
414     if (GET_BE_WORD(cf1->CoverageFormat) == 1)
415     {
416         int count = GET_BE_WORD(cf1->GlyphCount);
417         int i;
418         TRACE("Coverage Format 1, %i glyphs\n",count);
419         for (i = 0; i < count; i++)
420             if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
421                 return i;
422         return -1;
423     }
424     else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
425     {
426         const GSUB_CoverageFormat2* cf2;
427         int i;
428         int count;
429         cf2 = (const GSUB_CoverageFormat2*)cf1;
430
431         count = GET_BE_WORD(cf2->RangeCount);
432         TRACE("Coverage Format 2, %i ranges\n",count);
433         for (i = 0; i < count; i++)
434         {
435             if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
436                 return -1;
437             if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
438                 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
439             {
440                 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
441                     glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
442             }
443         }
444         return -1;
445     }
446     else
447         ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
448
449     return -1;
450 }
451
452 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
453 {
454     const GSUB_ScriptList *script;
455     const GSUB_Script *deflt = NULL;
456     int i;
457     script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
458
459     TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
460     for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
461     {
462         const GSUB_Script *scr;
463         int offset;
464
465         offset = GET_BE_WORD(script->ScriptRecord[i].Script);
466         scr = (const GSUB_Script*)((const BYTE*)script + offset);
467
468         if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
469             return scr;
470         if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
471             deflt = scr;
472     }
473     return deflt;
474 }
475
476 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
477 {
478     int i;
479     int offset;
480     const GSUB_LangSys *Lang;
481
482     TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
483
484     for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
485     {
486         offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
487         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
488
489         if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
490             return Lang;
491     }
492     offset = GET_BE_WORD(script->DefaultLangSys);
493     if (offset)
494     {
495         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
496         return Lang;
497     }
498     return NULL;
499 }
500
501 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
502 {
503     int i;
504     const GSUB_FeatureList *feature;
505     feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
506
507     TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
508     for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
509     {
510         int index = GET_BE_WORD(lang->FeatureIndex[i]);
511         if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
512         {
513             const GSUB_Feature *feat;
514             feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
515             return feat;
516         }
517     }
518     return NULL;
519 }
520
521 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
522 {
523     int j;
524     TRACE("Single Substitution Subtable\n");
525
526     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
527     {
528         int offset;
529         const GSUB_SingleSubstFormat1 *ssf1;
530         offset = GET_BE_WORD(look->SubTable[j]);
531         ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
532         if (GET_BE_WORD(ssf1->SubstFormat) == 1)
533         {
534             int offset = GET_BE_WORD(ssf1->Coverage);
535             TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
536             if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
537             {
538                 TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
539                 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
540                 TRACE(" 0x%x\n",glyphs[glyph_index]);
541                 return glyph_index + 1;
542             }
543         }
544         else
545         {
546             const GSUB_SingleSubstFormat2 *ssf2;
547             INT index;
548             INT offset;
549
550             ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
551             offset = GET_BE_WORD(ssf1->Coverage);
552             TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
553             index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
554             TRACE("  Coverage index %i\n",index);
555             if (index != -1)
556             {
557                 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
558                     return GSUB_E_NOGLYPH;
559
560                 TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
561                 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
562                 TRACE("0x%x\n",glyphs[glyph_index]);
563                 return glyph_index + 1;
564             }
565         }
566     }
567     return GSUB_E_NOGLYPH;
568 }
569
570 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
571 {
572     int j;
573     TRACE("Alternate Substitution Subtable\n");
574
575     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
576     {
577         int offset;
578         const GSUB_AlternateSubstFormat1 *asf1;
579         INT index;
580
581         offset = GET_BE_WORD(look->SubTable[j]);
582         asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
583         offset = GET_BE_WORD(asf1->Coverage);
584
585         index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
586         if (index != -1)
587         {
588             const GSUB_AlternateSet *as;
589             offset =  GET_BE_WORD(asf1->AlternateSet[index]);
590             as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
591             FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
592             if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
593                 return GSUB_E_NOGLYPH;
594
595             TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
596             glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
597             TRACE(" 0x%x\n",glyphs[glyph_index]);
598             return glyph_index + 1;
599         }
600     }
601     return GSUB_E_NOGLYPH;
602 }
603
604 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
605 {
606     int j;
607
608     TRACE("Ligature Substitution Subtable\n");
609     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
610     {
611         const GSUB_LigatureSubstFormat1 *lsf1;
612         int offset,index;
613
614         offset = GET_BE_WORD(look->SubTable[j]);
615         lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
616         offset = GET_BE_WORD(lsf1->Coverage);
617         index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
618         TRACE("  Coverage index %i\n",index);
619         if (index != -1)
620         {
621             const GSUB_LigatureSet *ls;
622             int k, count;
623
624             offset = GET_BE_WORD(lsf1->LigatureSet[index]);
625             ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
626             count = GET_BE_WORD(ls->LigatureCount);
627             TRACE("  LigatureSet has %i members\n",count);
628             for (k = 0; k < count; k++)
629             {
630                 const GSUB_Ligature *lig;
631                 int CompCount,l,CompIndex;
632
633                 offset = GET_BE_WORD(ls->Ligature[k]);
634                 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
635                 CompCount = GET_BE_WORD(lig->CompCount) - 1;
636                 CompIndex = glyph_index+write_dir;
637                 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
638                 {
639                     int CompGlyph;
640                     CompGlyph = GET_BE_WORD(lig->Component[l]);
641                     if (CompGlyph != glyphs[CompIndex])
642                         break;
643                     CompIndex += write_dir;
644                 }
645                 if (l == CompCount)
646                 {
647                     int replaceIdx = glyph_index;
648                     if (write_dir < 0)
649                         replaceIdx = glyph_index - CompCount;
650
651                     TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
652                     glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
653                     TRACE("0x%x\n",glyphs[replaceIdx]);
654                     if (CompCount > 0)
655                     {
656                         int j;
657                         for (j = replaceIdx + 1; j < *glyph_count; j++)
658                             glyphs[j] =glyphs[j+CompCount];
659                         *glyph_count = *glyph_count - CompCount;
660                     }
661                     return replaceIdx + 1;
662                 }
663             }
664         }
665     }
666     return GSUB_E_NOGLYPH;
667 }
668
669 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
670 {
671     int j;
672     BOOL done = FALSE;
673
674     TRACE("Chaining Contextual Substitution Subtable\n");
675     for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
676     {
677         const GSUB_ChainContextSubstFormat1 *ccsf1;
678         int offset;
679         int dirLookahead = write_dir;
680         int dirBacktrack = -1 * write_dir;
681
682         offset = GET_BE_WORD(look->SubTable[j]);
683         ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
684         if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
685         {
686             FIXME("  TODO: subtype 1 (Simple context glyph substitution)\n");
687             return -1;
688         }
689         else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
690         {
691             FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
692             return -1;
693         }
694         else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
695         {
696             int k;
697             int indexGlyphs;
698             const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
699             const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
700             const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
701             const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
702             int newIndex = glyph_index;
703
704             ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
705
706             TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
707
708             for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
709             {
710                 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
711                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
712                     break;
713             }
714             if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
715                 return -1;
716             TRACE("Matched Backtrack\n");
717
718             ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
719
720             indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
721             for (k = 0; k < indexGlyphs; k++)
722             {
723                 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
724                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
725                     break;
726             }
727             if (k != indexGlyphs)
728                 return -1;
729             TRACE("Matched IndexGlyphs\n");
730
731             ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
732
733             for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
734             {
735                 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
736                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
737                     break;
738             }
739             if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
740                 return -1;
741             TRACE("Matched LookAhead\n");
742
743             ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
744
745             for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
746             {
747                 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
748                 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
749
750                 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
751                 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
752                 if (newIndex == -1)
753                 {
754                     ERR("Chain failed to generate a glyph\n");
755                     return -1;
756                 }
757             }
758             return newIndex + 1;
759         }
760     }
761     return -1;
762 }
763
764 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
765 {
766     int offset;
767     const GSUB_LookupTable *look;
768
769     offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
770     look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
771     TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
772     switch(GET_BE_WORD(look->LookupType))
773     {
774         case 1:
775             return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
776         case 3:
777             return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
778         case 4:
779             return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
780         case 6:
781             return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
782         default:
783             FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
784     }
785     return GSUB_E_NOGLYPH;
786 }
787
788 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
789 {
790     int i;
791     int out_index = GSUB_E_NOGLYPH;
792     const GSUB_LookupList *lookup;
793
794     lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
795
796     TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
797     for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
798     {
799         out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
800         if (out_index != GSUB_E_NOGLYPH)
801             break;
802     }
803     if (out_index == GSUB_E_NOGLYPH)
804         TRACE("lookups found no glyphs\n");
805     else
806     {
807         int out2;
808         out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
809         if (out2!=GSUB_E_NOGLYPH)
810             out_index = out2;
811     }
812     return out_index;
813 }
814
815 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc)
816 {
817     UINT charset;
818
819     if (psc->userScript != 0)
820         return (char*)&psc->userScript;
821
822     if (ShapingData[psa->eScript].otTag[0] != 0)
823         return ShapingData[psa->eScript].otTag;
824
825     /*
826      * fall back to the font charset
827      */
828     charset = GetTextCharsetInfo(hdc, NULL, 0x0);
829     switch (charset)
830     {
831         case ANSI_CHARSET: return "latn";
832         case BALTIC_CHARSET: return "latn"; /* ?? */
833         case CHINESEBIG5_CHARSET: return "hani";
834         case EASTEUROPE_CHARSET: return "latn"; /* ?? */
835         case GB2312_CHARSET: return "hani";
836         case GREEK_CHARSET: return "grek";
837         case HANGUL_CHARSET: return "hang";
838         case RUSSIAN_CHARSET: return "cyrl";
839         case SHIFTJIS_CHARSET: return "kana";
840         case TURKISH_CHARSET: return "latn"; /* ?? */
841         case VIETNAMESE_CHARSET: return "latn";
842         case JOHAB_CHARSET: return "latn"; /* ?? */
843         case ARABIC_CHARSET: return "arab";
844         case HEBREW_CHARSET: return "hebr";
845         case THAI_CHARSET: return "thai";
846         default: return "latn";
847     }
848 }
849
850 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
851 {
852     const GSUB_Feature *feature;
853     int i;
854
855     for (i = 0; i <  psc->feature_count; i++)
856         if (strncmp(psc->features[i].tag,feat,4)==0)
857             return psc->features[i].feature;
858
859     feature = NULL;
860
861     if (psc->GSUB_Table)
862     {
863         const GSUB_Script *script;
864         const GSUB_LangSys *language;
865
866         script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc));
867         if (script)
868         {
869             if (psc->userLang != 0)
870                 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
871             else
872                 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
873             if (language)
874                 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
875         }
876
877         /* try in the default (latin) table */
878         if (!feature)
879         {
880             script = GSUB_get_script_table(psc->GSUB_Table, "latn");
881             if (script)
882             {
883                 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
884                 if (language)
885                     feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
886             }
887         }
888     }
889
890     TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
891
892     psc->feature_count++;
893
894     if (psc->features)
895         psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
896     else
897         psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
898
899     lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
900     psc->features[psc->feature_count - 1].feature = feature;
901     return feature;
902 }
903
904 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)
905 {
906     const GSUB_Feature *feature;
907
908     feature = load_GSUB_feature(hdc, psa, psc, feat);
909     if (!feature)
910         return GSUB_E_NOFEATURE;
911
912     TRACE("applying feature %s\n",feat);
913     return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
914 }
915
916 static VOID *load_gsub_table(HDC hdc)
917 {
918     VOID* GSUB_Table = NULL;
919     int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
920     if (length != GDI_ERROR)
921     {
922         GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
923         GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
924         TRACE("Loaded GSUB table of %i bytes\n",length);
925     }
926     return GSUB_Table;
927 }
928
929 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
930 {
931     int offset;
932     WORD class = 0;
933     const GDEF_ClassDefFormat1 *cf1;
934
935     if (!header)
936         return 0;
937
938     offset = GET_BE_WORD(header->GlyphClassDef);
939     if (!offset)
940         return 0;
941
942     cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
943     if (GET_BE_WORD(cf1->ClassFormat) == 1)
944     {
945         if (glyph >= GET_BE_WORD(cf1->StartGlyph))
946         {
947             int index = glyph - GET_BE_WORD(cf1->StartGlyph);
948             if (index < GET_BE_WORD(cf1->GlyphCount))
949                 class = GET_BE_WORD(cf1->ClassValueArray[index]);
950         }
951     }
952     else if (GET_BE_WORD(cf1->ClassFormat) == 2)
953     {
954         const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
955         int i, top;
956         top = GET_BE_WORD(cf2->ClassRangeCount);
957         for (i = 0; i < top; i++)
958         {
959             if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
960                 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
961             {
962                 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
963                 break;
964             }
965         }
966     }
967     else
968         ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
969
970     return class;
971 }
972
973 static VOID *load_gdef_table(HDC hdc)
974 {
975     VOID* GDEF_Table = NULL;
976     int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
977     if (length != GDI_ERROR)
978     {
979         GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
980         GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
981         TRACE("Loaded GDEF table of %i bytes\n",length);
982     }
983     return GDEF_Table;
984 }
985
986 static void GDEF_UpdateGlyphProps(HDC hdc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
987 {
988     VOID* header = load_gdef_table(hdc);
989     int i;
990
991     for (i = 0; i < cGlyphs; i++)
992     {
993         WORD class;
994
995         class = GDEF_get_glyph_class(header, pwGlyphs[i]);
996
997         switch (class)
998         {
999             case 0:
1000             case BaseGlyph:
1001                 pGlyphProp[i].sva.fClusterStart = 1;
1002                 pGlyphProp[i].sva.fDiacritic = 0;
1003                 pGlyphProp[i].sva.fZeroWidth = 0;
1004                 break;
1005             case LigatureGlyph:
1006                 pGlyphProp[i].sva.fClusterStart = 1;
1007                 pGlyphProp[i].sva.fDiacritic = 0;
1008                 pGlyphProp[i].sva.fZeroWidth = 0;
1009                 break;
1010             case MarkGlyph:
1011                 pGlyphProp[i].sva.fClusterStart = 0;
1012                 pGlyphProp[i].sva.fDiacritic = 1;
1013                 pGlyphProp[i].sva.fZeroWidth = 1;
1014                 break;
1015             case ComponentGlyph:
1016                 pGlyphProp[i].sva.fClusterStart = 0;
1017                 pGlyphProp[i].sva.fDiacritic = 0;
1018                 pGlyphProp[i].sva.fZeroWidth = 0;
1019                 break;
1020             default:
1021                 ERR("Unknown glyph class %i\n",class);
1022                 pGlyphProp[i].sva.fClusterStart = 1;
1023                 pGlyphProp[i].sva.fDiacritic = 0;
1024                 pGlyphProp[i].sva.fZeroWidth = 0;
1025         }
1026     }
1027 }
1028
1029 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1030 {
1031     int i;
1032
1033     for (i = 0; i < cGlyphs; i++)
1034     {
1035         if (!pGlyphProp[i].sva.fClusterStart)
1036         {
1037             int j;
1038             for (j = 0; j < cChars; j++)
1039             {
1040                 if (pwLogClust[j] == i)
1041                 {
1042                     int k = j;
1043                     while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1044                         k-=1;
1045                     if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1046                         pwLogClust[j] = pwLogClust[k];
1047                 }
1048             }
1049         }
1050     }
1051 }
1052
1053 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1054 {
1055     if (changeCount == 0)
1056         return;
1057     else
1058     {
1059         int i;
1060         int target_glyph = nextIndex - 1;
1061         int target_index = -1;
1062         int replacing_glyph = -1;
1063         int changed = 0;
1064
1065         if (write_dir > 0)
1066             for (i = 0; i < chars; i++)
1067             {
1068                 if (pwLogClust[i] == target_glyph)
1069                 {
1070                     target_index = i;
1071                     break;
1072                 }
1073             }
1074         else
1075             for (i = chars - 1; i >= 0; i--)
1076             {
1077                 if (pwLogClust[i] == target_glyph)
1078                 {
1079                     target_index = i;
1080                     break;
1081                 }
1082             }
1083         if (target_index == -1)
1084         {
1085             ERR("Unable to find target glyph\n");
1086             return;
1087         }
1088
1089         if (changeCount < 0)
1090         {
1091             /* merge glyphs */
1092             for(i = target_index; i < chars && i >= 0; i+=write_dir)
1093             {
1094                 if (pwLogClust[i] == target_glyph)
1095                     continue;
1096                 if(pwLogClust[i] == replacing_glyph)
1097                     pwLogClust[i] = target_glyph;
1098                 else
1099                 {
1100                     changed--;
1101                     if (changed >= changeCount)
1102                     {
1103                         replacing_glyph = pwLogClust[i];
1104                         pwLogClust[i] = target_glyph;
1105                     }
1106                     else
1107                         break;
1108                 }
1109             }
1110         }
1111
1112         /* renumber trailing indexes*/
1113         for(i = target_index; i < chars && i >= 0; i+=write_dir)
1114         {
1115             if (pwLogClust[i] != target_glyph)
1116                 pwLogClust[i] += changeCount;
1117         }
1118     }
1119 }
1120
1121 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 )
1122 {
1123     int i;
1124
1125     if (psc->GSUB_Table)
1126     {
1127         const GSUB_Feature *feature;
1128
1129         feature = load_GSUB_feature(hdc, psa, psc, feat);
1130         if (!feature)
1131             return GSUB_E_NOFEATURE;
1132
1133         i = 0;
1134         TRACE("applying feature %s\n",debugstr_an(feat,4));
1135         while(i < *pcGlyphs)
1136         {
1137                 INT nextIndex;
1138                 INT prevCount = *pcGlyphs;
1139                 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1140                 if (nextIndex > GSUB_E_NOGLYPH)
1141                 {
1142                     UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1143                     i = nextIndex;
1144                 }
1145                 else
1146                     i++;
1147         }
1148         return *pcGlyphs;
1149     }
1150     return GSUB_E_NOFEATURE;
1151 }
1152
1153 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1154 {
1155     if (i + delta < 0)
1156         return 0;
1157     if ( i+ delta >= cchLen)
1158         return 0;
1159
1160     i += delta;
1161
1162     return chars[i];
1163 }
1164
1165 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1166 {
1167     if (i + delta < 0)
1168     {
1169         if (psa->fLinkBefore)
1170             return jtR;
1171         else
1172             return jtU;
1173     }
1174     if ( i+ delta >= cchLen)
1175     {
1176         if (psa->fLinkAfter)
1177             return jtL;
1178         else
1179             return jtU;
1180     }
1181
1182     i += delta;
1183
1184     if (context_type[i] == jtT)
1185         return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1186     else
1187         return context_type[i];
1188 }
1189
1190 static inline BOOL right_join_causing(CHAR joining_type)
1191 {
1192     return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1193 }
1194
1195 static inline BOOL left_join_causing(CHAR joining_type)
1196 {
1197     return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1198 }
1199
1200 static inline BOOL word_break_causing(WCHAR chr)
1201 {
1202     /* we are working within a string of characters already guareented to
1203        be within one script, Syriac, so we do not worry about any characers
1204        other than the space character outside of that range */
1205     return (chr == 0 || chr == 0x20 );
1206 }
1207
1208 /*
1209  * ContextualShape_Arabic
1210  */
1211 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1212 {
1213     CHAR *context_type;
1214     INT *context_shape;
1215     INT dirR, dirL;
1216     int i;
1217
1218     if (*pcGlyphs != cChars)
1219     {
1220         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1221         return;
1222     }
1223
1224     if (!psa->fLogicalOrder && psa->fRTL)
1225     {
1226         dirR = 1;
1227         dirL = -1;
1228     }
1229     else
1230     {
1231         dirR = -1;
1232         dirL = 1;
1233     }
1234
1235     if (!psc->GSUB_Table)
1236         psc->GSUB_Table = load_gsub_table(hdc);
1237
1238     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1239     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1240
1241     for (i = 0; i < cChars; i++)
1242         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1243
1244     for (i = 0; i < cChars; i++)
1245     {
1246         if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1247             context_shape[i] = Xr;
1248         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1249             context_shape[i] = Xl;
1250         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)))
1251             context_shape[i] = Xm;
1252         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1253             context_shape[i] = Xr;
1254         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1255             context_shape[i] = Xl;
1256         else
1257             context_shape[i] = Xn;
1258     }
1259
1260     /* Contextual Shaping */
1261     i = 0;
1262     while(i < *pcGlyphs)
1263     {
1264         BOOL shaped = FALSE;
1265
1266         if (psc->GSUB_Table)
1267         {
1268             INT nextIndex;
1269             INT prevCount = *pcGlyphs;
1270             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1271             if (nextIndex > GSUB_E_NOGLYPH)
1272             {
1273                 i = nextIndex;
1274                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1275             }
1276             shaped = (nextIndex > GSUB_E_NOGLYPH);
1277         }
1278
1279         if (!shaped)
1280         {
1281             WORD newGlyph = pwOutGlyphs[i];
1282             if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1283             {
1284                 /* fall back to presentation form B */
1285                 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1286                 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1287                     pwOutGlyphs[i] = newGlyph;
1288             }
1289             i++;
1290         }
1291     }
1292
1293     HeapFree(GetProcessHeap(),0,context_shape);
1294     HeapFree(GetProcessHeap(),0,context_type);
1295 }
1296
1297 /*
1298  * ContextualShape_Syriac
1299  */
1300
1301 #define ALAPH 0x710
1302 #define DALATH 0x715
1303 #define RISH 0x72A
1304
1305 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1306 {
1307     CHAR *context_type;
1308     INT *context_shape;
1309     INT dirR, dirL;
1310     int i;
1311
1312     if (*pcGlyphs != cChars)
1313     {
1314         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1315         return;
1316     }
1317
1318     if (!psa->fLogicalOrder && psa->fRTL)
1319     {
1320         dirR = 1;
1321         dirL = -1;
1322     }
1323     else
1324     {
1325         dirR = -1;
1326         dirL = 1;
1327     }
1328
1329     if (!psc->GSUB_Table)
1330         psc->GSUB_Table = load_gsub_table(hdc);
1331
1332     if (!psc->GSUB_Table)
1333         return;
1334
1335     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1336     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1337
1338     for (i = 0; i < cChars; i++)
1339         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1340
1341     for (i = 0; i < cChars; i++)
1342     {
1343         if (pwcChars[i] == ALAPH)
1344         {
1345             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1346
1347             if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1348             context_shape[i] = Afj;
1349             else if ( rchar != DALATH && rchar != RISH &&
1350 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1351 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1352             context_shape[i] = Afn;
1353             else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1354             context_shape[i] = Afx;
1355             else
1356             context_shape[i] = Xn;
1357         }
1358         else if (context_type[i] == jtR &&
1359 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1360             context_shape[i] = Xr;
1361         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1362             context_shape[i] = Xl;
1363         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)))
1364             context_shape[i] = Xm;
1365         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1366             context_shape[i] = Xr;
1367         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1368             context_shape[i] = Xl;
1369         else
1370             context_shape[i] = Xn;
1371     }
1372
1373     /* Contextual Shaping */
1374     i = 0;
1375     while(i < *pcGlyphs)
1376     {
1377         INT nextIndex;
1378         INT prevCount = *pcGlyphs;
1379         nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1380         if (nextIndex > GSUB_E_NOGLYPH)
1381         {
1382             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1383             i = nextIndex;
1384         }
1385         else
1386             i++;
1387     }
1388
1389     HeapFree(GetProcessHeap(),0,context_shape);
1390     HeapFree(GetProcessHeap(),0,context_type);
1391 }
1392
1393 /*
1394  * ContextualShape_Phags_pa
1395  */
1396
1397 #define phags_pa_CANDRABINDU  0xA873
1398 #define phags_pa_START 0xA840
1399 #define phags_pa_END  0xA87F
1400
1401 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1402 {
1403     INT *context_shape;
1404     INT dirR, dirL;
1405     int i;
1406
1407     if (*pcGlyphs != cChars)
1408     {
1409         ERR("Number of Glyphs and Chars need to match at the beginning\n");
1410         return;
1411     }
1412
1413     if (!psa->fLogicalOrder && psa->fRTL)
1414     {
1415         dirR = 1;
1416         dirL = -1;
1417     }
1418     else
1419     {
1420         dirR = -1;
1421         dirL = 1;
1422     }
1423
1424     if (!psc->GSUB_Table)
1425         psc->GSUB_Table = load_gsub_table(hdc);
1426
1427     if (!psc->GSUB_Table)
1428         return;
1429
1430     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1431
1432     for (i = 0; i < cChars; i++)
1433     {
1434         if (pwcChars[i] >= phags_pa_START && pwcChars[i] <=  phags_pa_END)
1435         {
1436             WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1437             WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1438             BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <=  phags_pa_END);
1439             BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <=  phags_pa_END);
1440
1441             if (jrchar && jlchar)
1442                 context_shape[i] = Xm;
1443             else if (jrchar)
1444                 context_shape[i] = Xr;
1445             else if (jlchar)
1446                 context_shape[i] = Xl;
1447             else
1448                 context_shape[i] = Xn;
1449         }
1450         else
1451             context_shape[i] = -1;
1452     }
1453
1454     /* Contextual Shaping */
1455     i = 0;
1456     while(i < *pcGlyphs)
1457     {
1458         if (context_shape[i] >= 0)
1459         {
1460             INT nextIndex;
1461             INT prevCount = *pcGlyphs;
1462             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1463             if (nextIndex > GSUB_E_NOGLYPH)
1464             {
1465                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1466                 i = nextIndex;
1467             }
1468             else
1469                 i++;
1470         }
1471         else
1472             i++;
1473     }
1474
1475     HeapFree(GetProcessHeap(),0,context_shape);
1476 }
1477
1478 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)
1479 {
1480     int i,k;
1481
1482     for (i = 0; i < cGlyphs; i++)
1483     {
1484         int char_index[20];
1485         int char_count = 0;
1486
1487         for (k = 0; k < cChars; k++)
1488         {
1489             if (pwLogClust[k] == i)
1490             {
1491                 char_index[char_count] = k;
1492                 char_count++;
1493             }
1494         }
1495
1496         if (char_count == 0)
1497         {
1498             FIXME("No chars in this glyph?  Must be an error\n");
1499             continue;
1500         }
1501
1502         if (char_count ==1 && pwcChars[char_index[0]] == 0x0020)  /* space */
1503         {
1504             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
1505             pCharProp[char_index[0]].fCanGlyphAlone = 1;
1506         }
1507         else
1508             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
1509     }
1510
1511     GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1512     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1513 }
1514
1515 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)
1516 {
1517     if (ShapingData[psa->eScript].charGlyphPropProc)
1518         ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
1519     else
1520         ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
1521 }
1522
1523 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1524 {
1525     if (ShapingData[psa->eScript].contextProc)
1526         ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
1527 }
1528
1529 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)
1530 {
1531     int i;
1532     INT dirL;
1533
1534     if (!rpRangeProperties)
1535         return;
1536
1537     if (!psc->GSUB_Table)
1538         psc->GSUB_Table = load_gsub_table(hdc);
1539
1540     if (!psc->GSUB_Table)
1541         return;
1542
1543     if (!psa->fLogicalOrder && psa->fRTL)
1544         dirL = -1;
1545     else
1546         dirL = 1;
1547
1548     for (i = 0; i < rpRangeProperties->cotfRecords; i++)
1549     {
1550         if (rpRangeProperties->potfRecords[i].lParameter > 0)
1551         apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
1552     }
1553 }
1554
1555 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
1556 {
1557 const TEXTRANGE_PROPERTIES *rpRangeProperties;
1558 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
1559
1560     SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
1561 }
1562
1563 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
1564 {
1565     const GSUB_Feature *feature;
1566     int i;
1567
1568     if (!ShapingData[psa->eScript].requiredFeatures)
1569         return S_OK;
1570
1571     if (!psc->GSUB_Table)
1572         psc->GSUB_Table = load_gsub_table(hdc);
1573
1574     /* we need to have at least one of the required features */
1575     i = 0;
1576     while (ShapingData[psa->eScript].requiredFeatures[i])
1577     {
1578         feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
1579         if (feature)
1580             return S_OK;
1581         i++;
1582     }
1583
1584     return USP_E_SCRIPT_NOT_IN_FONT;
1585 }