msi/tests: Skip some source tests if a required product key cannot be created.
[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 extern const unsigned short wine_shaping_table[];
41 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
42
43 enum joining_types {
44     jtU,
45     jtT,
46     jtR,
47     jtL,
48     jtD,
49     jtC
50 };
51
52 enum joined_forms {
53     Xn=0,
54     Xr,
55     Xl,
56     Xm
57 };
58
59 #ifdef WORDS_BIGENDIAN
60 #define GET_BE_WORD(x) (x)
61 #else
62 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
63 #endif
64
65 /* These are all structures needed for the GSUB table */
66 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
67           ( ( (ULONG)_x4 << 24 ) |     \
68             ( (ULONG)_x3 << 16 ) |     \
69             ( (ULONG)_x2 <<  8 ) |     \
70               (ULONG)_x1         )
71
72 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
73 #define GSUB_E_NOFEATURE -2
74 #define GSUB_E_NOGLYPH -1
75
76 typedef struct {
77     DWORD version;
78     WORD ScriptList;
79     WORD FeatureList;
80     WORD LookupList;
81 } GSUB_Header;
82
83 typedef struct {
84     CHAR ScriptTag[4];
85     WORD Script;
86 } GSUB_ScriptRecord;
87
88 typedef struct {
89     WORD ScriptCount;
90     GSUB_ScriptRecord ScriptRecord[1];
91 } GSUB_ScriptList;
92
93 typedef struct {
94     CHAR LangSysTag[4];
95     WORD LangSys;
96 } GSUB_LangSysRecord;
97
98 typedef struct {
99     WORD DefaultLangSys;
100     WORD LangSysCount;
101     GSUB_LangSysRecord LangSysRecord[1];
102 } GSUB_Script;
103
104 typedef struct {
105     WORD LookupOrder; /* Reserved */
106     WORD ReqFeatureIndex;
107     WORD FeatureCount;
108     WORD FeatureIndex[1];
109 } GSUB_LangSys;
110
111 typedef struct {
112     CHAR FeatureTag[4];
113     WORD Feature;
114 } GSUB_FeatureRecord;
115
116 typedef struct {
117     WORD FeatureCount;
118     GSUB_FeatureRecord FeatureRecord[1];
119 } GSUB_FeatureList;
120
121 typedef struct {
122     WORD FeatureParams; /* Reserved */
123     WORD LookupCount;
124     WORD LookupListIndex[1];
125 } GSUB_Feature;
126
127 typedef struct {
128     WORD LookupCount;
129     WORD Lookup[1];
130 } GSUB_LookupList;
131
132 typedef struct {
133     WORD LookupType;
134     WORD LookupFlag;
135     WORD SubTableCount;
136     WORD SubTable[1];
137 } GSUB_LookupTable;
138
139 typedef struct {
140     WORD CoverageFormat;
141     WORD GlyphCount;
142     WORD GlyphArray[1];
143 } GSUB_CoverageFormat1;
144
145 typedef struct {
146     WORD Start;
147     WORD End;
148     WORD StartCoverageIndex;
149 } GSUB_RangeRecord;
150
151 typedef struct {
152     WORD CoverageFormat;
153     WORD RangeCount;
154     GSUB_RangeRecord RangeRecord[1];
155 } GSUB_CoverageFormat2;
156
157 typedef struct {
158     WORD SubstFormat; /* = 1 */
159     WORD Coverage;
160     WORD DeltaGlyphID;
161 } GSUB_SingleSubstFormat1;
162
163 typedef struct {
164     WORD SubstFormat; /* = 2 */
165     WORD Coverage;
166     WORD GlyphCount;
167     WORD Substitute[1];
168 }GSUB_SingleSubstFormat2;
169
170 typedef struct {
171     WORD SubstFormat; /* = 1 */
172     WORD Coverage;
173     WORD LigSetCount;
174     WORD LigatureSet[1];
175 }GSUB_LigatureSubstFormat1;
176
177 typedef struct {
178     WORD LigatureCount;
179     WORD Ligature[1];
180 }GSUB_LigatureSet;
181
182 typedef struct{
183     WORD LigGlyph;
184     WORD CompCount;
185     WORD Component[1];
186 }GSUB_Ligature;
187
188 /* the orders of joined_forms and contextual_features need to line up */
189 static const char* contextual_features[] =
190 {
191     "isol",
192     "fina",
193     "init",
194     "medi"
195 };
196
197 static const char* arabic_GSUB_features[] =
198 {
199     "rlig",
200     "calt",
201     "liga",
202     "dlig",
203     "cswh",
204     "mset",
205     NULL
206 };
207
208 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
209 {
210     const GSUB_CoverageFormat1* cf1;
211
212     cf1 = table;
213
214     if (GET_BE_WORD(cf1->CoverageFormat) == 1)
215     {
216         int count = GET_BE_WORD(cf1->GlyphCount);
217         int i;
218         TRACE("Coverage Format 1, %i glyphs\n",count);
219         for (i = 0; i < count; i++)
220             if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
221                 return i;
222         return -1;
223     }
224     else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
225     {
226         const GSUB_CoverageFormat2* cf2;
227         int i;
228         int count;
229         cf2 = (const GSUB_CoverageFormat2*)cf1;
230
231         count = GET_BE_WORD(cf2->RangeCount);
232         TRACE("Coverage Format 2, %i ranges\n",count);
233         for (i = 0; i < count; i++)
234         {
235             if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
236                 return -1;
237             if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
238                 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
239             {
240                 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
241                     glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
242             }
243         }
244         return -1;
245     }
246     else
247         ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
248
249     return -1;
250 }
251
252 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
253 {
254     const GSUB_ScriptList *script;
255     const GSUB_Script *deflt = NULL;
256     int i;
257     script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
258
259     TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
260     for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
261     {
262         const GSUB_Script *scr;
263         int offset;
264
265         offset = GET_BE_WORD(script->ScriptRecord[i].Script);
266         scr = (const GSUB_Script*)((const BYTE*)script + offset);
267
268         if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
269             return scr;
270         if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
271             deflt = scr;
272     }
273     return deflt;
274 }
275
276 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
277 {
278     int i;
279     int offset;
280     const GSUB_LangSys *Lang;
281
282     TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
283
284     for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
285     {
286         offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
287         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
288
289         if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
290             return Lang;
291     }
292     offset = GET_BE_WORD(script->DefaultLangSys);
293     if (offset)
294     {
295         Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
296         return Lang;
297     }
298     return NULL;
299 }
300
301 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
302 {
303     int i;
304     const GSUB_FeatureList *feature;
305     feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
306
307     TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
308     for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
309     {
310         int index = GET_BE_WORD(lang->FeatureIndex[i]);
311         if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
312         {
313             const GSUB_Feature *feat;
314             feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
315             return feat;
316         }
317     }
318     return NULL;
319 }
320
321 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
322 {
323     int j;
324     TRACE("Single Substitution Subtable\n");
325
326     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
327     {
328         int offset;
329         const GSUB_SingleSubstFormat1 *ssf1;
330         offset = GET_BE_WORD(look->SubTable[j]);
331         ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
332         if (GET_BE_WORD(ssf1->SubstFormat) == 1)
333         {
334             int offset = GET_BE_WORD(ssf1->Coverage);
335             TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
336             if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
337             {
338                 TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
339                 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
340                 TRACE(" 0x%x\n",glyphs[glyph_index]);
341                 return glyph_index + 1;
342             }
343         }
344         else
345         {
346             const GSUB_SingleSubstFormat2 *ssf2;
347             INT index;
348             INT offset;
349
350             ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
351             offset = GET_BE_WORD(ssf1->Coverage);
352             TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
353             index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
354             TRACE("  Coverage index %i\n",index);
355             if (index != -1)
356             {
357                 TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
358                 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
359                 TRACE("0x%x\n",glyphs[glyph_index]);
360                 return glyph_index + 1;
361             }
362         }
363     }
364     return GSUB_E_NOGLYPH;
365 }
366
367 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
368 {
369     int j;
370
371     TRACE("Ligature Substitution Subtable\n");
372     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
373     {
374         const GSUB_LigatureSubstFormat1 *lsf1;
375         int offset,index;
376
377         offset = GET_BE_WORD(look->SubTable[j]);
378         lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
379         offset = GET_BE_WORD(lsf1->Coverage);
380         index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
381         TRACE("  Coverage index %i\n",index);
382         if (index != -1)
383         {
384             const GSUB_LigatureSet *ls;
385             int k, count;
386
387             offset = GET_BE_WORD(lsf1->LigatureSet[index]);
388             ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
389             count = GET_BE_WORD(ls->LigatureCount);
390             TRACE("  LigatureSet has %i members\n",count);
391             for (k = 0; k < count; k++)
392             {
393                 const GSUB_Ligature *lig;
394                 int CompCount,l,CompIndex;
395
396                 offset = GET_BE_WORD(ls->Ligature[k]);
397                 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
398                 CompCount = GET_BE_WORD(lig->CompCount) - 1;
399                 CompIndex = glyph_index+write_dir;
400                 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
401                 {
402                     int CompGlyph;
403                     CompGlyph = GET_BE_WORD(lig->Component[l]);
404                     if (CompGlyph != glyphs[CompIndex])
405                         break;
406                     CompIndex += write_dir;
407                 }
408                 if (l == CompCount)
409                 {
410                     int replaceIdx = glyph_index;
411                     if (write_dir < 0)
412                         replaceIdx = glyph_index - CompCount;
413
414                     TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
415                     glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
416                     TRACE("0x%x\n",glyphs[replaceIdx]);
417                     if (CompCount > 0)
418                     {
419                         int j;
420                         for (j = replaceIdx + 1; j < *glyph_count; j++)
421                             glyphs[j] =glyphs[j+CompCount];
422                         *glyph_count = *glyph_count - CompCount;
423                     }
424                     return replaceIdx + 1;
425                 }
426             }
427         }
428     }
429     return GSUB_E_NOGLYPH;
430 }
431
432 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
433 {
434     int offset;
435     const GSUB_LookupTable *look;
436
437     offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
438     look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
439     TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
440     switch(GET_BE_WORD(look->LookupType))
441     {
442         case 1:
443             return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
444         case 4:
445             return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
446         default:
447             FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
448     }
449     return GSUB_E_NOGLYPH;
450 }
451
452 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
453 {
454     int i;
455     int out_index = GSUB_E_NOGLYPH;
456     const GSUB_LookupList *lookup;
457
458     lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
459
460     TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
461     for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
462     {
463         out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
464         if (out_index != GSUB_E_NOGLYPH)
465             break;
466     }
467     if (out_index == GSUB_E_NOGLYPH)
468         TRACE("lookups found no glyphs\n");
469     return out_index;
470 }
471
472 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa)
473 {
474     UINT charset;
475
476     switch (psa->eScript)
477     {
478         case Script_Arabic:
479             return "arab";
480         case Script_Syriac:
481             return "syrc";
482         case Script_Hebrew:
483             return "hebr";
484         case Script_Latin:
485         case Script_Numeric:
486         case Script_CR:
487         case Script_LF:
488             return "latn";
489     }
490
491     /*
492      * fall back to the font charset
493      */
494     charset = GetTextCharsetInfo(hdc, NULL, 0x0);
495     switch (charset)
496     {
497         case ANSI_CHARSET: return "latn";
498         case BALTIC_CHARSET: return "latn"; /* ?? */
499         case CHINESEBIG5_CHARSET: return "hani";
500         case EASTEUROPE_CHARSET: return "latn"; /* ?? */
501         case GB2312_CHARSET: return "hani";
502         case GREEK_CHARSET: return "grek";
503         case HANGUL_CHARSET: return "hang";
504         case RUSSIAN_CHARSET: return "cyrl";
505         case SHIFTJIS_CHARSET: return "kana";
506         case TURKISH_CHARSET: return "latn"; /* ?? */
507         case VIETNAMESE_CHARSET: return "latn";
508         case JOHAB_CHARSET: return "latn"; /* ?? */
509         case ARABIC_CHARSET: return "arab";
510         case HEBREW_CHARSET: return "hebr";
511         case THAI_CHARSET: return "thai";
512         default: return "latn";
513     }
514 }
515
516 static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, void* GSUB_Table, WORD *glyphs, INT index, INT write_dir, INT* glyph_count, const char* feat)
517 {
518     const GSUB_Header *header;
519     const GSUB_Script *script;
520     const GSUB_LangSys *language;
521     const GSUB_Feature *feature;
522
523     if (!GSUB_Table)
524         return GSUB_E_NOFEATURE;
525
526     header = GSUB_Table;
527
528     script = GSUB_get_script_table(header, get_opentype_script(hdc,psa));
529     if (!script)
530     {
531         TRACE("Script not found\n");
532         return GSUB_E_NOFEATURE;
533     }
534     language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
535     if (!language)
536     {
537         TRACE("Language not found\n");
538         return GSUB_E_NOFEATURE;
539     }
540     feature  =  GSUB_get_feature(header, language, feat);
541     if (!feature)
542     {
543         TRACE("%s feature not found\n",feat);
544         return GSUB_E_NOFEATURE;
545     }
546     TRACE("applying feature %s\n",feat);
547     return GSUB_apply_feature(header, feature, glyphs, index, write_dir, glyph_count);
548 }
549
550 static VOID *load_gsub_table(HDC hdc)
551 {
552     VOID* GSUB_Table = NULL;
553     int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
554     if (length != GDI_ERROR)
555     {
556         GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
557         GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
558         TRACE("Loaded GSUB table of %i bytes\n",length);
559     }
560     return GSUB_Table;
561 }
562
563 static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, void* GSUB_Table, WORD *pwOutGlyphs, int write_dir, INT* pcGlyphs, const char* feat)
564 {
565     int i;
566
567     if (GSUB_Table)
568     {
569         const GSUB_Header *header;
570         const GSUB_Script *script;
571         const GSUB_LangSys *language;
572         const GSUB_Feature *feature;
573
574         if (!GSUB_Table)
575             return GSUB_E_NOFEATURE;
576
577         header = GSUB_Table;
578
579         script = GSUB_get_script_table(header, get_opentype_script(hdc,psa));
580         if (!script)
581         {
582             TRACE("Script not found\n");
583             return GSUB_E_NOFEATURE;
584         }
585         language = GSUB_get_lang_table(script, "xxxx");
586         if (!language)
587         {
588             TRACE("Language not found\n");
589             return GSUB_E_NOFEATURE;
590         }
591         feature  =  GSUB_get_feature(header, language, feat);
592         if (!feature)
593         {
594             TRACE("%s feature not found\n",feat);
595             return GSUB_E_NOFEATURE;
596         }
597
598         i = 0;
599         TRACE("applying feature %s\n",feat);
600         while(i < *pcGlyphs)
601         {
602                 INT nextIndex;
603                 nextIndex = GSUB_apply_feature(header, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
604                 if (nextIndex > GSUB_E_NOGLYPH)
605                     i = nextIndex;
606                 else
607                     i++;
608         }
609         return *pcGlyphs;
610     }
611     return GSUB_E_NOFEATURE;
612 }
613
614 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
615 {
616     if (i + delta < 0)
617     {
618         if (psa->fLinkBefore)
619             return jtR;
620         else
621             return jtU;
622     }
623     if ( i+ delta >= cchLen)
624     {
625         if (psa->fLinkAfter)
626             return jtL;
627         else
628             return jtU;
629     }
630
631     i += delta;
632
633     if (context_type[i] == jtT)
634         return neighbour_joining_type(i,delta,context_type,cchLen,psa);
635     else
636         return context_type[i];
637 }
638
639 static inline BOOL right_join_causing(CHAR joining_type)
640 {
641     return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
642 }
643
644 static inline BOOL left_join_causing(CHAR joining_type)
645 {
646     return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
647 }
648
649 /* SHAPE_ShapeArabicGlyphs
650  */
651 void SHAPE_ShapeArabicGlyphs(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs)
652 {
653     CHAR *context_type;
654     INT *context_shape;
655     INT dirR, dirL;
656     int i;
657
658     if (psa->eScript != Script_Arabic)
659         return;
660
661     if (*pcGlyphs != cChars)
662     {
663         ERR("Number of Glyphs and Chars need to match at the beginning\n");
664         return;
665     }
666
667
668     if (!psa->fLogicalOrder && psa->fRTL)
669     {
670         dirR = 1;
671         dirL = -1;
672     }
673     else
674     {
675         dirR = -1;
676         dirL = 1;
677     }
678
679     if (!psc->GSUB_Table)
680         psc->GSUB_Table = load_gsub_table(hdc);
681
682     context_type = HeapAlloc(GetProcessHeap(),0,cChars);
683     context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
684
685     for (i = 0; i < cChars; i++)
686         context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
687
688     for (i = 0; i < cChars; i++)
689     {
690         if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
691             context_shape[i] = Xr;
692         else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
693             context_shape[i] = Xl;
694         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)))
695             context_shape[i] = Xm;
696         else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
697             context_shape[i] = Xr;
698         else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
699             context_shape[i] = Xl;
700         else
701             context_shape[i] = Xn;
702     }
703
704     /* Contextual Shaping */
705     i = 0;
706     while(i < *pcGlyphs)
707     {
708         BOOL shaped = FALSE;
709
710         if (psc->GSUB_Table)
711         {
712             INT nextIndex;
713             nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc->GSUB_Table, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
714             if (nextIndex > GSUB_E_NOGLYPH)
715                 i = nextIndex;
716             shaped = (nextIndex > GSUB_E_NOGLYPH);
717         }
718
719         if (!shaped)
720         {
721             WORD newGlyph = pwOutGlyphs[i];
722             if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
723             {
724                 /* fall back to presentation form B */
725                 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
726                 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
727                     pwOutGlyphs[i] = newGlyph;
728             }
729             i++;
730         }
731     }
732
733     i = 0;
734     while (arabic_GSUB_features[i] != NULL)
735     {
736         apply_GSUB_feature(hdc, psa, psc->GSUB_Table, pwOutGlyphs, dirL, pcGlyphs, arabic_GSUB_features[i]);
737         i++;
738     }
739
740     HeapFree(GetProcessHeap(),0,context_shape);
741     HeapFree(GetProcessHeap(),0,context_type);
742 }