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