advapi32: Close hTemp on error (Coverity).
[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 #define round(x) (((x) < 0) ? (int)((x) - 0.5) : (int)((x) + 0.5))
47
48 /* These are all structures needed for the cmap format 12 table */
49 #define CMAP_TAG MS_MAKE_TAG('c', 'm', 'a', 'p')
50
51 typedef struct {
52     WORD platformID;
53     WORD encodingID;
54     DWORD offset;
55 } CMAP_EncodingRecord;
56
57 typedef struct {
58     WORD version;
59     WORD numTables;
60     CMAP_EncodingRecord tables[1];
61 } CMAP_Header;
62
63 typedef struct {
64     DWORD startCharCode;
65     DWORD endCharCode;
66     DWORD startGlyphID;
67 } CMAP_SegmentedCoverage_group;
68
69 typedef struct {
70     WORD format;
71     WORD reserved;
72     DWORD length;
73     DWORD language;
74     DWORD nGroups;
75     CMAP_SegmentedCoverage_group groups[1];
76 } CMAP_SegmentedCoverage;
77
78 /* These are all structures needed for the GDEF table */
79 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
80
81 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
82
83 typedef struct {
84     DWORD Version;
85     WORD GlyphClassDef;
86     WORD AttachList;
87     WORD LigCaretList;
88     WORD MarkAttachClassDef;
89 } GDEF_Header;
90
91 typedef struct {
92     WORD ClassFormat;
93     WORD StartGlyph;
94     WORD GlyphCount;
95     WORD ClassValueArray[1];
96 } OT_ClassDefFormat1;
97
98 typedef struct {
99     WORD Start;
100     WORD End;
101     WORD Class;
102 } OT_ClassRangeRecord;
103
104 typedef struct {
105     WORD ClassFormat;
106     WORD ClassRangeCount;
107     OT_ClassRangeRecord ClassRangeRecord[1];
108 } OT_ClassDefFormat2;
109
110 /* These are all structures needed for the GSUB table */
111
112 typedef struct {
113     DWORD version;
114     WORD ScriptList;
115     WORD FeatureList;
116     WORD LookupList;
117 } GSUB_Header;
118
119 typedef struct {
120     CHAR ScriptTag[4];
121     WORD Script;
122 } OT_ScriptRecord;
123
124 typedef struct {
125     WORD ScriptCount;
126     OT_ScriptRecord ScriptRecord[1];
127 } OT_ScriptList;
128
129 typedef struct {
130     CHAR LangSysTag[4];
131     WORD LangSys;
132 } OT_LangSysRecord;
133
134 typedef struct {
135     WORD DefaultLangSys;
136     WORD LangSysCount;
137     OT_LangSysRecord LangSysRecord[1];
138 } OT_Script;
139
140 typedef struct {
141     WORD LookupOrder; /* Reserved */
142     WORD ReqFeatureIndex;
143     WORD FeatureCount;
144     WORD FeatureIndex[1];
145 } OT_LangSys;
146
147 typedef struct {
148     CHAR FeatureTag[4];
149     WORD Feature;
150 } OT_FeatureRecord;
151
152 typedef struct {
153     WORD FeatureCount;
154     OT_FeatureRecord FeatureRecord[1];
155 } OT_FeatureList;
156
157 typedef struct {
158     WORD FeatureParams; /* Reserved */
159     WORD LookupCount;
160     WORD LookupListIndex[1];
161 } OT_Feature;
162
163 typedef struct {
164     WORD LookupCount;
165     WORD Lookup[1];
166 } OT_LookupList;
167
168 typedef struct {
169     WORD LookupType;
170     WORD LookupFlag;
171     WORD SubTableCount;
172     WORD SubTable[1];
173 } OT_LookupTable;
174
175 typedef struct {
176     WORD CoverageFormat;
177     WORD GlyphCount;
178     WORD GlyphArray[1];
179 } OT_CoverageFormat1;
180
181 typedef struct {
182     WORD Start;
183     WORD End;
184     WORD StartCoverageIndex;
185 } OT_RangeRecord;
186
187 typedef struct {
188     WORD CoverageFormat;
189     WORD RangeCount;
190     OT_RangeRecord RangeRecord[1];
191 } OT_CoverageFormat2;
192
193 typedef struct {
194     WORD SubstFormat; /* = 1 */
195     WORD Coverage;
196     WORD DeltaGlyphID;
197 } GSUB_SingleSubstFormat1;
198
199 typedef struct {
200     WORD SubstFormat; /* = 2 */
201     WORD Coverage;
202     WORD GlyphCount;
203     WORD Substitute[1];
204 }GSUB_SingleSubstFormat2;
205
206 typedef struct {
207     WORD SubstFormat; /* = 1 */
208     WORD Coverage;
209     WORD SequenceCount;
210     WORD Sequence[1];
211 }GSUB_MultipleSubstFormat1;
212
213 typedef struct {
214     WORD GlyphCount;
215     WORD Substitute[1];
216 }GSUB_Sequence;
217
218 typedef struct {
219     WORD SubstFormat; /* = 1 */
220     WORD Coverage;
221     WORD LigSetCount;
222     WORD LigatureSet[1];
223 }GSUB_LigatureSubstFormat1;
224
225 typedef struct {
226     WORD LigatureCount;
227     WORD Ligature[1];
228 }GSUB_LigatureSet;
229
230 typedef struct{
231     WORD LigGlyph;
232     WORD CompCount;
233     WORD Component[1];
234 }GSUB_Ligature;
235
236 typedef struct{
237     WORD SequenceIndex;
238     WORD LookupListIndex;
239
240 }GSUB_SubstLookupRecord;
241
242 typedef struct{
243     WORD SubstFormat; /* = 1 */
244     WORD Coverage;
245     WORD ChainSubRuleSetCount;
246     WORD ChainSubRuleSet[1];
247 }GSUB_ChainContextSubstFormat1;
248
249 typedef struct {
250     WORD SubstFormat; /* = 3 */
251     WORD BacktrackGlyphCount;
252     WORD Coverage[1];
253 }GSUB_ChainContextSubstFormat3_1;
254
255 typedef struct{
256     WORD InputGlyphCount;
257     WORD Coverage[1];
258 }GSUB_ChainContextSubstFormat3_2;
259
260 typedef struct{
261     WORD LookaheadGlyphCount;
262     WORD Coverage[1];
263 }GSUB_ChainContextSubstFormat3_3;
264
265 typedef struct{
266     WORD SubstCount;
267     GSUB_SubstLookupRecord SubstLookupRecord[1];
268 }GSUB_ChainContextSubstFormat3_4;
269
270 typedef struct {
271     WORD SubstFormat; /* = 1 */
272     WORD Coverage;
273     WORD AlternateSetCount;
274     WORD AlternateSet[1];
275 } GSUB_AlternateSubstFormat1;
276
277 typedef struct{
278     WORD GlyphCount;
279     WORD Alternate[1];
280 } GSUB_AlternateSet;
281
282 /* These are all structures needed for the GPOS table */
283
284 typedef struct {
285     DWORD version;
286     WORD ScriptList;
287     WORD FeatureList;
288     WORD LookupList;
289 } GPOS_Header;
290
291 typedef struct {
292     WORD StartSize;
293     WORD EndSize;
294     WORD DeltaFormat;
295     WORD DeltaValue[1];
296 } OT_DeviceTable;
297
298 typedef struct {
299     WORD AnchorFormat;
300     WORD XCoordinate;
301     WORD YCoordinate;
302 } GPOS_AnchorFormat1;
303
304 typedef struct {
305     WORD AnchorFormat;
306     WORD XCoordinate;
307     WORD YCoordinate;
308     WORD AnchorPoint;
309 } GPOS_AnchorFormat2;
310
311 typedef struct {
312     WORD AnchorFormat;
313     WORD XCoordinate;
314     WORD YCoordinate;
315     WORD XDeviceTable;
316     WORD YDeviceTable;
317 } GPOS_AnchorFormat3;
318
319 typedef struct {
320     WORD XPlacement;
321     WORD YPlacement;
322     WORD XAdvance;
323     WORD YAdvance;
324     WORD XPlaDevice;
325     WORD YPlaDevice;
326     WORD XAdvDevice;
327     WORD YAdvDevice;
328 } GPOS_ValueRecord;
329
330 typedef struct {
331     WORD PosFormat;
332     WORD Coverage;
333     WORD ValueFormat;
334     WORD Value[1];
335 } GPOS_SinglePosFormat1;
336
337 typedef struct {
338     WORD PosFormat;
339     WORD Coverage;
340     WORD ValueFormat;
341     WORD ValueCount;
342     WORD Value[1];
343 } GPOS_SinglePosFormat2;
344
345 typedef struct {
346     WORD PosFormat;
347     WORD Coverage;
348     WORD ValueFormat1;
349     WORD ValueFormat2;
350     WORD PairSetCount;
351     WORD PairSetOffset[1];
352 } GPOS_PairPosFormat1;
353
354 typedef struct {
355     WORD PosFormat;
356     WORD Coverage;
357     WORD ValueFormat1;
358     WORD ValueFormat2;
359     WORD ClassDef1;
360     WORD ClassDef2;
361     WORD Class1Count;
362     WORD Class2Count;
363     WORD Class1Record[1];
364 } GPOS_PairPosFormat2;
365
366 typedef struct {
367     WORD SecondGlyph;
368     WORD Value1[1];
369     WORD Value2[1];
370 } GPOS_PairValueRecord;
371
372 typedef struct {
373     WORD PairValueCount;
374     GPOS_PairValueRecord PairValueRecord[1];
375 } GPOS_PairSet;
376
377 typedef struct {
378     WORD PosFormat;
379     WORD MarkCoverage;
380     WORD BaseCoverage;
381     WORD ClassCount;
382     WORD MarkArray;
383     WORD BaseArray;
384 } GPOS_MarkBasePosFormat1;
385
386 typedef struct {
387     WORD BaseAnchor[1];
388 } GPOS_BaseRecord;
389
390 typedef struct {
391     WORD BaseCount;
392     GPOS_BaseRecord BaseRecord[1];
393 } GPOS_BaseArray;
394
395 typedef struct {
396     WORD Class;
397     WORD MarkAnchor;
398 } GPOS_MarkRecord;
399
400 typedef struct {
401     WORD MarkCount;
402     GPOS_MarkRecord MarkRecord[1];
403 } GPOS_MarkArray;
404
405 typedef struct {
406     WORD PosFormat;
407     WORD Mark1Coverage;
408     WORD Mark2Coverage;
409     WORD ClassCount;
410     WORD Mark1Array;
411     WORD Mark2Array;
412 } GPOS_MarkMarkPosFormat1;
413
414 typedef struct {
415     WORD Mark2Anchor[1];
416 } GPOS_Mark2Record;
417
418 typedef struct {
419     WORD Mark2Count;
420     GPOS_Mark2Record Mark2Record[1];
421 } GPOS_Mark2Array;
422
423 typedef struct {
424     WORD SequenceIndex;
425     WORD LookupListIndex;
426 } GPOS_PosLookupRecord;
427
428 typedef struct {
429     WORD PosFormat;
430     WORD BacktrackGlyphCount;
431     WORD Coverage[1];
432 } GPOS_ChainContextPosFormat3_1;
433
434 typedef struct {
435     WORD InputGlyphCount;
436     WORD Coverage[1];
437 } GPOS_ChainContextPosFormat3_2;
438
439 typedef struct {
440     WORD LookaheadGlyphCount;
441     WORD Coverage[1];
442 } GPOS_ChainContextPosFormat3_3;
443
444 typedef struct {
445     WORD PosCount;
446     GPOS_PosLookupRecord PosLookupRecord[1];
447 } GPOS_ChainContextPosFormat3_4;
448
449 /**********
450  * CMAP
451  **********/
452
453 static VOID *load_CMAP_format12_table(HDC hdc, ScriptCache *psc)
454 {
455     CMAP_Header *CMAP_Table = NULL;
456     int length;
457     int i;
458
459     if (!psc->CMAP_Table)
460     {
461         length = GetFontData(hdc, CMAP_TAG , 0, NULL, 0);
462         if (length != GDI_ERROR)
463         {
464             psc->CMAP_Table = HeapAlloc(GetProcessHeap(),0,length);
465             GetFontData(hdc, CMAP_TAG , 0, psc->CMAP_Table, length);
466             TRACE("Loaded cmap table of %i bytes\n",length);
467         }
468         else
469             return NULL;
470     }
471
472     CMAP_Table = psc->CMAP_Table;
473
474     for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
475     {
476         if ( (GET_BE_WORD(CMAP_Table->tables[i].platformID) == 3) &&
477              (GET_BE_WORD(CMAP_Table->tables[i].encodingID) == 10) )
478         {
479             CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
480             if (GET_BE_WORD(format->format) == 12)
481                 return format;
482         }
483     }
484     return NULL;
485 }
486
487 static int compare_group(const void *a, const void* b)
488 {
489     const DWORD *chr = a;
490     const CMAP_SegmentedCoverage_group *group = b;
491
492     if (*chr < GET_BE_DWORD(group->startCharCode))
493         return -1;
494     if (*chr > GET_BE_DWORD(group->endCharCode))
495         return 1;
496     return 0;
497 }
498
499 DWORD OpenType_CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, LPWORD pgi, DWORD flags)
500 {
501     /* BMP: use gdi32 for ease */
502     if (utf32c < 0x10000)
503     {
504         WCHAR ch = utf32c;
505         return GetGlyphIndicesW(hdc,&ch, 1, pgi, flags);
506     }
507
508     if (!psc->CMAP_format12_Table)
509         psc->CMAP_format12_Table = load_CMAP_format12_table(hdc, psc);
510
511     if (flags & GGI_MARK_NONEXISTING_GLYPHS)
512         *pgi = 0xffff;
513     else
514         *pgi = 0;
515
516     if (psc->CMAP_format12_Table)
517     {
518         CMAP_SegmentedCoverage *format = NULL;
519         CMAP_SegmentedCoverage_group *group = NULL;
520
521         format = (CMAP_SegmentedCoverage *)psc->CMAP_format12_Table;
522
523         group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
524                         sizeof(CMAP_SegmentedCoverage_group), compare_group);
525
526         if (group)
527         {
528             DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
529             *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
530             return 0;
531         }
532     }
533     return 0;
534 }
535
536 /**********
537  * GDEF
538  **********/
539
540 static WORD OT_get_glyph_class(const void *table, WORD glyph)
541 {
542     WORD class = 0;
543     const OT_ClassDefFormat1 *cf1 = table;
544
545     if (!table) return 0;
546
547     if (GET_BE_WORD(cf1->ClassFormat) == 1)
548     {
549         if (glyph >= GET_BE_WORD(cf1->StartGlyph))
550         {
551             int index = glyph - GET_BE_WORD(cf1->StartGlyph);
552             if (index < GET_BE_WORD(cf1->GlyphCount))
553                 class = GET_BE_WORD(cf1->ClassValueArray[index]);
554         }
555     }
556     else if (GET_BE_WORD(cf1->ClassFormat) == 2)
557     {
558         const OT_ClassDefFormat2 *cf2 = table;
559         int i, top;
560         top = GET_BE_WORD(cf2->ClassRangeCount);
561         for (i = 0; i < top; i++)
562         {
563             if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
564                 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
565             {
566                 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
567                 break;
568             }
569         }
570     }
571     else
572         ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
573
574     return class;
575 }
576
577 static VOID *load_gdef_table(HDC hdc)
578 {
579     VOID* GDEF_Table = NULL;
580     int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
581     if (length != GDI_ERROR)
582     {
583         GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
584         GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
585         TRACE("Loaded GDEF table of %i bytes\n",length);
586     }
587     return GDEF_Table;
588 }
589
590 void OpenType_GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
591 {
592     int i;
593     void *glyph_class_table = NULL;
594
595     if (!psc->GDEF_Table)
596         psc->GDEF_Table = load_gdef_table(hdc);
597
598     if (psc->GDEF_Table)
599     {
600         const GDEF_Header *header = psc->GDEF_Table;
601         WORD offset = GET_BE_WORD( header->GlyphClassDef );
602         if (offset)
603             glyph_class_table = (BYTE *)psc->GDEF_Table + offset;
604     }
605
606     for (i = 0; i < cGlyphs; i++)
607     {
608         WORD class;
609         int char_count = 0;
610         int k;
611
612         k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
613         if (k >= 0)
614         {
615             for (; k < cChars && pwLogClust[k] == i; k++)
616                 char_count++;
617         }
618
619         class = OT_get_glyph_class( glyph_class_table, pwGlyphs[i] );
620
621         switch (class)
622         {
623             case 0:
624             case BaseGlyph:
625                 pGlyphProp[i].sva.fClusterStart = 1;
626                 pGlyphProp[i].sva.fDiacritic = 0;
627                 pGlyphProp[i].sva.fZeroWidth = 0;
628                 break;
629             case LigatureGlyph:
630                 pGlyphProp[i].sva.fClusterStart = 1;
631                 pGlyphProp[i].sva.fDiacritic = 0;
632                 pGlyphProp[i].sva.fZeroWidth = 0;
633                 break;
634             case MarkGlyph:
635                 pGlyphProp[i].sva.fClusterStart = 0;
636                 pGlyphProp[i].sva.fDiacritic = 1;
637                 pGlyphProp[i].sva.fZeroWidth = 1;
638                 break;
639             case ComponentGlyph:
640                 pGlyphProp[i].sva.fClusterStart = 0;
641                 pGlyphProp[i].sva.fDiacritic = 0;
642                 pGlyphProp[i].sva.fZeroWidth = 0;
643                 break;
644             default:
645                 ERR("Unknown glyph class %i\n",class);
646                 pGlyphProp[i].sva.fClusterStart = 1;
647                 pGlyphProp[i].sva.fDiacritic = 0;
648                 pGlyphProp[i].sva.fZeroWidth = 0;
649         }
650
651         if (char_count == 0)
652             pGlyphProp[i].sva.fClusterStart = 0;
653     }
654 }
655
656 /**********
657  * GSUB
658  **********/
659 static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
660
661 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
662 {
663     const OT_CoverageFormat1* cf1;
664
665     cf1 = table;
666
667     if (GET_BE_WORD(cf1->CoverageFormat) == 1)
668     {
669         int count = GET_BE_WORD(cf1->GlyphCount);
670         int i;
671         TRACE("Coverage Format 1, %i glyphs\n",count);
672         for (i = 0; i < count; i++)
673             if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
674                 return i;
675         return -1;
676     }
677     else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
678     {
679         const OT_CoverageFormat2* cf2;
680         int i;
681         int count;
682         cf2 = (const OT_CoverageFormat2*)cf1;
683
684         count = GET_BE_WORD(cf2->RangeCount);
685         TRACE("Coverage Format 2, %i ranges\n",count);
686         for (i = 0; i < count; i++)
687         {
688             if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
689                 return -1;
690             if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
691                 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
692             {
693                 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
694                     glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
695             }
696         }
697         return -1;
698     }
699     else
700         ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
701
702     return -1;
703 }
704
705 static INT GSUB_apply_SingleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
706 {
707     int j;
708     TRACE("Single Substitution Subtable\n");
709
710     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
711     {
712         int offset;
713         const GSUB_SingleSubstFormat1 *ssf1;
714         offset = GET_BE_WORD(look->SubTable[j]);
715         ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
716         if (GET_BE_WORD(ssf1->SubstFormat) == 1)
717         {
718             int offset = GET_BE_WORD(ssf1->Coverage);
719             TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
720             if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
721             {
722                 TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
723                 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
724                 TRACE(" 0x%x\n",glyphs[glyph_index]);
725                 return glyph_index + write_dir;
726             }
727         }
728         else
729         {
730             const GSUB_SingleSubstFormat2 *ssf2;
731             INT index;
732             INT offset;
733
734             ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
735             offset = GET_BE_WORD(ssf1->Coverage);
736             TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
737             index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
738             TRACE("  Coverage index %i\n",index);
739             if (index != -1)
740             {
741                 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
742                     return GSUB_E_NOGLYPH;
743
744                 TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
745                 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
746                 TRACE("0x%x\n",glyphs[glyph_index]);
747                 return glyph_index + write_dir;
748             }
749         }
750     }
751     return GSUB_E_NOGLYPH;
752 }
753
754 static INT GSUB_apply_MultipleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
755 {
756     int j;
757     TRACE("Multiple Substitution Subtable\n");
758
759     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
760     {
761         int offset, index;
762         const GSUB_MultipleSubstFormat1 *msf1;
763         offset = GET_BE_WORD(look->SubTable[j]);
764         msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
765
766         offset = GET_BE_WORD(msf1->Coverage);
767         index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
768         if (index != -1)
769         {
770             const GSUB_Sequence *seq;
771             int sub_count;
772             int j;
773             offset = GET_BE_WORD(msf1->Sequence[index]);
774             seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
775             sub_count = GET_BE_WORD(seq->GlyphCount);
776             TRACE("  Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
777
778             for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
779                     glyphs[j] =glyphs[j-(sub_count-1)];
780
781             for (j = 0; j < sub_count; j++)
782                     if (write_dir < 0)
783                         glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
784                     else
785                         glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
786
787             *glyph_count = *glyph_count + (sub_count - 1);
788
789             if (TRACE_ON(uniscribe))
790             {
791                 for (j = 0; j < sub_count; j++)
792                     TRACE(" 0x%x",glyphs[glyph_index+j]);
793                 TRACE("\n");
794             }
795
796             return glyph_index + (sub_count * write_dir);
797         }
798     }
799     return GSUB_E_NOGLYPH;
800 }
801
802 static INT GSUB_apply_AlternateSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
803 {
804     int j;
805     TRACE("Alternate Substitution Subtable\n");
806
807     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
808     {
809         int offset;
810         const GSUB_AlternateSubstFormat1 *asf1;
811         INT index;
812
813         offset = GET_BE_WORD(look->SubTable[j]);
814         asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
815         offset = GET_BE_WORD(asf1->Coverage);
816
817         index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
818         if (index != -1)
819         {
820             const GSUB_AlternateSet *as;
821             offset =  GET_BE_WORD(asf1->AlternateSet[index]);
822             as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
823             FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
824             if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
825                 return GSUB_E_NOGLYPH;
826
827             TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
828             glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
829             TRACE(" 0x%x\n",glyphs[glyph_index]);
830             return glyph_index + write_dir;
831         }
832     }
833     return GSUB_E_NOGLYPH;
834 }
835
836 static INT GSUB_apply_LigatureSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
837 {
838     int j;
839
840     TRACE("Ligature Substitution Subtable\n");
841     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
842     {
843         const GSUB_LigatureSubstFormat1 *lsf1;
844         int offset,index;
845
846         offset = GET_BE_WORD(look->SubTable[j]);
847         lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
848         offset = GET_BE_WORD(lsf1->Coverage);
849         index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
850         TRACE("  Coverage index %i\n",index);
851         if (index != -1)
852         {
853             const GSUB_LigatureSet *ls;
854             int k, count;
855
856             offset = GET_BE_WORD(lsf1->LigatureSet[index]);
857             ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
858             count = GET_BE_WORD(ls->LigatureCount);
859             TRACE("  LigatureSet has %i members\n",count);
860             for (k = 0; k < count; k++)
861             {
862                 const GSUB_Ligature *lig;
863                 int CompCount,l,CompIndex;
864
865                 offset = GET_BE_WORD(ls->Ligature[k]);
866                 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
867                 CompCount = GET_BE_WORD(lig->CompCount) - 1;
868                 CompIndex = glyph_index+write_dir;
869                 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
870                 {
871                     int CompGlyph;
872                     CompGlyph = GET_BE_WORD(lig->Component[l]);
873                     if (CompGlyph != glyphs[CompIndex])
874                         break;
875                     CompIndex += write_dir;
876                 }
877                 if (l == CompCount)
878                 {
879                     int replaceIdx = glyph_index;
880                     if (write_dir < 0)
881                         replaceIdx = glyph_index - CompCount;
882
883                     TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
884                     glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
885                     TRACE("0x%x\n",glyphs[replaceIdx]);
886                     if (CompCount > 0)
887                     {
888                         int j;
889                         for (j = replaceIdx + 1; j < *glyph_count; j++)
890                             glyphs[j] =glyphs[j+CompCount];
891                         *glyph_count = *glyph_count - CompCount;
892                     }
893                     return replaceIdx + write_dir;
894                 }
895             }
896         }
897     }
898     return GSUB_E_NOGLYPH;
899 }
900
901 static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
902 {
903     int j;
904     BOOL done = FALSE;
905
906     TRACE("Chaining Contextual Substitution Subtable\n");
907     for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
908     {
909         const GSUB_ChainContextSubstFormat1 *ccsf1;
910         int offset;
911         int dirLookahead = write_dir;
912         int dirBacktrack = -1 * write_dir;
913
914         offset = GET_BE_WORD(look->SubTable[j]);
915         ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
916         if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
917         {
918             FIXME("  TODO: subtype 1 (Simple context glyph substitution)\n");
919             continue;
920         }
921         else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
922         {
923             FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
924             continue;
925         }
926         else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
927         {
928             int k;
929             int indexGlyphs;
930             const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
931             const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
932             const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
933             const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
934             int newIndex = glyph_index;
935
936             ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
937
938             TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
939
940             for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
941             {
942                 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
943                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
944                     break;
945             }
946             if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
947                 continue;
948             TRACE("Matched Backtrack\n");
949
950             ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)((BYTE *)ccsf1 +
951                     FIELD_OFFSET(GSUB_ChainContextSubstFormat3_1, Coverage[GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)]));
952
953             indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
954             for (k = 0; k < indexGlyphs; k++)
955             {
956                 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
957                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
958                     break;
959             }
960             if (k != indexGlyphs)
961                 continue;
962             TRACE("Matched IndexGlyphs\n");
963
964             ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)((BYTE *)ccsf3_2 +
965                     FIELD_OFFSET(GSUB_ChainContextSubstFormat3_2, Coverage[GET_BE_WORD(ccsf3_2->InputGlyphCount)]));
966
967             for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
968             {
969                 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
970                 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
971                     break;
972             }
973             if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
974                 continue;
975             TRACE("Matched LookAhead\n");
976
977             ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)((BYTE *)ccsf3_3 +
978                     FIELD_OFFSET(GSUB_ChainContextSubstFormat3_3, Coverage[GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)]));
979
980             if (GET_BE_WORD(ccsf3_4->SubstCount))
981             {
982                 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
983                 {
984                     int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
985                     int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
986
987                     TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
988                     newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
989                     if (newIndex == -1)
990                     {
991                         ERR("Chain failed to generate a glyph\n");
992                         continue;
993                     }
994                 }
995                 return newIndex;
996             }
997             else return GSUB_E_NOGLYPH;
998         }
999     }
1000     return -1;
1001 }
1002
1003 static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1004 {
1005     int offset;
1006     const OT_LookupTable *look;
1007
1008     offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1009     look = (const OT_LookupTable*)((const BYTE*)lookup + offset);
1010     TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1011     switch(GET_BE_WORD(look->LookupType))
1012     {
1013         case 1:
1014             return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1015         case 2:
1016             return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1017         case 3:
1018             return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1019         case 4:
1020             return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1021         case 6:
1022             return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1023         default:
1024             FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1025     }
1026     return GSUB_E_NOGLYPH;
1027 }
1028
1029 INT OpenType_apply_GSUB_lookup(LPCVOID table, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1030 {
1031     const GSUB_Header *header = (const GSUB_Header *)table;
1032     const OT_LookupList *lookup = (const OT_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1033
1034     return GSUB_apply_lookup(lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count);
1035 }
1036
1037 /**********
1038  * GPOS
1039  **********/
1040 static INT GPOS_apply_lookup(LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, INT* piAdvance, const OT_LookupList* lookup, INT lookup_index, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, GOFFSET *pGoffset);
1041
1042 static INT GPOS_get_device_table_value(const OT_DeviceTable *DeviceTable, WORD ppem)
1043 {
1044     static const WORD mask[3] = {3,0xf,0xff};
1045     if (DeviceTable && ppem >= GET_BE_WORD(DeviceTable->StartSize) && ppem  <= GET_BE_WORD(DeviceTable->EndSize))
1046     {
1047         int format = GET_BE_WORD(DeviceTable->DeltaFormat);
1048         int index = ppem - GET_BE_WORD(DeviceTable->StartSize);
1049         int value;
1050         TRACE("device table, format %i, index %i\n",format, index);
1051         index = index << format;
1052         value = (DeviceTable->DeltaValue[index/sizeof(WORD)] << (index%sizeof(WORD)))&mask[format-1];
1053         TRACE("offset %i, value %i\n",index, value);
1054         if (value > mask[format-1]/2)
1055             value = -1 * ((mask[format-1]+1) - value);
1056         return value;
1057     }
1058     return 0;
1059 }
1060
1061 static VOID GPOS_get_anchor_values(LPCVOID table, LPPOINT pt, WORD ppem)
1062 {
1063     const GPOS_AnchorFormat1* anchor1 = (const GPOS_AnchorFormat1*)table;
1064
1065     switch (GET_BE_WORD(anchor1->AnchorFormat))
1066     {
1067         case 1:
1068         {
1069             TRACE("Anchor Format 1\n");
1070             pt->x = (short)GET_BE_WORD(anchor1->XCoordinate);
1071             pt->y = (short)GET_BE_WORD(anchor1->YCoordinate);
1072             break;
1073         }
1074         case 2:
1075         {
1076             const GPOS_AnchorFormat2* anchor2 = (const GPOS_AnchorFormat2*)table;
1077             TRACE("Anchor Format 2\n");
1078             pt->x = (short)GET_BE_WORD(anchor2->XCoordinate);
1079             pt->y = (short)GET_BE_WORD(anchor2->YCoordinate);
1080             break;
1081         }
1082         case 3:
1083         {
1084             int offset;
1085             const GPOS_AnchorFormat3* anchor3 = (const GPOS_AnchorFormat3*)table;
1086             TRACE("Anchor Format 3\n");
1087             pt->x = (short)GET_BE_WORD(anchor3->XCoordinate);
1088             pt->y = (short)GET_BE_WORD(anchor3->YCoordinate);
1089             offset = GET_BE_WORD(anchor3->XDeviceTable);
1090             TRACE("ppem %i\n",ppem);
1091             if (offset)
1092             {
1093                 const OT_DeviceTable* DeviceTableX = NULL;
1094                 DeviceTableX = (const OT_DeviceTable*)((const BYTE*)anchor3 + offset);
1095                 pt->x += GPOS_get_device_table_value(DeviceTableX, ppem);
1096             }
1097             offset = GET_BE_WORD(anchor3->YDeviceTable);
1098             if (offset)
1099             {
1100                 const OT_DeviceTable* DeviceTableY = NULL;
1101                 DeviceTableY = (const OT_DeviceTable*)((const BYTE*)anchor3 + offset);
1102                 pt->y += GPOS_get_device_table_value(DeviceTableY, ppem);
1103             }
1104             break;
1105         }
1106         default:
1107             ERR("Unknown Anchor Format %i\n",GET_BE_WORD(anchor1->AnchorFormat));
1108             pt->x = 0;
1109             pt->y = 0;
1110     }
1111 }
1112
1113 static void GPOS_convert_design_units_to_device(LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, int desX, int desY, double *devX, double *devY)
1114 {
1115     int emHeight = lpotm->otmTextMetrics.tmAscent + lpotm->otmTextMetrics.tmDescent - lpotm->otmTextMetrics.tmInternalLeading;
1116
1117     TRACE("emHeight %i lfWidth %i\n",emHeight, lplogfont->lfWidth);
1118     *devX = (desX * emHeight) / (double)lpotm->otmEMSquare;
1119     *devY = (desY * emHeight) / (double)lpotm->otmEMSquare;
1120     if (lplogfont->lfWidth)
1121         FIXME("Font with lfWidth set no handled properly\n");
1122 }
1123
1124 static INT GPOS_get_value_record(WORD ValueFormat, const WORD data[], GPOS_ValueRecord *record)
1125 {
1126     INT offset = 0;
1127     if (ValueFormat & 0x0001) { if (data) record->XPlacement = GET_BE_WORD(data[offset]); offset++; }
1128     if (ValueFormat & 0x0002) { if (data) record->YPlacement = GET_BE_WORD(data[offset]); offset++; }
1129     if (ValueFormat & 0x0004) { if (data) record->XAdvance   = GET_BE_WORD(data[offset]); offset++; }
1130     if (ValueFormat & 0x0008) { if (data) record->YAdvance   = GET_BE_WORD(data[offset]); offset++; }
1131     if (ValueFormat & 0x0010) { if (data) record->XPlaDevice = GET_BE_WORD(data[offset]); offset++; }
1132     if (ValueFormat & 0x0020) { if (data) record->YPlaDevice = GET_BE_WORD(data[offset]); offset++; }
1133     if (ValueFormat & 0x0040) { if (data) record->XAdvDevice = GET_BE_WORD(data[offset]); offset++; }
1134     if (ValueFormat & 0x0080) { if (data) record->YAdvDevice = GET_BE_WORD(data[offset]); offset++; }
1135     return offset;
1136 }
1137
1138 static VOID GPOS_get_value_record_offsets(const BYTE* head, GPOS_ValueRecord *ValueRecord,  WORD ValueFormat, INT ppem, LPPOINT ptPlacement, LPPOINT ptAdvance)
1139 {
1140     if (ValueFormat & 0x0001) ptPlacement->x += (short)ValueRecord->XPlacement;
1141     if (ValueFormat & 0x0002) ptPlacement->y += (short)ValueRecord->YPlacement;
1142     if (ValueFormat & 0x0004) ptAdvance->x += (short)ValueRecord->XAdvance;
1143     if (ValueFormat & 0x0008) ptAdvance->y += (short)ValueRecord->YAdvance;
1144     if (ValueFormat & 0x0010) ptPlacement->x += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->XPlaDevice), ppem);
1145     if (ValueFormat & 0x0020) ptPlacement->y += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->YPlaDevice), ppem);
1146     if (ValueFormat & 0x0040) ptAdvance->x += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->XAdvDevice), ppem);
1147     if (ValueFormat & 0x0080) ptAdvance->y += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->YAdvDevice), ppem);
1148     if (ValueFormat & 0xFF00) FIXME("Unhandled Value Format %x\n",ValueFormat&0xFF00);
1149 }
1150
1151 static VOID GPOS_apply_SingleAdjustment(const OT_LookupTable *look, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, INT ppem, LPPOINT ptAdjust, LPPOINT ptAdvance)
1152 {
1153     int j;
1154
1155     TRACE("Single Adjustment Positioning Subtable\n");
1156
1157     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1158     {
1159         const GPOS_SinglePosFormat1 *spf1;
1160         WORD offset = GET_BE_WORD(look->SubTable[j]);
1161         spf1 = (const GPOS_SinglePosFormat1*)((const BYTE*)look+offset);
1162         if (GET_BE_WORD(spf1->PosFormat) == 1)
1163         {
1164             offset = GET_BE_WORD(spf1->Coverage);
1165             if (GSUB_is_glyph_covered((const BYTE*)spf1+offset, glyphs[glyph_index]) != -1)
1166             {
1167                 GPOS_ValueRecord ValueRecord = {0,0,0,0,0,0,0,0};
1168                 WORD ValueFormat = GET_BE_WORD(spf1->ValueFormat);
1169                 GPOS_get_value_record(ValueFormat, spf1->Value, &ValueRecord);
1170                 GPOS_get_value_record_offsets((const BYTE*)spf1, &ValueRecord,  ValueFormat, ppem, ptAdjust, ptAdvance);
1171                 TRACE("Glyph Adjusted by %i,%i\n",ValueRecord.XPlacement,ValueRecord.YPlacement);
1172             }
1173         }
1174         else if (GET_BE_WORD(spf1->PosFormat) == 2)
1175         {
1176             int index;
1177             const GPOS_SinglePosFormat2 *spf2;
1178             spf2 = (const GPOS_SinglePosFormat2*)spf1;
1179             offset = GET_BE_WORD(spf2->Coverage);
1180             index  = GSUB_is_glyph_covered((const BYTE*)spf2+offset, glyphs[glyph_index]);
1181             if (index != -1)
1182             {
1183                 int size;
1184                 GPOS_ValueRecord ValueRecord = {0,0,0,0,0,0,0,0};
1185                 WORD ValueFormat = GET_BE_WORD(spf2->ValueFormat);
1186                 size = GPOS_get_value_record(ValueFormat, spf2->Value, &ValueRecord);
1187                 if (index > 0)
1188                 {
1189                     offset = size * index;
1190                     GPOS_get_value_record(ValueFormat, &spf2->Value[offset], &ValueRecord);
1191                 }
1192                 GPOS_get_value_record_offsets((const BYTE*)spf2, &ValueRecord,  ValueFormat, ppem, ptAdjust, ptAdvance);
1193                 TRACE("Glyph Adjusted by %i,%i\n",ValueRecord.XPlacement,ValueRecord.YPlacement);
1194             }
1195         }
1196         else
1197             FIXME("Single Adjustment Positioning: Format %i Unhandled\n",GET_BE_WORD(spf1->PosFormat));
1198     }
1199 }
1200
1201 static void apply_pair_value( const void *pos_table, WORD val_fmt1, WORD val_fmt2, const WORD *pair,
1202                               INT ppem, POINT *adjust, POINT *advance )
1203 {
1204     GPOS_ValueRecord val_rec1 = {0,0,0,0,0,0,0,0};
1205     GPOS_ValueRecord val_rec2 = {0,0,0,0,0,0,0,0};
1206     INT size;
1207
1208     size = GPOS_get_value_record( val_fmt1, pair, &val_rec1 );
1209     GPOS_get_value_record( val_fmt2, pair + size, &val_rec2 );
1210
1211     if (val_fmt1)
1212     {
1213         GPOS_get_value_record_offsets( pos_table, &val_rec1, val_fmt1, ppem, adjust, advance );
1214         TRACE( "Glyph 1 resulting cumulative offset is %i,%i design units\n", adjust[0].x, adjust[0].y );
1215         TRACE( "Glyph 1 resulting cumulative advance is %i,%i design units\n", advance[0].x, advance[0].y );
1216     }
1217     if (val_fmt2)
1218     {
1219         GPOS_get_value_record_offsets( pos_table, &val_rec2, val_fmt2, ppem, adjust + 1, advance + 1 );
1220         TRACE( "Glyph 2 resulting cumulative offset is %i,%i design units\n", adjust[1].x, adjust[1].y );
1221         TRACE( "Glyph 2 resulting cumulative advance is %i,%i design units\n", advance[1].x, advance[1].y );
1222     }
1223 }
1224
1225 static INT GPOS_apply_PairAdjustment(const OT_LookupTable *look, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, INT ppem, LPPOINT ptAdjust, LPPOINT ptAdvance)
1226 {
1227     int j;
1228
1229     TRACE("Pair Adjustment Positioning Subtable\n");
1230
1231     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1232     {
1233         const GPOS_PairPosFormat1 *ppf1;
1234         WORD offset = GET_BE_WORD(look->SubTable[j]);
1235         ppf1 = (const GPOS_PairPosFormat1*)((const BYTE*)look+offset);
1236         if (GET_BE_WORD(ppf1->PosFormat) == 1)
1237         {
1238             int index;
1239             WORD ValueFormat1 = GET_BE_WORD(ppf1->ValueFormat1);
1240             WORD ValueFormat2 = GET_BE_WORD(ppf1->ValueFormat2);
1241             INT val_fmt1_size = GPOS_get_value_record( ValueFormat1, NULL, NULL );
1242             INT val_fmt2_size = GPOS_get_value_record( ValueFormat2, NULL, NULL );
1243             offset = GET_BE_WORD(ppf1->Coverage);
1244             index = GSUB_is_glyph_covered((const BYTE*)ppf1+offset, glyphs[glyph_index]);
1245             if (index != -1 && index < GET_BE_WORD(ppf1->PairSetCount))
1246             {
1247                 int k;
1248                 int pair_count;
1249                 const GPOS_PairSet *ps;
1250                 const GPOS_PairValueRecord *pair_val_rec;
1251                 offset = GET_BE_WORD(ppf1->PairSetOffset[index]);
1252                 ps = (const GPOS_PairSet*)((const BYTE*)ppf1+offset);
1253                 pair_count = GET_BE_WORD(ps->PairValueCount);
1254                 pair_val_rec = ps->PairValueRecord;
1255                 for (k = 0; k < pair_count; k++)
1256                 {
1257                     WORD second_glyph = GET_BE_WORD(pair_val_rec->SecondGlyph);
1258                     if (glyphs[glyph_index+write_dir] == second_glyph)
1259                     {
1260                         int next = 1;
1261                         TRACE("Format 1: Found Pair %x,%x\n",glyphs[glyph_index],glyphs[glyph_index+write_dir]);
1262                         apply_pair_value( ppf1, ValueFormat1, ValueFormat2, pair_val_rec->Value1, ppem, ptAdjust, ptAdvance );
1263                         if (ValueFormat2) next++;
1264                         return glyph_index + next;
1265                     }
1266                     pair_val_rec = (const GPOS_PairValueRecord *)(pair_val_rec->Value1 + val_fmt1_size + val_fmt2_size);
1267                 }
1268             }
1269         }
1270         else if (GET_BE_WORD(ppf1->PosFormat) == 2)
1271         {
1272             const GPOS_PairPosFormat2 *ppf2 = (const GPOS_PairPosFormat2*)((const BYTE*)look + offset);
1273             int index;
1274             WORD ValueFormat1 = GET_BE_WORD( ppf2->ValueFormat1 );
1275             WORD ValueFormat2 = GET_BE_WORD( ppf2->ValueFormat2 );
1276             INT val_fmt1_size = GPOS_get_value_record( ValueFormat1, NULL, NULL );
1277             INT val_fmt2_size = GPOS_get_value_record( ValueFormat2, NULL, NULL );
1278             WORD class1_count = GET_BE_WORD( ppf2->Class1Count );
1279             WORD class2_count = GET_BE_WORD( ppf2->Class2Count );
1280
1281             offset = GET_BE_WORD( ppf2->Coverage );
1282             index = GSUB_is_glyph_covered( (const BYTE*)ppf2 + offset, glyphs[glyph_index] );
1283             if (index != -1)
1284             {
1285                 WORD class1, class2;
1286                 class1 = OT_get_glyph_class( (const BYTE *)ppf2 + GET_BE_WORD(ppf2->ClassDef1), glyphs[glyph_index] );
1287                 class2 = OT_get_glyph_class( (const BYTE *)ppf2 + GET_BE_WORD(ppf2->ClassDef2), glyphs[glyph_index + write_dir] );
1288                 if (class1 < class1_count && class2 < class2_count)
1289                 {
1290                     const WORD *pair_val = ppf2->Class1Record + (class1 * class2_count + class2) * (val_fmt1_size + val_fmt2_size);
1291                     int next = 1;
1292
1293                     TRACE( "Format 2: Found Pair %x,%x\n", glyphs[glyph_index], glyphs[glyph_index + write_dir] );
1294
1295                     apply_pair_value( ppf2, ValueFormat1, ValueFormat2, pair_val, ppem, ptAdjust, ptAdvance );
1296                     if (ValueFormat2) next++;
1297                     return glyph_index + next;
1298                 }
1299             }
1300         }
1301         else
1302             FIXME("Pair Adjustment Positioning: Format %i Unhandled\n",GET_BE_WORD(ppf1->PosFormat));
1303     }
1304     return glyph_index+1;
1305 }
1306
1307 static VOID GPOS_apply_MarkToBase(const OT_LookupTable *look, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, INT ppem, LPPOINT pt)
1308 {
1309     int j;
1310
1311     TRACE("MarkToBase Attachment Positioning Subtable\n");
1312
1313     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1314     {
1315         int offset;
1316         const GPOS_MarkBasePosFormat1 *mbpf1;
1317         offset = GET_BE_WORD(look->SubTable[j]);
1318         mbpf1 = (const GPOS_MarkBasePosFormat1*)((const BYTE*)look+offset);
1319         if (GET_BE_WORD(mbpf1->PosFormat) == 1)
1320         {
1321             int offset = GET_BE_WORD(mbpf1->MarkCoverage);
1322             int mark_index;
1323             mark_index = GSUB_is_glyph_covered((const BYTE*)mbpf1+offset, glyphs[glyph_index]);
1324             if (mark_index != -1)
1325             {
1326                 int base_index;
1327                 offset = GET_BE_WORD(mbpf1->BaseCoverage);
1328                 base_index = GSUB_is_glyph_covered((const BYTE*)mbpf1+offset, glyphs[glyph_index - write_dir]);
1329                 if (base_index != -1)
1330                 {
1331                     const GPOS_MarkArray *ma;
1332                     const GPOS_MarkRecord *mr;
1333                     const GPOS_BaseArray *ba;
1334                     const GPOS_BaseRecord *br;
1335                     int mark_class;
1336                     int class_count = GET_BE_WORD(mbpf1->ClassCount);
1337                     int baserecord_size;
1338                     POINT base_pt;
1339                     POINT mark_pt;
1340                     TRACE("Mark %x(%i) and base %x(%i)\n",glyphs[glyph_index], mark_index, glyphs[glyph_index - write_dir], base_index);
1341                     offset = GET_BE_WORD(mbpf1->MarkArray);
1342                     ma = (const GPOS_MarkArray*)((const BYTE*)mbpf1 + offset);
1343                     if (mark_index > GET_BE_WORD(ma->MarkCount))
1344                     {
1345                         ERR("Mark index exeeded mark count\n");
1346                         return;
1347                     }
1348                     mr = &ma->MarkRecord[mark_index];
1349                     mark_class = GET_BE_WORD(mr->Class);
1350                     TRACE("Mark Class %i total classes %i\n",mark_class,class_count);
1351                     offset = GET_BE_WORD(mbpf1->BaseArray);
1352                     ba = (const GPOS_BaseArray*)((const BYTE*)mbpf1 + offset);
1353                     baserecord_size = class_count * sizeof(WORD);
1354                     br = (const GPOS_BaseRecord*)((const BYTE*)ba + sizeof(WORD) + (baserecord_size * base_index));
1355                     offset = GET_BE_WORD(br->BaseAnchor[mark_class]);
1356                     GPOS_get_anchor_values((const BYTE*)ba + offset, &base_pt, ppem);
1357                     offset = GET_BE_WORD(mr->MarkAnchor);
1358                     GPOS_get_anchor_values((const BYTE*)ma + offset, &mark_pt, ppem);
1359                     TRACE("Offset on base is %i,%i design units\n",base_pt.x,base_pt.y);
1360                     TRACE("Offset on mark is %i,%i design units\n",mark_pt.x, mark_pt.y);
1361                     pt->x += base_pt.x - mark_pt.x;
1362                     pt->y += base_pt.y - mark_pt.y;
1363                     TRACE("Resulting cumulative offset is %i,%i design units\n",pt->x,pt->y);
1364                 }
1365             }
1366         }
1367         else
1368             FIXME("Unhandled Mark To Base Format %i\n",GET_BE_WORD(mbpf1->PosFormat));
1369     }
1370 }
1371
1372 static VOID GPOS_apply_MarkToMark(const OT_LookupTable *look, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, INT ppem, LPPOINT pt)
1373 {
1374     int j;
1375
1376     TRACE("MarkToMark Attachment Positioning Subtable\n");
1377
1378     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1379     {
1380         int offset;
1381         const GPOS_MarkMarkPosFormat1 *mmpf1;
1382         offset = GET_BE_WORD(look->SubTable[j]);
1383         mmpf1 = (const GPOS_MarkMarkPosFormat1*)((const BYTE*)look+offset);
1384         if (GET_BE_WORD(mmpf1->PosFormat) == 1)
1385         {
1386             int offset = GET_BE_WORD(mmpf1->Mark1Coverage);
1387             int mark_index;
1388             mark_index = GSUB_is_glyph_covered((const BYTE*)mmpf1+offset, glyphs[glyph_index]);
1389             if (mark_index != -1)
1390             {
1391                 int mark2_index;
1392                 offset = GET_BE_WORD(mmpf1->Mark2Coverage);
1393                 mark2_index = GSUB_is_glyph_covered((const BYTE*)mmpf1+offset, glyphs[glyph_index - write_dir]);
1394                 if (mark2_index != -1)
1395                 {
1396                     const GPOS_MarkArray *ma;
1397                     const GPOS_MarkRecord *mr;
1398                     const GPOS_Mark2Array *m2a;
1399                     const GPOS_Mark2Record *m2r;
1400                     int mark_class;
1401                     int class_count = GET_BE_WORD(mmpf1->ClassCount);
1402                     int mark2record_size;
1403                     POINT mark2_pt;
1404                     POINT mark_pt;
1405                     TRACE("Mark %x(%i) and Mark2 %x(%i)\n",glyphs[glyph_index], mark_index, glyphs[glyph_index - write_dir], mark2_index);
1406                     offset = GET_BE_WORD(mmpf1->Mark1Array);
1407                     ma = (const GPOS_MarkArray*)((const BYTE*)mmpf1 + offset);
1408                     if (mark_index > GET_BE_WORD(ma->MarkCount))
1409                     {
1410                         ERR("Mark index exeeded mark count\n");
1411                         return;
1412                     }
1413                     mr = &ma->MarkRecord[mark_index];
1414                     mark_class = GET_BE_WORD(mr->Class);
1415                     TRACE("Mark Class %i total classes %i\n",mark_class,class_count);
1416                     offset = GET_BE_WORD(mmpf1->Mark2Array);
1417                     m2a = (const GPOS_Mark2Array*)((const BYTE*)mmpf1 + offset);
1418                     mark2record_size = class_count * sizeof(WORD);
1419                     m2r = (const GPOS_Mark2Record*)((const BYTE*)m2a + sizeof(WORD) + (mark2record_size * mark2_index));
1420                     offset = GET_BE_WORD(m2r->Mark2Anchor[mark_class]);
1421                     GPOS_get_anchor_values((const BYTE*)m2a + offset, &mark2_pt, ppem);
1422                     offset = GET_BE_WORD(mr->MarkAnchor);
1423                     GPOS_get_anchor_values((const BYTE*)ma + offset, &mark_pt, ppem);
1424                     TRACE("Offset on mark2 is %i,%i design units\n",mark2_pt.x,mark2_pt.y);
1425                     TRACE("Offset on mark is %i,%i design units\n",mark_pt.x, mark_pt.y);
1426                     pt->x += mark2_pt.x - mark_pt.x;
1427                     pt->y += mark2_pt.y - mark_pt.y;
1428                     TRACE("Resulting cumulative offset is %i,%i design units\n",pt->x,pt->y);
1429                 }
1430             }
1431         }
1432         else
1433             FIXME("Unhandled Mark To Mark Format %i\n",GET_BE_WORD(mmpf1->PosFormat));
1434     }
1435 }
1436
1437 static INT GPOS_apply_ChainContextPos(LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, INT* piAdvance, const OT_LookupList *lookup, const OT_LookupTable *look, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, INT ppem, GOFFSET *pGoffset)
1438 {
1439     int j;
1440
1441     TRACE("Chaining Contextual Positioning Subtable\n");
1442
1443     for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1444     {
1445         int offset;
1446         const GPOS_ChainContextPosFormat3_1 *ccpf3;
1447         int dirLookahead = write_dir;
1448         int dirBacktrack = -1 * write_dir;
1449
1450         offset = GET_BE_WORD(look->SubTable[j]);
1451         ccpf3 = (const GPOS_ChainContextPosFormat3_1*)((const BYTE*)look+offset);
1452
1453         if (GET_BE_WORD(ccpf3->PosFormat) == 1)
1454         {
1455             FIXME("  TODO: subtype 1 (Simple Chaining Context Glyph Positioning)\n");
1456             continue;
1457         }
1458         else if (GET_BE_WORD(ccpf3->PosFormat) == 2)
1459         {
1460             FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Positioning)\n");
1461             continue;
1462         }
1463         else if (GET_BE_WORD(ccpf3->PosFormat) == 3)
1464         {
1465             int k;
1466             int indexGlyphs;
1467             const GPOS_ChainContextPosFormat3_2 *ccpf3_2;
1468             const GPOS_ChainContextPosFormat3_3 *ccpf3_3;
1469             const GPOS_ChainContextPosFormat3_4 *ccpf3_4;
1470
1471             TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Positioning)\n");
1472
1473             for (k = 0; k < GET_BE_WORD(ccpf3->BacktrackGlyphCount); k++)
1474             {
1475                 offset = GET_BE_WORD(ccpf3->Coverage[k]);
1476                 if (GSUB_is_glyph_covered((const BYTE*)ccpf3+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
1477                     break;
1478             }
1479             if (k != GET_BE_WORD(ccpf3->BacktrackGlyphCount))
1480                 continue;
1481             TRACE("Matched Backtrack\n");
1482
1483             ccpf3_2 = (const GPOS_ChainContextPosFormat3_2*)((BYTE *)ccpf3 +
1484                     FIELD_OFFSET(GPOS_ChainContextPosFormat3_1, Coverage[GET_BE_WORD(ccpf3->BacktrackGlyphCount)]));
1485
1486             indexGlyphs = GET_BE_WORD(ccpf3_2->InputGlyphCount);
1487             for (k = 0; k < indexGlyphs; k++)
1488             {
1489                 offset = GET_BE_WORD(ccpf3_2->Coverage[k]);
1490                 if (GSUB_is_glyph_covered((const BYTE*)ccpf3+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
1491                     break;
1492             }
1493             if (k != indexGlyphs)
1494                 continue;
1495             TRACE("Matched IndexGlyphs\n");
1496
1497             ccpf3_3 = (const GPOS_ChainContextPosFormat3_3*)((BYTE *)ccpf3_2 +
1498                     FIELD_OFFSET(GPOS_ChainContextPosFormat3_2, Coverage[GET_BE_WORD(ccpf3_2->InputGlyphCount)]));
1499
1500             for (k = 0; k < GET_BE_WORD(ccpf3_3->LookaheadGlyphCount); k++)
1501             {
1502                 offset = GET_BE_WORD(ccpf3_3->Coverage[k]);
1503                 if (GSUB_is_glyph_covered((const BYTE*)ccpf3+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
1504                     break;
1505             }
1506             if (k != GET_BE_WORD(ccpf3_3->LookaheadGlyphCount))
1507                 continue;
1508             TRACE("Matched LookAhead\n");
1509
1510             ccpf3_4 = (const GPOS_ChainContextPosFormat3_4*)((BYTE *)ccpf3_3 +
1511                     FIELD_OFFSET(GPOS_ChainContextPosFormat3_3, Coverage[GET_BE_WORD(ccpf3_3->LookaheadGlyphCount)]));
1512
1513             if (GET_BE_WORD(ccpf3_4->PosCount))
1514             {
1515                 for (k = 0; k < GET_BE_WORD(ccpf3_4->PosCount); k++)
1516                 {
1517                     int lookupIndex = GET_BE_WORD(ccpf3_4->PosLookupRecord[k].LookupListIndex);
1518                     int SequenceIndex = GET_BE_WORD(ccpf3_4->PosLookupRecord[k].SequenceIndex) * write_dir;
1519
1520                     TRACE("Position: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
1521                     GPOS_apply_lookup(lpotm, lplogfont, piAdvance, lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count, pGoffset);
1522                 }
1523                 return glyph_index + indexGlyphs + GET_BE_WORD(ccpf3_3->LookaheadGlyphCount);
1524             }
1525             else return glyph_index + 1;
1526         }
1527         else
1528             FIXME("Unhandled Chaining Contextual Positioning Format %i\n",GET_BE_WORD(ccpf3->PosFormat));
1529     }
1530     return glyph_index + 1;
1531 }
1532
1533 static INT GPOS_apply_lookup(LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, INT* piAdvance, const OT_LookupList* lookup, INT lookup_index, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, GOFFSET *pGoffset)
1534 {
1535     int offset;
1536     const OT_LookupTable *look;
1537     int ppem = lpotm->otmTextMetrics.tmAscent + lpotm->otmTextMetrics.tmDescent - lpotm->otmTextMetrics.tmInternalLeading;
1538
1539     offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1540     look = (const OT_LookupTable*)((const BYTE*)lookup + offset);
1541     TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1542     switch(GET_BE_WORD(look->LookupType))
1543     {
1544         case 1:
1545         {
1546             double devX, devY;
1547             POINT adjust = {0,0};
1548             POINT advance = {0,0};
1549             GPOS_apply_SingleAdjustment(look, glyphs, glyph_index, write_dir, glyph_count, ppem, &adjust, &advance);
1550             if (adjust.x || adjust.y)
1551             {
1552                 GPOS_convert_design_units_to_device(lpotm, lplogfont, adjust.x, adjust.y, &devX, &devY);
1553                 pGoffset[glyph_index].du += round(devX);
1554                 pGoffset[glyph_index].dv += round(devY);
1555             }
1556             if (advance.x || advance.y)
1557             {
1558                 GPOS_convert_design_units_to_device(lpotm, lplogfont, advance.x, advance.y, &devX, &devY);
1559                 piAdvance[glyph_index] += round(devX);
1560                 if (advance.y)
1561                     FIXME("Unhandled adjustment to Y advancement\n");
1562             }
1563             break;
1564         }
1565         case 2:
1566         {
1567             POINT advance[2]= {{0,0},{0,0}};
1568             POINT adjust[2]= {{0,0},{0,0}};
1569             double devX, devY;
1570             int index;
1571             index = GPOS_apply_PairAdjustment(look, glyphs, glyph_index, write_dir, glyph_count, ppem, adjust, advance);
1572             if (adjust[0].x || adjust[0].y)
1573             {
1574                 GPOS_convert_design_units_to_device(lpotm, lplogfont, adjust[0].x, adjust[0].y, &devX, &devY);
1575                 pGoffset[glyph_index].du += round(devX);
1576                 pGoffset[glyph_index].dv += round(devY);
1577             }
1578             if (advance[0].x || advance[0].y)
1579             {
1580                 GPOS_convert_design_units_to_device(lpotm, lplogfont, advance[0].x, advance[0].y, &devX, &devY);
1581                 piAdvance[glyph_index] += round(devX);
1582             }
1583             if (adjust[1].x || adjust[1].y)
1584             {
1585                 GPOS_convert_design_units_to_device(lpotm, lplogfont, adjust[1].x, adjust[1].y, &devX, &devY);
1586                 pGoffset[glyph_index + write_dir].du += round(devX);
1587                 pGoffset[glyph_index + write_dir].dv += round(devY);
1588             }
1589             if (advance[1].x || advance[1].y)
1590             {
1591                 GPOS_convert_design_units_to_device(lpotm, lplogfont, advance[1].x, advance[1].y, &devX, &devY);
1592                 piAdvance[glyph_index + write_dir] += round(devX);
1593             }
1594             return index;
1595         }
1596         case 4:
1597         {
1598             double devX, devY;
1599             POINT desU = {0,0};
1600             GPOS_apply_MarkToBase(look, glyphs, glyph_index, write_dir, glyph_count, ppem, &desU);
1601             if (desU.x || desU.y)
1602             {
1603                 GPOS_convert_design_units_to_device(lpotm, lplogfont, desU.x, desU.y, &devX, &devY);
1604                 pGoffset[glyph_index].du += (round(devX) - piAdvance[glyph_index-1]);
1605                 pGoffset[glyph_index].dv += round(devY);
1606             }
1607             break;
1608         }
1609         case 6:
1610         {
1611             double devX, devY;
1612             POINT desU = {0,0};
1613             GPOS_apply_MarkToMark(look, glyphs, glyph_index, write_dir, glyph_count, ppem, &desU);
1614             if (desU.x || desU.y)
1615             {
1616                 GPOS_convert_design_units_to_device(lpotm, lplogfont, desU.x, desU.y, &devX, &devY);
1617                 pGoffset[glyph_index].du += round(devX) + pGoffset[glyph_index-1].du;
1618                 pGoffset[glyph_index].dv += round(devY) + pGoffset[glyph_index-1].dv;
1619             }
1620             break;
1621         }
1622         case 8:
1623         {
1624             return GPOS_apply_ChainContextPos(lpotm, lplogfont, piAdvance, lookup, look, glyphs, glyph_index, write_dir, glyph_count, ppem, pGoffset);
1625         }
1626         default:
1627             FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1628     }
1629     return glyph_index+1;
1630 }
1631
1632 INT OpenType_apply_GPOS_lookup(LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, INT* piAdvance, LPCVOID table, INT lookup_index, const WORD *glyphs, INT glyph_index, INT write_dir, INT glyph_count, GOFFSET *pGoffset)
1633 {
1634     const GPOS_Header *header = (const GPOS_Header *)table;
1635     const OT_LookupList *lookup = (const OT_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1636
1637     return GPOS_apply_lookup(lpotm, lplogfont, piAdvance, lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count, pGoffset);
1638 }
1639
1640 static void GSUB_initialize_script_cache(ScriptCache *psc)
1641 {
1642     int i;
1643
1644     if (psc->GSUB_Table)
1645     {
1646         const OT_ScriptList *script;
1647         const GSUB_Header* header = (const GSUB_Header*)psc->GSUB_Table;
1648         script = (const OT_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
1649         psc->script_count = GET_BE_WORD(script->ScriptCount);
1650         TRACE("initializing %i scripts in this font\n",psc->script_count);
1651         if (psc->script_count)
1652         {
1653             psc->scripts = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LoadedScript) * psc->script_count);
1654             for (i = 0; i < psc->script_count; i++)
1655             {
1656                 int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
1657                 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]);
1658                 psc->scripts[i].gsub_table = ((const BYTE*)script + offset);
1659             }
1660         }
1661     }
1662 }
1663
1664 static void GPOS_expand_script_cache(ScriptCache *psc)
1665 {
1666     int i, count;
1667     const OT_ScriptList *script;
1668     const GPOS_Header* header = (const GPOS_Header*)psc->GPOS_Table;
1669
1670     if (!header)
1671         return;
1672
1673     script = (const OT_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
1674     count = GET_BE_WORD(script->ScriptCount);
1675
1676     if (!psc->script_count)
1677     {
1678         psc->script_count = count;
1679         TRACE("initializing %i scripts in this font\n",psc->script_count);
1680         if (psc->script_count)
1681         {
1682             psc->scripts = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LoadedScript) * psc->script_count);
1683             for (i = 0; i < psc->script_count; i++)
1684             {
1685                 int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
1686                 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]);
1687                 psc->scripts[i].gpos_table = ((const BYTE*)script + offset);
1688             }
1689         }
1690     }
1691     else
1692     {
1693         for (i = 0; i < count; i++)
1694         {
1695             int j;
1696             int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
1697             OPENTYPE_TAG tag = MS_MAKE_TAG(script->ScriptRecord[i].ScriptTag[0], script->ScriptRecord[i].ScriptTag[1], script->ScriptRecord[i].ScriptTag[2], script->ScriptRecord[i].ScriptTag[3]);
1698             for (j = 0; j < psc->script_count; j++)
1699             {
1700                 if (psc->scripts[j].tag == tag)
1701                 {
1702                     psc->scripts[j].gpos_table = ((const BYTE*)script + offset);
1703                     break;
1704                 }
1705             }
1706             if (j == psc->script_count)
1707             {
1708                 psc->script_count++;
1709                 psc->scripts = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,psc->scripts, sizeof(LoadedScript) * psc->script_count);
1710                 psc->scripts[j].tag = tag;
1711                 psc->scripts[j].gpos_table = ((const BYTE*)script + offset);
1712             }
1713         }
1714     }
1715 }
1716
1717 static void _initialize_script_cache(ScriptCache *psc)
1718 {
1719     if (!psc->script_count)
1720     {
1721         GSUB_initialize_script_cache(psc);
1722         GPOS_expand_script_cache(psc);
1723     }
1724 }
1725
1726 HRESULT OpenType_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
1727 {
1728     int i;
1729     HRESULT rc = S_OK;
1730
1731     _initialize_script_cache(psc);
1732
1733     *pcTags = psc->script_count;
1734
1735     if (!searchingFor && cMaxTags < *pcTags)
1736         rc = E_OUTOFMEMORY;
1737     else if (searchingFor)
1738         rc = USP_E_SCRIPT_NOT_IN_FONT;
1739
1740     for (i = 0; i < psc->script_count; i++)
1741     {
1742         if (i < cMaxTags)
1743             pScriptTags[i] = psc->scripts[i].tag;
1744
1745         if (searchingFor)
1746         {
1747             if (searchingFor == psc->scripts[i].tag)
1748             {
1749                 pScriptTags[0] = psc->scripts[i].tag;
1750                 *pcTags = 1;
1751                 rc = S_OK;
1752                 break;
1753             }
1754         }
1755     }
1756     return rc;
1757 }
1758
1759 static void GSUB_initialize_language_cache(LoadedScript *script)
1760 {
1761     int i;
1762
1763     if (script->gsub_table)
1764     {
1765         DWORD offset;
1766         const OT_Script* table = script->gsub_table;
1767         script->language_count = GET_BE_WORD(table->LangSysCount);
1768         offset = GET_BE_WORD(table->DefaultLangSys);
1769         if (offset)
1770         {
1771             script->default_language.tag = MS_MAKE_TAG('d','f','l','t');
1772             script->default_language.gsub_table = (const BYTE*)table + offset;
1773         }
1774
1775         if (script->language_count)
1776         {
1777             TRACE("Deflang %p, LangCount %i\n",script->default_language.gsub_table, script->language_count);
1778
1779             script->languages = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LoadedLanguage) * script->language_count);
1780
1781             for (i = 0; i < script->language_count; i++)
1782             {
1783                 int offset = GET_BE_WORD(table->LangSysRecord[i].LangSys);
1784                 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]);
1785                 script->languages[i].gsub_table = ((const BYTE*)table + offset);
1786             }
1787         }
1788     }
1789 }
1790
1791 static void GPOS_expand_language_cache(LoadedScript *script)
1792 {
1793     int count;
1794     const OT_Script* table = script->gpos_table;
1795     DWORD offset;
1796
1797     if (!table)
1798         return;
1799
1800     offset = GET_BE_WORD(table->DefaultLangSys);
1801     if (offset)
1802         script->default_language.gpos_table = (const BYTE*)table + offset;
1803
1804     count = GET_BE_WORD(table->LangSysCount);
1805
1806     TRACE("Deflang %p, LangCount %i\n",script->default_language.gpos_table, count);
1807     if (!script->language_count)
1808     {
1809         int i;
1810         script->language_count = count;
1811
1812         script->languages = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LoadedLanguage) * script->language_count);
1813
1814         for (i = 0; i < script->language_count; i++)
1815         {
1816             int offset = GET_BE_WORD(table->LangSysRecord[i].LangSys);
1817             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]);
1818             script->languages[i].gpos_table = ((const BYTE*)table + offset);
1819         }
1820     }
1821     else if (count)
1822     {
1823         int i,j;
1824         for (i = 0; i < count; i++)
1825         {
1826             int offset = GET_BE_WORD(table->LangSysRecord[i].LangSys);
1827             OPENTYPE_TAG tag = MS_MAKE_TAG(table->LangSysRecord[i].LangSysTag[0], table->LangSysRecord[i].LangSysTag[1], table->LangSysRecord[i].LangSysTag[2], table->LangSysRecord[i].LangSysTag[3]);
1828
1829             for (j = 0; j < script->language_count; j++)
1830             {
1831                 if (script->languages[j].tag == tag)
1832                 {
1833                     script->languages[j].gpos_table = ((const BYTE*)table + offset);
1834                     break;
1835                 }
1836             }
1837             if (j == script->language_count)
1838             {
1839                 script->language_count++;
1840                 script->languages = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,script->languages, sizeof(LoadedLanguage) * script->language_count);
1841                 script->languages[j].tag = tag;
1842                 script->languages[j].gpos_table = ((const BYTE*)table + offset);
1843             }
1844         }
1845     }
1846 }
1847
1848 static void _initialize_language_cache(LoadedScript *script)
1849 {
1850     if (!script->language_count)
1851     {
1852         GSUB_initialize_language_cache(script);
1853         GPOS_expand_language_cache(script);
1854     }
1855 }
1856
1857 HRESULT OpenType_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags)
1858 {
1859     int i;
1860     HRESULT rc = S_OK;
1861     LoadedScript *script = NULL;
1862
1863     _initialize_script_cache(psc);
1864
1865     for (i = 0; i < psc->script_count; i++)
1866     {
1867          if (psc->scripts[i].tag == script_tag)
1868          {
1869             script = &psc->scripts[i];
1870             break;
1871          }
1872     }
1873
1874     if (!script)
1875         return E_INVALIDARG;
1876
1877     _initialize_language_cache(script);
1878
1879     if (!searchingFor && cMaxTags < script->language_count)
1880         rc = E_OUTOFMEMORY;
1881     else if (searchingFor)
1882         rc = E_INVALIDARG;
1883
1884     *pcTags = script->language_count;
1885
1886     for (i = 0; i < script->language_count; i++)
1887     {
1888         if (i < cMaxTags)
1889             pLanguageTags[i] = script->languages[i].tag;
1890
1891         if (searchingFor)
1892         {
1893             if (searchingFor == script->languages[i].tag)
1894             {
1895                 pLanguageTags[0] = script->languages[i].tag;
1896                 *pcTags = 1;
1897                 rc = S_OK;
1898                 break;
1899             }
1900         }
1901     }
1902
1903     if (script->default_language.gsub_table)
1904     {
1905         if (i < cMaxTags)
1906             pLanguageTags[i] = script->default_language.tag;
1907
1908         if (searchingFor  && FAILED(rc))
1909         {
1910             pLanguageTags[0] = script->default_language.tag;
1911         }
1912         i++;
1913         *pcTags = (*pcTags) + 1;
1914     }
1915
1916     return rc;
1917 }
1918
1919
1920 static void GSUB_initialize_feature_cache(LPCVOID table, LoadedLanguage *language)
1921 {
1922     int i;
1923
1924     if (language->gsub_table)
1925     {
1926         const OT_LangSys *lang = language->gsub_table;
1927         const GSUB_Header *header = (const GSUB_Header *)table;
1928         const OT_FeatureList *feature_list;
1929
1930         language->feature_count = GET_BE_WORD(lang->FeatureCount);
1931         TRACE("%i features\n",language->feature_count);
1932
1933         if (language->feature_count)
1934         {
1935             language->features = HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature)*language->feature_count);
1936
1937             feature_list = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
1938
1939             for (i = 0; i < language->feature_count; i++)
1940             {
1941                 const OT_Feature *feature;
1942                 int j;
1943                 int index = GET_BE_WORD(lang->FeatureIndex[i]);
1944
1945                 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]);
1946                 language->features[i].feature = ((const BYTE*)feature_list + GET_BE_WORD(feature_list->FeatureRecord[index].Feature));
1947                 feature = (const OT_Feature*)language->features[i].feature;
1948                 language->features[i].lookup_count = GET_BE_WORD(feature->LookupCount);
1949                 language->features[i].lookups = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * language->features[i].lookup_count);
1950                 for (j = 0; j < language->features[i].lookup_count; j++)
1951                     language->features[i].lookups[j] = GET_BE_WORD(feature->LookupListIndex[j]);
1952             }
1953         }
1954     }
1955 }
1956
1957 static void GPOS_expand_feature_cache(LPCVOID table, LoadedLanguage *language)
1958 {
1959     int i, count;
1960     const OT_LangSys *lang = language->gpos_table;
1961     const GPOS_Header *header = (const GPOS_Header *)table;
1962     const OT_FeatureList *feature_list;
1963
1964     if (!lang)
1965         return;
1966
1967     count = GET_BE_WORD(lang->FeatureCount);
1968     feature_list = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
1969
1970     TRACE("%i features\n",count);
1971     if (!language->feature_count)
1972     {
1973         language->feature_count = count;
1974
1975         if (language->feature_count)
1976         {
1977             language->features = HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature)*language->feature_count);
1978
1979             for (i = 0; i < language->feature_count; i++)
1980             {
1981                 const OT_Feature *feature;
1982                 int j;
1983                 int index = GET_BE_WORD(lang->FeatureIndex[i]);
1984
1985                 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]);
1986                 language->features[i].feature = ((const BYTE*)feature_list + GET_BE_WORD(feature_list->FeatureRecord[index].Feature));
1987                 feature = (const OT_Feature*)language->features[i].feature;
1988                 language->features[i].lookup_count = GET_BE_WORD(feature->LookupCount);
1989                 language->features[i].lookups = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * language->features[i].lookup_count);
1990                 for (j = 0; j < language->features[i].lookup_count; j++)
1991                     language->features[i].lookups[j] = GET_BE_WORD(feature->LookupListIndex[j]);
1992             }
1993         }
1994     }
1995     else if (count)
1996     {
1997         language->features = HeapReAlloc(GetProcessHeap(),0,language->features, sizeof(LoadedFeature)*(language->feature_count + count));
1998
1999         for (i = 0; i < count; i++)
2000         {
2001             const OT_Feature *feature;
2002             int j;
2003             int index = GET_BE_WORD(lang->FeatureIndex[i]);
2004             int idx = language->feature_count + i;
2005
2006             language->features[idx].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]);
2007             language->features[idx].feature = ((const BYTE*)feature_list + GET_BE_WORD(feature_list->FeatureRecord[index].Feature));
2008             feature = (const OT_Feature*)language->features[idx].feature;
2009             language->features[idx].lookup_count = GET_BE_WORD(feature->LookupCount);
2010             language->features[idx].lookups = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * language->features[idx].lookup_count);
2011             for (j = 0; j < language->features[idx].lookup_count; j++)
2012                 language->features[idx].lookups[j] = GET_BE_WORD(feature->LookupListIndex[j]);
2013         }
2014         language->feature_count += count;
2015     }
2016 }
2017
2018 static void _initialize_feature_cache(ScriptCache *psc, LoadedLanguage *language)
2019 {
2020     if (!language->feature_count)
2021     {
2022         GSUB_initialize_feature_cache(psc->GSUB_Table, language);
2023         GPOS_expand_feature_cache(psc->GPOS_Table, language);
2024     }
2025 }
2026
2027 HRESULT OpenType_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)
2028 {
2029     int i;
2030     HRESULT rc = S_OK;
2031     LoadedScript *script = NULL;
2032     LoadedLanguage *language = NULL;
2033
2034     _initialize_script_cache(psc);
2035
2036     for (i = 0; i < psc->script_count; i++)
2037     {
2038         if (psc->scripts[i].tag == script_tag)
2039         {
2040             script = &psc->scripts[i];
2041             break;
2042         }
2043     }
2044
2045     if (!script)
2046     {
2047         *pcTags = 0;
2048         if (!filtered)
2049             return S_OK;
2050         else
2051             return E_INVALIDARG;
2052     }
2053
2054     _initialize_language_cache(script);
2055
2056     if ((script->default_language.gsub_table || script->default_language.gpos_table) && script->default_language.tag == language_tag)
2057         language = &script->default_language;
2058     else
2059     {
2060         for (i = 0; i < script->language_count; i++)
2061         {
2062             if (script->languages[i].tag == language_tag)
2063             {
2064                 language = &script->languages[i];
2065                 break;
2066             }
2067         }
2068     }
2069
2070     if (!language)
2071     {
2072         *pcTags = 0;
2073         return S_OK;
2074     }
2075
2076     _initialize_feature_cache(psc, language);
2077
2078     *pcTags = language->feature_count;
2079
2080     if (!searchingFor && cMaxTags < *pcTags)
2081         rc = E_OUTOFMEMORY;
2082     else if (searchingFor)
2083         rc = E_INVALIDARG;
2084
2085     for (i = 0; i < language->feature_count; i++)
2086     {
2087         if (i < cMaxTags)
2088             pFeatureTags[i] = language->features[i].tag;
2089
2090         if (searchingFor)
2091         {
2092             if (searchingFor == language->features[i].tag)
2093             {
2094                 pFeatureTags[0] = language->features[i].tag;
2095                 *pcTags = 1;
2096                 if (feature)
2097                     *feature = &language->features[i];
2098                 rc = S_OK;
2099                 break;
2100             }
2101         }
2102     }
2103     return rc;
2104 }