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