d3d9/tests: Add tests for IDirect3DCubeTexture9::GetLevelDesc and IDirect3DCubeTextur...
[wine] / dlls / usp10 / opentype.c
1 /*
2  * Opentype font interfaces for the Uniscribe Script Processor (usp10.dll)
3  *
4  * Copyright 2012 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 #include <stdlib.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
31
32 #include "usp10_internal.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
37
38 #ifdef WORDS_BIGENDIAN
39 #define GET_BE_WORD(x) (x)
40 #define GET_BE_DWORD(x) (x)
41 #else
42 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
43 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
44 #endif
45
46 /* These are all structures needed for the cmap format 12 table */
47 #define CMAP_TAG MS_MAKE_TAG('c', 'm', 'a', 'p')
48
49 typedef struct {
50     WORD platformID;
51     WORD encodingID;
52     DWORD offset;
53 } CMAP_EncodingRecord;
54
55 typedef struct {
56     WORD version;
57     WORD numTables;
58     CMAP_EncodingRecord tables[1];
59 } CMAP_Header;
60
61 typedef struct {
62     DWORD startCharCode;
63     DWORD endCharCode;
64     DWORD startGlyphID;
65 } CMAP_SegmentedCoverage_group;
66
67 typedef struct {
68     WORD format;
69     WORD reserved;
70     DWORD length;
71     DWORD language;
72     DWORD nGroups;
73     CMAP_SegmentedCoverage_group groups[1];
74 } CMAP_SegmentedCoverage;
75
76 /* These are all structures needed for the GDEF table */
77 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
78
79 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
80
81 typedef struct {
82     DWORD Version;
83     WORD GlyphClassDef;
84     WORD AttachList;
85     WORD LigCaretList;
86     WORD MarkAttachClassDef;
87 } GDEF_Header;
88
89 typedef struct {
90     WORD ClassFormat;
91     WORD StartGlyph;
92     WORD GlyphCount;
93     WORD ClassValueArray[1];
94 } GDEF_ClassDefFormat1;
95
96 typedef struct {
97     WORD Start;
98     WORD End;
99     WORD Class;
100 } GDEF_ClassRangeRecord;
101
102 typedef struct {
103     WORD ClassFormat;
104     WORD ClassRangeCount;
105     GDEF_ClassRangeRecord ClassRangeRecord[1];
106 } GDEF_ClassDefFormat2;
107
108 /* These are all structures needed for the GSUB table */
109
110 typedef struct {
111     DWORD version;
112     WORD ScriptList;
113     WORD FeatureList;
114     WORD LookupList;
115 } GSUB_Header;
116
117 typedef struct {
118     CHAR ScriptTag[4];
119     WORD Script;
120 } GSUB_ScriptRecord;
121
122 typedef struct {
123     WORD ScriptCount;
124     GSUB_ScriptRecord ScriptRecord[1];
125 } GSUB_ScriptList;
126
127 typedef struct {
128     CHAR LangSysTag[4];
129     WORD LangSys;
130 } GSUB_LangSysRecord;
131
132 typedef struct {
133     WORD DefaultLangSys;
134     WORD LangSysCount;
135     GSUB_LangSysRecord LangSysRecord[1];
136 } GSUB_Script;
137
138 typedef struct {
139     WORD LookupOrder; /* Reserved */
140     WORD ReqFeatureIndex;
141     WORD FeatureCount;
142     WORD FeatureIndex[1];
143 } GSUB_LangSys;
144
145 typedef struct {
146     CHAR FeatureTag[4];
147     WORD Feature;
148 } GSUB_FeatureRecord;
149
150 typedef struct {
151     WORD FeatureCount;
152     GSUB_FeatureRecord FeatureRecord[1];
153 } GSUB_FeatureList;
154
155 typedef struct {
156     WORD FeatureParams; /* Reserved */
157     WORD LookupCount;
158     WORD LookupListIndex[1];
159 } GSUB_Feature;
160
161 typedef struct {
162     WORD LookupCount;
163     WORD Lookup[1];
164 } GSUB_LookupList;
165
166 typedef struct {
167     WORD LookupType;
168     WORD LookupFlag;
169     WORD SubTableCount;
170     WORD SubTable[1];
171 } GSUB_LookupTable;
172
173 typedef struct {
174     WORD CoverageFormat;
175     WORD GlyphCount;
176     WORD GlyphArray[1];
177 } GSUB_CoverageFormat1;
178
179 typedef struct {
180     WORD Start;
181     WORD End;
182     WORD StartCoverageIndex;
183 } GSUB_RangeRecord;
184
185 typedef struct {
186     WORD CoverageFormat;
187     WORD RangeCount;
188     GSUB_RangeRecord RangeRecord[1];
189 } GSUB_CoverageFormat2;
190
191 typedef struct {
192     WORD SubstFormat; /* = 1 */
193     WORD Coverage;
194     WORD DeltaGlyphID;
195 } GSUB_SingleSubstFormat1;
196
197 typedef struct {
198     WORD SubstFormat; /* = 2 */
199     WORD Coverage;
200     WORD GlyphCount;
201     WORD Substitute[1];
202 }GSUB_SingleSubstFormat2;
203
204 typedef struct {
205     WORD SubstFormat; /* = 1 */
206     WORD Coverage;
207     WORD SequenceCount;
208     WORD Sequence[1];
209 }GSUB_MultipleSubstFormat1;
210
211 typedef struct {
212     WORD GlyphCount;
213     WORD Substitute[1];
214 }GSUB_Sequence;
215
216 typedef struct {
217     WORD SubstFormat; /* = 1 */
218     WORD Coverage;
219     WORD LigSetCount;
220     WORD LigatureSet[1];
221 }GSUB_LigatureSubstFormat1;
222
223 typedef struct {
224     WORD LigatureCount;
225     WORD Ligature[1];
226 }GSUB_LigatureSet;
227
228 typedef struct{
229     WORD LigGlyph;
230     WORD CompCount;
231     WORD Component[1];
232 }GSUB_Ligature;
233
234 typedef struct{
235     WORD SequenceIndex;
236     WORD LookupListIndex;
237
238 }GSUB_SubstLookupRecord;
239
240 typedef struct{
241     WORD SubstFormat; /* = 1 */
242     WORD Coverage;
243     WORD ChainSubRuleSetCount;
244     WORD ChainSubRuleSet[1];
245 }GSUB_ChainContextSubstFormat1;
246
247 typedef struct {
248     WORD SubstFormat; /* = 3 */
249     WORD BacktrackGlyphCount;
250     WORD Coverage[1];
251 }GSUB_ChainContextSubstFormat3_1;
252
253 typedef struct{
254     WORD InputGlyphCount;
255     WORD Coverage[1];
256 }GSUB_ChainContextSubstFormat3_2;
257
258 typedef struct{
259     WORD LookaheadGlyphCount;
260     WORD Coverage[1];
261 }GSUB_ChainContextSubstFormat3_3;
262
263 typedef struct{
264     WORD SubstCount;
265     GSUB_SubstLookupRecord SubstLookupRecord[1];
266 }GSUB_ChainContextSubstFormat3_4;
267
268 typedef struct {
269     WORD SubstFormat; /* = 1 */
270     WORD Coverage;
271     WORD AlternateSetCount;
272     WORD AlternateSet[1];
273 } GSUB_AlternateSubstFormat1;
274
275 typedef struct{
276     WORD GlyphCount;
277     WORD Alternate[1];
278 } GSUB_AlternateSet;
279
280 /**********
281  * CMAP
282  **********/
283
284 static VOID *load_CMAP_format12_table(HDC hdc, ScriptCache *psc)
285 {
286     CMAP_Header *CMAP_Table = NULL;
287     int length;
288     int i;
289
290     if (!psc->CMAP_Table)
291     {
292         length = GetFontData(hdc, CMAP_TAG , 0, NULL, 0);
293         if (length != GDI_ERROR)
294         {
295             psc->CMAP_Table = HeapAlloc(GetProcessHeap(),0,length);
296             GetFontData(hdc, CMAP_TAG , 0, psc->CMAP_Table, length);
297             TRACE("Loaded cmap table of %i bytes\n",length);
298         }
299         else
300             return NULL;
301     }
302
303     CMAP_Table = psc->CMAP_Table;
304
305     for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
306     {
307         if ( (GET_BE_WORD(CMAP_Table->tables[i].platformID) == 3) &&
308              (GET_BE_WORD(CMAP_Table->tables[i].encodingID) == 10) )
309         {
310             CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
311             if (GET_BE_WORD(format->format) == 12)
312                 return format;
313         }
314     }
315     return NULL;
316 }
317
318 static int compare_group(const void *a, const void* b)
319 {
320     const DWORD *chr = a;
321     const CMAP_SegmentedCoverage_group *group = b;
322
323     if (*chr < GET_BE_DWORD(group->startCharCode))
324         return -1;
325     if (*chr > GET_BE_DWORD(group->endCharCode))
326         return 1;
327     return 0;
328 }
329
330 DWORD OpenType_CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, LPWORD pgi, DWORD flags)
331 {
332     /* BMP: use gdi32 for ease */
333     if (utf32c < 0x10000)
334     {
335         WCHAR ch = utf32c;
336         return GetGlyphIndicesW(hdc,&ch, 1, pgi, flags);
337     }
338
339     if (!psc->CMAP_format12_Table)
340         psc->CMAP_format12_Table = load_CMAP_format12_table(hdc, psc);
341
342     if (flags & GGI_MARK_NONEXISTING_GLYPHS)
343         *pgi = 0xffff;
344     else
345         *pgi = 0;
346
347     if (psc->CMAP_format12_Table)
348     {
349         CMAP_SegmentedCoverage *format = NULL;
350         CMAP_SegmentedCoverage_group *group = NULL;
351
352         format = (CMAP_SegmentedCoverage *)psc->CMAP_format12_Table;
353
354         group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
355                         sizeof(CMAP_SegmentedCoverage_group), compare_group);
356
357         if (group)
358         {
359             DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
360             *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
361             return 0;
362         }
363     }
364     return 0;
365 }
366
367 /**********
368  * GDEF
369  **********/
370
371 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
372 {
373     int offset;
374     WORD class = 0;
375     const GDEF_ClassDefFormat1 *cf1;
376
377     if (!header)
378         return 0;
379
380     offset = GET_BE_WORD(header->GlyphClassDef);
381     if (!offset)
382         return 0;
383
384     cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
385     if (GET_BE_WORD(cf1->ClassFormat) == 1)
386     {
387         if (glyph >= GET_BE_WORD(cf1->StartGlyph))
388         {
389             int index = glyph - GET_BE_WORD(cf1->StartGlyph);
390             if (index < GET_BE_WORD(cf1->GlyphCount))
391                 class = GET_BE_WORD(cf1->ClassValueArray[index]);
392         }
393     }
394     else if (GET_BE_WORD(cf1->ClassFormat) == 2)
395     {
396         const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
397         int i, top;
398         top = GET_BE_WORD(cf2->ClassRangeCount);
399         for (i = 0; i < top; i++)
400         {
401             if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
402                 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
403             {
404                 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
405                 break;
406             }
407         }
408     }
409     else
410         ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
411
412     return class;
413 }
414
415 static VOID *load_gdef_table(HDC hdc)
416 {
417     VOID* GDEF_Table = NULL;
418     int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
419     if (length != GDI_ERROR)
420     {
421         GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
422         GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
423         TRACE("Loaded GDEF table of %i bytes\n",length);
424     }
425     return GDEF_Table;
426 }
427
428 void OpenType_GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
429 {
430     int i;
431
432     if (!psc->GDEF_Table)
433         psc->GDEF_Table = load_gdef_table(hdc);
434
435     for (i = 0; i < cGlyphs; i++)
436     {
437         WORD class;
438         int char_count = 0;
439         int k;
440
441         k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
442         if (k >= 0)
443         {
444             for (; k < cChars && pwLogClust[k] == i; k++)
445                 char_count++;
446         }
447
448         class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
449
450         switch (class)
451         {
452             case 0:
453             case BaseGlyph:
454                 pGlyphProp[i].sva.fClusterStart = 1;
455                 pGlyphProp[i].sva.fDiacritic = 0;
456                 pGlyphProp[i].sva.fZeroWidth = 0;
457                 break;
458             case LigatureGlyph:
459                 pGlyphProp[i].sva.fClusterStart = 1;
460                 pGlyphProp[i].sva.fDiacritic = 0;
461                 pGlyphProp[i].sva.fZeroWidth = 0;
462                 break;
463             case MarkGlyph:
464                 pGlyphProp[i].sva.fClusterStart = 0;
465                 pGlyphProp[i].sva.fDiacritic = 1;
466                 pGlyphProp[i].sva.fZeroWidth = 1;
467                 break;
468             case ComponentGlyph:
469                 pGlyphProp[i].sva.fClusterStart = 0;
470                 pGlyphProp[i].sva.fDiacritic = 0;
471                 pGlyphProp[i].sva.fZeroWidth = 0;
472                 break;
473             default:
474                 ERR("Unknown glyph class %i\n",class);
475                 pGlyphProp[i].sva.fClusterStart = 1;
476                 pGlyphProp[i].sva.fDiacritic = 0;
477                 pGlyphProp[i].sva.fZeroWidth = 0;
478         }
479
480         if (char_count == 0)
481             pGlyphProp[i].sva.fClusterStart = 0;
482     }
483 }
484
485 /**********
486  * GSUB
487  **********/
488 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
489
490 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
491 {
492     const GSUB_CoverageFormat1* cf1;
493
494     cf1 = table;
495
496     if (GET_BE_WORD(cf1->CoverageFormat) == 1)
497     {
498         int count = GET_BE_WORD(cf1->GlyphCount);
499         int i;
500         TRACE("Coverage Format 1, %i glyphs\n",count);
501         for (i = 0; i < count; i++)
502             if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
503                 return i;
504         return -1;
505     }
506     else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
507     {
508         const GSUB_CoverageFormat2* cf2;
509         int i;
510         int count;
511         cf2 = (const GSUB_CoverageFormat2*)cf1;
512
513         count = GET_BE_WORD(cf2->RangeCount);
514         TRACE("Coverage Format 2, %i ranges\n",count);
515         for (i = 0; i < count; i++)
516         {
517             if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
518                 return -1;
519             if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
520                 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
521             {
522                 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
523                     glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
524             }
525         }
526         return -1;
527     }
528     else
529         ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
530
531     return -1;
532 }
533
534 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
535 {
536     int j;
537     TRACE("Single Substitution Subtable\n");
538
539     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
540     {
541         int offset;
542         const GSUB_SingleSubstFormat1 *ssf1;
543         offset = GET_BE_WORD(look->SubTable[j]);
544         ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
545         if (GET_BE_WORD(ssf1->SubstFormat) == 1)
546         {
547             int offset = GET_BE_WORD(ssf1->Coverage);
548             TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
549             if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
550             {
551                 TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
552                 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
553                 TRACE(" 0x%x\n",glyphs[glyph_index]);
554                 return glyph_index + write_dir;
555             }
556         }
557         else
558         {
559             const GSUB_SingleSubstFormat2 *ssf2;
560             INT index;
561             INT offset;
562
563             ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
564             offset = GET_BE_WORD(ssf1->Coverage);
565             TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
566             index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
567             TRACE("  Coverage index %i\n",index);
568             if (index != -1)
569             {
570                 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
571                     return GSUB_E_NOGLYPH;
572
573                 TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
574                 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
575                 TRACE("0x%x\n",glyphs[glyph_index]);
576                 return glyph_index + write_dir;
577             }
578         }
579     }
580     return GSUB_E_NOGLYPH;
581 }
582
583 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
584 {
585     int j;
586     TRACE("Multiple Substitution Subtable\n");
587
588     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
589     {
590         int offset, index;
591         const GSUB_MultipleSubstFormat1 *msf1;
592         offset = GET_BE_WORD(look->SubTable[j]);
593         msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
594
595         offset = GET_BE_WORD(msf1->Coverage);
596         index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
597         if (index != -1)
598         {
599             const GSUB_Sequence *seq;
600             int sub_count;
601             int j;
602             offset = GET_BE_WORD(msf1->Sequence[index]);
603             seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
604             sub_count = GET_BE_WORD(seq->GlyphCount);
605             TRACE("  Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
606
607             for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
608                     glyphs[j] =glyphs[j-(sub_count-1)];
609
610             for (j = 0; j < sub_count; j++)
611                     if (write_dir < 0)
612                         glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
613                     else
614                         glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
615
616             *glyph_count = *glyph_count + (sub_count - 1);
617
618             if (TRACE_ON(uniscribe))
619             {
620                 for (j = 0; j < sub_count; j++)
621                     TRACE(" 0x%x",glyphs[glyph_index+j]);
622                 TRACE("\n");
623             }
624
625             return glyph_index + (sub_count * write_dir);
626         }
627     }
628     return GSUB_E_NOGLYPH;
629 }
630
631 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
632 {
633     int j;
634     TRACE("Alternate Substitution Subtable\n");
635
636     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
637     {
638         int offset;
639         const GSUB_AlternateSubstFormat1 *asf1;
640         INT index;
641
642         offset = GET_BE_WORD(look->SubTable[j]);
643         asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
644         offset = GET_BE_WORD(asf1->Coverage);
645
646         index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
647         if (index != -1)
648         {
649             const GSUB_AlternateSet *as;
650             offset =  GET_BE_WORD(asf1->AlternateSet[index]);
651             as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
652             FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
653             if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
654                 return GSUB_E_NOGLYPH;
655
656             TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
657             glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
658             TRACE(" 0x%x\n",glyphs[glyph_index]);
659             return glyph_index + write_dir;
660         }
661     }
662     return GSUB_E_NOGLYPH;
663 }
664
665 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
666 {
667     int j;
668
669     TRACE("Ligature Substitution Subtable\n");
670     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
671     {
672         const GSUB_LigatureSubstFormat1 *lsf1;
673         int offset,index;
674
675         offset = GET_BE_WORD(look->SubTable[j]);
676         lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
677         offset = GET_BE_WORD(lsf1->Coverage);
678         index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
679         TRACE("  Coverage index %i\n",index);
680         if (index != -1)
681         {
682             const GSUB_LigatureSet *ls;
683             int k, count;
684
685             offset = GET_BE_WORD(lsf1->LigatureSet[index]);
686             ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
687             count = GET_BE_WORD(ls->LigatureCount);
688             TRACE("  LigatureSet has %i members\n",count);
689             for (k = 0; k < count; k++)
690             {
691                 const GSUB_Ligature *lig;
692                 int CompCount,l,CompIndex;
693
694                 offset = GET_BE_WORD(ls->Ligature[k]);
695                 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
696                 CompCount = GET_BE_WORD(lig->CompCount) - 1;
697                 CompIndex = glyph_index+write_dir;
698                 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
699                 {
700                     int CompGlyph;
701                     CompGlyph = GET_BE_WORD(lig->Component[l]);
702                     if (CompGlyph != glyphs[CompIndex])
703                         break;
704                     CompIndex += write_dir;
705                 }
706                 if (l == CompCount)
707                 {
708                     int replaceIdx = glyph_index;
709                     if (write_dir < 0)
710                         replaceIdx = glyph_index - CompCount;
711
712                     TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
713                     glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
714                     TRACE("0x%x\n",glyphs[replaceIdx]);
715                     if (CompCount > 0)
716                     {
717                         int j;
718                         for (j = replaceIdx + 1; j < *glyph_count; j++)
719                             glyphs[j] =glyphs[j+CompCount];
720                         *glyph_count = *glyph_count - CompCount;
721                     }
722                     return replaceIdx + write_dir;
723                 }
724             }
725         }
726     }
727     return GSUB_E_NOGLYPH;
728 }
729
730 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
731 {
732     int j;
733     BOOL done = FALSE;
734
735     TRACE("Chaining Contextual Substitution Subtable\n");
736     for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
737     {
738         const GSUB_ChainContextSubstFormat1 *ccsf1;
739         int offset;
740         int dirLookahead = write_dir;
741         int dirBacktrack = -1 * write_dir;
742
743         offset = GET_BE_WORD(look->SubTable[j]);
744         ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
745         if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
746         {
747             FIXME("  TODO: subtype 1 (Simple context glyph substitution)\n");
748             continue;
749         }
750         else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
751         {
752             FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
753             continue;
754         }
755         else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
756         {
757             int k;
758             int indexGlyphs;
759             const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
760             const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
761             const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
762             const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
763             int newIndex = glyph_index;
764
765             ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
766
767             TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
768
769             for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
770             {
771                 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
772                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
773                     break;
774             }
775             if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
776                 continue;
777             TRACE("Matched Backtrack\n");
778
779             ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
780
781             indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
782             for (k = 0; k < indexGlyphs; k++)
783             {
784                 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
785                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
786                     break;
787             }
788             if (k != indexGlyphs)
789                 continue;
790             TRACE("Matched IndexGlyphs\n");
791
792             ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
793
794             for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
795             {
796                 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
797                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
798                     break;
799             }
800             if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
801                 continue;
802             TRACE("Matched LookAhead\n");
803
804             ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
805
806             if (GET_BE_WORD(ccsf3_4->SubstCount))
807             {
808                 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
809                 {
810                     int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
811                     int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
812
813                     TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
814                     newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
815                     if (newIndex == -1)
816                     {
817                         ERR("Chain failed to generate a glyph\n");
818                         continue;
819                     }
820                 }
821                 return newIndex;
822             }
823             else return GSUB_E_NOGLYPH;
824         }
825     }
826     return -1;
827 }
828
829 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
830 {
831     int offset;
832     const GSUB_LookupTable *look;
833
834     offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
835     look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
836     TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
837     switch(GET_BE_WORD(look->LookupType))
838     {
839         case 1:
840             return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
841         case 2:
842             return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
843         case 3:
844             return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
845         case 4:
846             return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
847         case 6:
848             return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
849         default:
850             FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
851     }
852     return GSUB_E_NOGLYPH;
853 }
854
855 INT OpenType_apply_GSUB_lookup(LPCVOID table, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
856 {
857     const GSUB_Header *header = (const GSUB_Header *)table;
858     const GSUB_LookupList *lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
859
860     return GSUB_apply_lookup(lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count);
861 }
862
863 static void GSUB_initialize_script_cache(ScriptCache *psc)
864 {
865     int i;
866
867     if (!psc->script_count)
868     {
869         const GSUB_ScriptList *script;
870         const GSUB_Header* header = (const GSUB_Header*)psc->GSUB_Table;
871         script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
872         psc->script_count = GET_BE_WORD(script->ScriptCount);
873         TRACE("initializing %i scripts in this font\n",psc->script_count);
874         if (psc->script_count)
875         {
876             psc->scripts = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LoadedScript) * psc->script_count);
877             for (i = 0; i < psc->script_count; i++)
878             {
879                 int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
880                 psc->scripts[i].tag = MS_MAKE_TAG(script->ScriptRecord[i].ScriptTag[0], script->ScriptRecord[i].ScriptTag[1], script->ScriptRecord[i].ScriptTag[2], script->ScriptRecord[i].ScriptTag[3]);
881                 psc->scripts[i].table = ((const BYTE*)script + offset);
882             }
883         }
884     }
885 }
886
887 HRESULT OpenType_GSUB_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags, LPCVOID* script_table)
888 {
889     int i;
890     HRESULT rc = S_OK;
891
892     GSUB_initialize_script_cache(psc);
893     *pcTags = psc->script_count;
894
895     if (!searchingFor && cMaxTags < *pcTags)
896         rc = E_OUTOFMEMORY;
897     else if (searchingFor)
898         rc = USP_E_SCRIPT_NOT_IN_FONT;
899
900     for (i = 0; i < psc->script_count; i++)
901     {
902         if (i < cMaxTags)
903             pScriptTags[i] = psc->scripts[i].tag;
904
905         if (searchingFor)
906         {
907             if (searchingFor == psc->scripts[i].tag)
908             {
909                 pScriptTags[0] = psc->scripts[i].tag;
910                 *pcTags = 1;
911                 if (script_table)
912                     *script_table = psc->scripts[i].table;
913                 rc = S_OK;
914                 break;
915             }
916         }
917     }
918     return rc;
919 }
920
921 static void GSUB_initialize_language_cache(LoadedScript *script)
922 {
923     int i;
924
925     if (!script->language_count)
926     {
927         const GSUB_Script* table = script->table;
928         script->language_count = GET_BE_WORD(table->LangSysCount);
929         script->default_language.tag = MS_MAKE_TAG('d','f','l','t');
930         script->default_language.table = (const BYTE*)table + GET_BE_WORD(table->DefaultLangSys);
931
932         if (script->language_count)
933         {
934             TRACE("Deflang %p, LangCount %i\n",script->default_language.table, script->language_count);
935
936             script->languages = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LoadedLanguage) * script->language_count);
937
938             for (i = 0; i < script->language_count; i++)
939             {
940                 int offset = GET_BE_WORD(table->LangSysRecord[i].LangSys);
941                 script->languages[i].tag = MS_MAKE_TAG(table->LangSysRecord[i].LangSysTag[0], table->LangSysRecord[i].LangSysTag[1], table->LangSysRecord[i].LangSysTag[2], table->LangSysRecord[i].LangSysTag[3]);
942                 script->languages[i].table = ((const BYTE*)table + offset);
943             }
944         }
945     }
946 }
947
948 HRESULT OpenType_GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags, LPCVOID* language_table)
949 {
950     int i;
951     HRESULT rc = S_OK;
952     LoadedScript *script = NULL;
953
954     GSUB_initialize_script_cache(psc);
955
956     for (i = 0; i < psc->script_count; i++)
957     {
958          if (psc->scripts[i].tag == script_tag)
959          {
960             script = &psc->scripts[i];
961             break;
962          }
963     }
964
965     if (!script)
966         return E_INVALIDARG;
967
968     GSUB_initialize_language_cache(script);
969
970     if (!searchingFor && cMaxTags < script->language_count)
971         rc = E_OUTOFMEMORY;
972     else if (searchingFor)
973         rc = E_INVALIDARG;
974
975     *pcTags = script->language_count;
976
977     for (i = 0; i < script->language_count; i++)
978     {
979         if (i < cMaxTags)
980             pLanguageTags[i] = script->languages[i].tag;
981
982         if (searchingFor)
983         {
984             if (searchingFor == script->languages[i].tag)
985             {
986                 pLanguageTags[0] = script->languages[i].tag;
987                 *pcTags = 1;
988                 if (language_table)
989                     *language_table = script->languages[i].table;
990                 rc = S_OK;
991                 break;
992             }
993         }
994     }
995
996     if (script->default_language.table)
997     {
998         if (i < cMaxTags)
999             pLanguageTags[i] = script->default_language.tag;
1000
1001         if (searchingFor  && FAILED(rc))
1002         {
1003             pLanguageTags[0] = script->default_language.tag;
1004             if (language_table)
1005                 *language_table = script->default_language.table;
1006         }
1007         i++;
1008         *pcTags = (*pcTags) + 1;
1009     }
1010
1011     return rc;
1012 }
1013
1014
1015 static void GSUB_initialize_feature_cache(LPCVOID table, LoadedLanguage *language)
1016 {
1017     int i;
1018
1019     if (!language->feature_count)
1020     {
1021         const GSUB_LangSys *lang= language->table;
1022         const GSUB_Header *header = (const GSUB_Header *)table;
1023         const GSUB_FeatureList *feature_list;
1024
1025         language->feature_count = GET_BE_WORD(lang->FeatureCount);
1026         TRACE("%i features\n",language->feature_count);
1027
1028         if (language->feature_count)
1029         {
1030             language->features = HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature)*language->feature_count);
1031
1032             feature_list = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
1033
1034             for (i = 0; i < language->feature_count; i++)
1035             {
1036                 const GSUB_Feature *feature;
1037                 int j;
1038                 int index = GET_BE_WORD(lang->FeatureIndex[i]);
1039
1040                 language->features[i].tag = MS_MAKE_TAG(feature_list->FeatureRecord[index].FeatureTag[0], feature_list->FeatureRecord[index].FeatureTag[1], feature_list->FeatureRecord[index].FeatureTag[2], feature_list->FeatureRecord[index].FeatureTag[3]);
1041                 language->features[i].feature = ((const BYTE*)feature_list + GET_BE_WORD(feature_list->FeatureRecord[index].Feature));
1042                 feature = (const GSUB_Feature*)language->features[i].feature;
1043                 language->features[i].lookup_count = GET_BE_WORD(feature->LookupCount);
1044                 language->features[i].lookups = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * language->features[i].lookup_count);
1045                 for (j = 0; j < language->features[i].lookup_count; j++)
1046                     language->features[i].lookups[j] = GET_BE_WORD(feature->LookupListIndex[j]);
1047             }
1048         }
1049     }
1050 }
1051
1052 HRESULT OpenType_GSUB_GetFontFeatureTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG language_tag, BOOL filtered, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags, LoadedFeature** feature)
1053 {
1054     int i;
1055     HRESULT rc = S_OK;
1056     LoadedScript *script = NULL;
1057     LoadedLanguage *language = NULL;
1058
1059     GSUB_initialize_script_cache(psc);
1060
1061     for (i = 0; i < psc->script_count; i++)
1062     {
1063         if (psc->scripts[i].tag == script_tag)
1064         {
1065             script = &psc->scripts[i];
1066             break;
1067         }
1068     }
1069
1070     if (!script)
1071     {
1072         *pcTags = 0;
1073         if (!filtered)
1074             return S_OK;
1075         else
1076             return E_INVALIDARG;
1077     }
1078
1079     GSUB_initialize_language_cache(script);
1080
1081     if (script->default_language.table && script->default_language.tag == language_tag)
1082         language = &script->default_language;
1083     else
1084     {
1085         for (i = 0; i < script->language_count; i++)
1086         {
1087             if (script->languages[i].tag == language_tag)
1088             {
1089                 language = &script->languages[i];
1090                 break;
1091             }
1092         }
1093     }
1094
1095     if (!language)
1096     {
1097         *pcTags = 0;
1098         return S_OK;
1099     }
1100
1101     GSUB_initialize_feature_cache(psc->GSUB_Table, language);
1102
1103     *pcTags = language->feature_count;
1104
1105     if (!searchingFor && cMaxTags < *pcTags)
1106         rc = E_OUTOFMEMORY;
1107     else if (searchingFor)
1108         rc = E_INVALIDARG;
1109
1110     for (i = 0; i < language->feature_count; i++)
1111     {
1112         if (i < cMaxTags)
1113             pFeatureTags[i] = language->features[i].tag;
1114
1115         if (searchingFor)
1116         {
1117             if (searchingFor == language->features[i].tag)
1118             {
1119                 pFeatureTags[0] = language->features[i].tag;
1120                 *pcTags = 1;
1121                 if (feature)
1122                     *feature = &language->features[i];
1123                 rc = S_OK;
1124                 break;
1125             }
1126         }
1127     }
1128     return rc;
1129 }