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