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