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