ReactOS 0.4.15-dev-7924-g5949c20
opentype.c
Go to the documentation of this file.
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#include "wine/heap.h"
36
38
39#ifdef WORDS_BIGENDIAN
40#define GET_BE_WORD(x) (x)
41#define GET_BE_DWORD(x) (x)
42#else
43#define GET_BE_WORD(x) RtlUshortByteSwap(x)
44#define GET_BE_DWORD(x) RtlUlongByteSwap(x)
45#endif
46
47#define round(x) (((x) < 0) ? (int)((x) - 0.5) : (int)((x) + 0.5))
48
49/* These are all structures needed for the cmap format 12 table */
50#define CMAP_TAG MS_MAKE_TAG('c', 'm', 'a', 'p')
51
53{
63};
64
66{
75};
76
77typedef struct {
82
83typedef struct {
88
89typedef struct {
94
95typedef struct {
103
104/* These are all structures needed for the GDEF table */
106
107typedef struct {
114
115typedef struct {
119 WORD ClassValueArray[1];
121
122typedef struct {
127
128typedef struct {
131 OT_ClassRangeRecord ClassRangeRecord[1];
133
134/* These are all structures needed for the GSUB table */
135
136typedef struct {
142
143typedef struct {
144 CHAR ScriptTag[4];
147
148typedef struct {
150 OT_ScriptRecord ScriptRecord[1];
152
153typedef struct {
154 CHAR LangSysTag[4];
157
158typedef struct {
161 OT_LangSysRecord LangSysRecord[1];
162} OT_Script;
163
164typedef struct {
165 WORD LookupOrder; /* Reserved */
168 WORD FeatureIndex[1];
169} OT_LangSys;
170
171typedef struct {
172 CHAR FeatureTag[4];
175
176typedef struct {
178 OT_FeatureRecord FeatureRecord[1];
180
181typedef struct {
182 WORD FeatureParams; /* Reserved */
184 WORD LookupListIndex[1];
185} OT_Feature;
186
187typedef struct {
191
192typedef struct {
196 WORD SubTable[1];
198
199typedef struct {
202 WORD GlyphArray[1];
204
205typedef struct {
210
211typedef struct {
214 OT_RangeRecord RangeRecord[1];
216
217typedef struct {
218 WORD SubstFormat; /* = 1 */
222
223typedef struct {
224 WORD SubstFormat; /* = 2 */
229
230typedef struct {
231 WORD SubstFormat; /* = 1 */
234 WORD Sequence[1];
236
237typedef struct {
241
242typedef struct {
243 WORD SubstFormat; /* = 1 */
246 WORD LigatureSet[1];
248
249typedef struct {
253
254typedef struct{
259
260typedef struct{
263
265
266typedef struct{
270 WORD SubRuleSet[1];
272
273typedef struct{
275 WORD SubRule[1];
277
278typedef struct {
283
284typedef struct {
285 GSUB_SubstLookupRecord SubstLookupRecord[1];
287
288typedef struct {
293 WORD SubClassSet[1];
295
296typedef struct {
298 WORD SubClassRule[1];
300
301typedef struct {
306
307typedef struct {
308 GSUB_SubstLookupRecord SubstLookupRecord[1];
310
311typedef struct{
312 WORD SubstFormat; /* = 1 */
315 WORD ChainSubRuleSet[1];
317
318typedef struct {
319 WORD SubstFormat; /* = 2 */
325 WORD ChainSubClassSet[1];
327
328typedef struct {
330 WORD ChainSubClassRule[1];
332
333typedef struct {
335 WORD Backtrack[1];
337
338typedef struct {
342
343typedef struct {
345 WORD LookAhead[1];
347
348typedef struct {
350 GSUB_SubstLookupRecord SubstLookupRecord[1];
352
353typedef struct {
354 WORD SubstFormat; /* = 3 */
356 WORD Coverage[1];
358
359typedef struct{
361 WORD Coverage[1];
363
364typedef struct{
366 WORD Coverage[1];
368
369typedef struct{
371 GSUB_SubstLookupRecord SubstLookupRecord[1];
373
374typedef struct {
375 WORD SubstFormat; /* = 1 */
378 WORD AlternateSet[1];
380
381typedef struct{
383 WORD Alternate[1];
385
386typedef struct {
391
392/* These are all structures needed for the GPOS table */
393
394typedef struct {
400
401typedef struct {
405 WORD DeltaValue[1];
407
408typedef struct {
413
414typedef struct {
420
421typedef struct {
428
429typedef struct {
439
440typedef struct {
446
447typedef struct {
454
455typedef struct {
461 WORD PairSetOffset[1];
463
464typedef struct {
473 WORD Class1Record[1];
475
476typedef struct {
478 WORD Value1[1];
479 WORD Value2[1];
481
482typedef struct {
484 GPOS_PairValueRecord PairValueRecord[1];
486
487typedef struct {
491
492typedef struct {
496 GPOS_EntryExitRecord EntryExitRecord[1];
498
499typedef struct {
507
508typedef struct {
509 WORD BaseAnchor[1];
511
512typedef struct {
514 GPOS_BaseRecord BaseRecord[1];
516
517typedef struct {
521
522typedef struct {
524 GPOS_MarkRecord MarkRecord[1];
526
527typedef struct {
535
536typedef struct {
538 WORD LigatureAttach[1];
540
541typedef struct {
542 WORD LigatureAnchor[1];
544
545typedef struct {
547 GPOS_ComponentRecord ComponentRecord[1];
549
550typedef struct {
558
559typedef struct {
560 WORD Mark2Anchor[1];
562
563typedef struct {
565 GPOS_Mark2Record Mark2Record[1];
567
568typedef struct {
572
573typedef struct {
578 WORD PosClassSet[1];
580
581typedef struct {
583 WORD PosClassRule[1];
585
586typedef struct {
591
592typedef struct {
593 GPOS_PosLookupRecord PosLookupRecord[1];
595
596typedef struct {
599 WORD Coverage[1];
601
602typedef struct {
604 WORD Coverage[1];
606
607typedef struct {
609 WORD Coverage[1];
611
612typedef struct {
614 GPOS_PosLookupRecord PosLookupRecord[1];
616
617typedef struct {
622
623/**********
624 * CMAP
625 **********/
626
628{
629 CMAP_Header *CMAP_Table = NULL;
630 int length;
631 int i;
632
633 if (!psc->CMAP_Table)
634 {
635 length = GetFontData(hdc, CMAP_TAG , 0, NULL, 0);
636 if (length != GDI_ERROR)
637 {
638 psc->CMAP_Table = heap_alloc(length);
639 GetFontData(hdc, CMAP_TAG , 0, psc->CMAP_Table, length);
640 TRACE("Loaded cmap table of %i bytes\n",length);
641 }
642 else
643 return NULL;
644 }
645
646 CMAP_Table = psc->CMAP_Table;
647
648 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
649 {
650 if ( (GET_BE_WORD(CMAP_Table->tables[i].platformID) == 3) &&
651 (GET_BE_WORD(CMAP_Table->tables[i].encodingID) == 10) )
652 {
654 if (GET_BE_WORD(format->format) == 12)
655 return format;
656 }
657 }
658 return NULL;
659}
660
661static int __cdecl compare_group(const void *a, const void* b)
662{
663 const DWORD *chr = a;
665
666 if (*chr < GET_BE_DWORD(group->startCharCode))
667 return -1;
668 if (*chr > GET_BE_DWORD(group->endCharCode))
669 return 1;
670 return 0;
671}
672
674{
675 /* BMP: use gdi32 for ease */
676 if (utf32c < 0x10000)
677 {
678 WCHAR ch = utf32c;
679 return GetGlyphIndicesW(hdc, &ch, 1, glyph_index, flags);
680 }
681
682 if (!psc->CMAP_format12_Table)
683 psc->CMAP_format12_Table = load_CMAP_format12_table(hdc, psc);
684
686 *glyph_index = 0xffffu;
687 else
688 *glyph_index = 0u;
689
690 if (psc->CMAP_format12_Table)
691 {
694
695 format = (CMAP_SegmentedCoverage *)psc->CMAP_format12_Table;
696
697 group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
699
700 if (group)
701 {
702 DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
703 *glyph_index = GET_BE_DWORD(group->startGlyphID) + offset;
704 return 0;
705 }
706 }
707 return 0;
708}
709
710/**********
711 * GDEF
712 **********/
713
714static WORD OT_get_glyph_class(const void *table, WORD glyph)
715{
716 WORD class = 0;
717 const OT_ClassDefFormat1 *cf1 = table;
718
719 if (!table) return 0;
720
721 if (GET_BE_WORD(cf1->ClassFormat) == 1)
722 {
723 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
724 {
725 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
726 if (index < GET_BE_WORD(cf1->GlyphCount))
727 class = GET_BE_WORD(cf1->ClassValueArray[index]);
728 }
729 }
730 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
731 {
732 const OT_ClassDefFormat2 *cf2 = table;
733 int i, top;
735 for (i = 0; i < top; i++)
736 {
737 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
738 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
739 {
740 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
741 break;
742 }
743 }
744 }
745 else
746 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
747
748 return class;
749}
750
752{
753 int i;
754 void *glyph_class_table = NULL;
755
756 if (psc->GDEF_Table)
757 {
758 const GDEF_Header *header = psc->GDEF_Table;
759 WORD offset = GET_BE_WORD( header->GlyphClassDef );
760 if (offset)
761 glyph_class_table = (BYTE *)psc->GDEF_Table + offset;
762 }
763
764 for (i = 0; i < cGlyphs; i++)
765 {
766 WORD class;
767 int char_count = 0;
768 int k;
769
771 if (k >= 0)
772 {
773 for (; k < cChars && pwLogClust[k] == i; k++)
774 char_count++;
775 }
776
777 class = OT_get_glyph_class( glyph_class_table, pwGlyphs[i] );
778
779 switch (class)
780 {
781 case 0:
782 case BaseGlyph:
783 pGlyphProp[i].sva.fClusterStart = 1;
784 pGlyphProp[i].sva.fDiacritic = 0;
785 pGlyphProp[i].sva.fZeroWidth = 0;
786 break;
787 case LigatureGlyph:
788 pGlyphProp[i].sva.fClusterStart = 1;
789 pGlyphProp[i].sva.fDiacritic = 0;
790 pGlyphProp[i].sva.fZeroWidth = 0;
791 break;
792 case MarkGlyph:
793 pGlyphProp[i].sva.fClusterStart = 0;
794 pGlyphProp[i].sva.fDiacritic = 1;
795 pGlyphProp[i].sva.fZeroWidth = 1;
796 break;
797 case ComponentGlyph:
798 pGlyphProp[i].sva.fClusterStart = 0;
799 pGlyphProp[i].sva.fDiacritic = 0;
800 pGlyphProp[i].sva.fZeroWidth = 0;
801 break;
802 default:
803 ERR("Unknown glyph class %i\n",class);
804 pGlyphProp[i].sva.fClusterStart = 1;
805 pGlyphProp[i].sva.fDiacritic = 0;
806 pGlyphProp[i].sva.fZeroWidth = 0;
807 }
808
809 if (char_count == 0)
810 pGlyphProp[i].sva.fClusterStart = 0;
811 }
812}
813
814/**********
815 * GSUB
816 **********/
817static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
818
819static int GSUB_is_glyph_covered(const void *table, unsigned int glyph)
820{
821 const OT_CoverageFormat1* cf1;
822
823 cf1 = table;
824
825 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
826 {
827 int count = GET_BE_WORD(cf1->GlyphCount);
828 int i;
829 TRACE("Coverage Format 1, %i glyphs\n",count);
830 for (i = 0; i < count; i++)
831 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
832 return i;
833 return -1;
834 }
835 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
836 {
837 const OT_CoverageFormat2* cf2;
838 int i;
839 int count;
840 cf2 = (const OT_CoverageFormat2*)cf1;
841
843 TRACE("Coverage Format 2, %i ranges\n",count);
844 for (i = 0; i < count; i++)
845 {
846 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
847 return -1;
848 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
849 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
850 {
852 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
853 }
854 }
855 return -1;
856 }
857 else
858 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
859
860 return -1;
861}
862
863static const BYTE *GSUB_get_subtable(const OT_LookupTable *look, int index)
864{
865 int offset = GET_BE_WORD(look->SubTable[index]);
866
868 {
869 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)look + offset);
870 if (GET_BE_WORD(ext->SubstFormat) == 1)
871 {
872 offset += GET_BE_DWORD(ext->ExtensionOffset);
873 }
874 else
875 {
876 FIXME("Unhandled Extension Substitution Format %i\n",GET_BE_WORD(ext->SubstFormat));
877 }
878 }
879 return (const BYTE *)look + offset;
880}
881
882static INT GSUB_apply_SingleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
883{
884 int j;
885 TRACE("Single Substitution Subtable\n");
886
887 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
888 {
890 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
891 {
892 int offset = GET_BE_WORD(ssf1->Coverage);
893 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
894 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
895 {
896 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
897 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
898 TRACE(" 0x%x\n",glyphs[glyph_index]);
899 return glyph_index + write_dir;
900 }
901 }
902 else
903 {
904 const GSUB_SingleSubstFormat2 *ssf2;
905 INT index;
906 INT offset;
907
908 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
909 offset = GET_BE_WORD(ssf1->Coverage);
910 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
911 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
912 TRACE(" Coverage index %i\n",index);
913 if (index != -1)
914 {
915 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
916 return GSUB_E_NOGLYPH;
917
918 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
919 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
920 TRACE("0x%x\n",glyphs[glyph_index]);
921 return glyph_index + write_dir;
922 }
923 }
924 }
925 return GSUB_E_NOGLYPH;
926}
927
928static INT GSUB_apply_MultipleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
929{
930 int j;
931 TRACE("Multiple Substitution Subtable\n");
932
933 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
934 {
935 int offset, index;
936 const GSUB_MultipleSubstFormat1 *msf1;
937 msf1 = (const GSUB_MultipleSubstFormat1*)GSUB_get_subtable(look, j);
938
939 offset = GET_BE_WORD(msf1->Coverage);
940 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
941 if (index != -1)
942 {
943 const GSUB_Sequence *seq;
944 int sub_count;
945 int j;
947 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
948 sub_count = GET_BE_WORD(seq->GlyphCount);
949 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
950
951 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
952 glyphs[j] =glyphs[j-(sub_count-1)];
953
954 for (j = 0; j < sub_count; j++)
955 if (write_dir < 0)
956 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
957 else
958 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
959
960 *glyph_count = *glyph_count + (sub_count - 1);
961
962 if (TRACE_ON(uniscribe))
963 {
964 for (j = 0; j < sub_count; j++)
965 TRACE(" 0x%x",glyphs[glyph_index+j]);
966 TRACE("\n");
967 }
968
969 if (write_dir > 0)
970 return glyph_index + sub_count;
971 else
972 return glyph_index - 1;
973 }
974 }
975 return GSUB_E_NOGLYPH;
976}
977
978static INT GSUB_apply_AlternateSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
979{
980 int j;
981 TRACE("Alternate Substitution Subtable\n");
982
983 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
984 {
985 int offset;
986 const GSUB_AlternateSubstFormat1 *asf1;
987 INT index;
988
989 asf1 = (const GSUB_AlternateSubstFormat1*)GSUB_get_subtable(look, j);
990 offset = GET_BE_WORD(asf1->Coverage);
991
992 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
993 if (index != -1)
994 {
995 const GSUB_AlternateSet *as;
997 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
998 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
999 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
1000 return GSUB_E_NOGLYPH;
1001
1002 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
1003 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
1004 TRACE(" 0x%x\n",glyphs[glyph_index]);
1005 return glyph_index + write_dir;
1006 }
1007 }
1008 return GSUB_E_NOGLYPH;
1009}
1010
1011static INT GSUB_apply_LigatureSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1012{
1013 int j;
1014
1015 TRACE("Ligature Substitution Subtable\n");
1016 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1017 {
1018 const GSUB_LigatureSubstFormat1 *lsf1;
1019 int offset,index;
1020
1021 lsf1 = (const GSUB_LigatureSubstFormat1*)GSUB_get_subtable(look, j);
1022 offset = GET_BE_WORD(lsf1->Coverage);
1023 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
1024 TRACE(" Coverage index %i\n",index);
1025 if (index != -1)
1026 {
1027 const GSUB_LigatureSet *ls;
1028 int k, count;
1029
1031 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
1032 count = GET_BE_WORD(ls->LigatureCount);
1033 TRACE(" LigatureSet has %i members\n",count);
1034 for (k = 0; k < count; k++)
1035 {
1036 const GSUB_Ligature *lig;
1037 int CompCount,l,CompIndex;
1038
1039 offset = GET_BE_WORD(ls->Ligature[k]);
1040 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
1041 CompCount = GET_BE_WORD(lig->CompCount) - 1;
1042 CompIndex = glyph_index+write_dir;
1043 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
1044 {
1045 int CompGlyph;
1046 CompGlyph = GET_BE_WORD(lig->Component[l]);
1047 if (CompGlyph != glyphs[CompIndex])
1048 break;
1049 CompIndex += write_dir;
1050 }
1051 if (l == CompCount)
1052 {
1053 int replaceIdx = glyph_index;
1054 if (write_dir < 0)
1055 replaceIdx = glyph_index - CompCount;
1056
1057 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
1058 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
1059 TRACE("0x%x\n",glyphs[replaceIdx]);
1060 if (CompCount > 0)
1061 {
1062 unsigned int j = replaceIdx + 1;
1063 memmove(&glyphs[j], &glyphs[j + CompCount], (*glyph_count - j) * sizeof(*glyphs));
1064 *glyph_count = *glyph_count - CompCount;
1065 }
1066 return replaceIdx + write_dir;
1067 }
1068 }
1069 }
1070 }
1071 return GSUB_E_NOGLYPH;
1072}
1073
1074static INT GSUB_apply_ContextSubst(const OT_LookupList* lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1075{
1076 int j;
1077 TRACE("Context Substitution Subtable\n");
1078 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1079 {
1080 const GSUB_ContextSubstFormat1 *csf1;
1081
1082 csf1 = (const GSUB_ContextSubstFormat1*)GSUB_get_subtable(look, j);
1083 if (GET_BE_WORD(csf1->SubstFormat) == 1)
1084 {
1085 int offset, index;
1086 TRACE("Context Substitution Subtable: Class 1\n");
1087 offset = GET_BE_WORD(csf1->Coverage);
1088 index = GSUB_is_glyph_covered((const BYTE*)csf1+offset, glyphs[glyph_index]);
1089 TRACE(" Coverage index %i\n",index);
1090 if (index != -1)
1091 {
1092 int k, count;
1093 const GSUB_SubRuleSet *srs;
1095 srs = (const GSUB_SubRuleSet*)((const BYTE*)csf1+offset);
1097 TRACE(" SubRuleSet has %i members\n",count);
1098 for (k = 0; k < count; k++)
1099 {
1100 const GSUB_SubRule_1 *sr;
1101 const GSUB_SubRule_2 *sr_2;
1102 unsigned int g;
1103 int g_count, l;
1104 int newIndex = glyph_index;
1105
1106 offset = GET_BE_WORD(srs->SubRule[k]);
1107 sr = (const GSUB_SubRule_1*)((const BYTE*)srs+offset);
1108 g_count = GET_BE_WORD(sr->GlyphCount);
1109 TRACE(" SubRule has %i glyphs\n",g_count);
1110
1111 g = glyph_index + write_dir * (g_count - 1);
1112 if (g >= *glyph_count)
1113 continue;
1114
1115 for (l = 0; l < g_count-1; l++)
1116 if (glyphs[glyph_index + (write_dir * (l+1))] != GET_BE_WORD(sr->Input[l])) break;
1117
1118 if (l < g_count-1)
1119 {
1120 TRACE(" Rule does not match\n");
1121 continue;
1122 }
1123
1124 TRACE(" Rule matches\n");
1125 sr_2 = (const GSUB_SubRule_2 *)&sr->Input[g_count - 1];
1126
1127 for (l = 0; l < GET_BE_WORD(sr->SubstCount); l++)
1128 {
1129 unsigned int lookup_index = GET_BE_WORD(sr_2->SubstLookupRecord[l].LookupListIndex);
1130 unsigned int sequence_index = GET_BE_WORD(sr_2->SubstLookupRecord[l].SequenceIndex);
1131
1132 g = glyph_index + write_dir * sequence_index;
1133 if (g >= *glyph_count)
1134 {
1135 WARN("Invalid sequence index %u (glyph index %u, write dir %d).\n",
1136 sequence_index, glyph_index, write_dir);
1137 continue;
1138 }
1139
1140 TRACE(" SUBST: %u -> %u %u.\n", l, sequence_index, lookup_index);
1141 newIndex = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count);
1142 if (newIndex == GSUB_E_NOGLYPH)
1143 {
1144 ERR(" Chain failed to generate a glyph\n");
1145 continue;
1146 }
1147 }
1148 return newIndex;
1149 }
1150 }
1151 }
1152 else if (GET_BE_WORD(csf1->SubstFormat) == 2)
1153 {
1154 const GSUB_ContextSubstFormat2 *csf2;
1155 const void *glyph_class_table;
1156 int offset, index;
1157
1158 csf2 = (const GSUB_ContextSubstFormat2*)csf1;
1159 TRACE("Context Substitution Subtable: Class 2\n");
1160 offset = GET_BE_WORD(csf2->Coverage);
1161 index = GSUB_is_glyph_covered((const BYTE*)csf2+offset, glyphs[glyph_index]);
1162 TRACE(" Coverage index %i\n",index);
1163 if (index != -1)
1164 {
1165 int k, count, class;
1166 const GSUB_SubClassSet *scs;
1167
1168 offset = GET_BE_WORD(csf2->ClassDef);
1169 glyph_class_table = (const BYTE *)csf2 + offset;
1170
1171 class = OT_get_glyph_class(glyph_class_table,glyphs[glyph_index]);
1172
1173 offset = GET_BE_WORD(csf2->SubClassSet[class]);
1174 if (offset == 0)
1175 {
1176 TRACE(" No class rule table for class %i\n",class);
1177 continue;
1178 }
1179 scs = (const GSUB_SubClassSet*)((const BYTE*)csf2+offset);
1181 TRACE(" SubClassSet has %i members\n",count);
1182 for (k = 0; k < count; k++)
1183 {
1184 const GSUB_SubClassRule_1 *sr;
1185 const GSUB_SubClassRule_2 *sr_2;
1186 unsigned int g;
1187 int g_count, l;
1188 int newIndex = glyph_index;
1189
1191 sr = (const GSUB_SubClassRule_1*)((const BYTE*)scs+offset);
1192 g_count = GET_BE_WORD(sr->GlyphCount);
1193 TRACE(" SubClassRule has %i glyphs classes\n",g_count);
1194
1195 g = glyph_index + write_dir * (g_count - 1);
1196 if (g >= *glyph_count)
1197 continue;
1198
1199 for (l = 0; l < g_count-1; l++)
1200 {
1201 int g_class = OT_get_glyph_class(glyph_class_table, glyphs[glyph_index + (write_dir * (l+1))]);
1202 if (g_class != GET_BE_WORD(sr->Class[l])) break;
1203 }
1204
1205 if (l < g_count-1)
1206 {
1207 TRACE(" Rule does not match\n");
1208 continue;
1209 }
1210
1211 TRACE(" Rule matches\n");
1212 sr_2 = (const GSUB_SubClassRule_2 *)&sr->Class[g_count - 1];
1213
1214 for (l = 0; l < GET_BE_WORD(sr->SubstCount); l++)
1215 {
1216 unsigned int lookup_index = GET_BE_WORD(sr_2->SubstLookupRecord[l].LookupListIndex);
1217 unsigned int sequence_index = GET_BE_WORD(sr_2->SubstLookupRecord[l].SequenceIndex);
1218
1219 g = glyph_index + write_dir * sequence_index;
1220 if (g >= *glyph_count)
1221 {
1222 WARN("Invalid sequence index %u (glyph index %u, write dir %d).\n",
1223 sequence_index, glyph_index, write_dir);
1224 continue;
1225 }
1226
1227 TRACE(" SUBST: %u -> %u %u.\n", l, sequence_index, lookup_index);
1228 newIndex = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count);
1229 if (newIndex == GSUB_E_NOGLYPH)
1230 {
1231 ERR(" Chain failed to generate a glyph\n");
1232 continue;
1233 }
1234 }
1235 return newIndex;
1236 }
1237 }
1238 }
1239 else
1240 FIXME("Unhandled Context Substitution Format %i\n", GET_BE_WORD(csf1->SubstFormat));
1241 }
1242 return GSUB_E_NOGLYPH;
1243}
1244
1245static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1246{
1247 int j;
1248
1249 TRACE("Chaining Contextual Substitution Subtable\n");
1250 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1251 {
1252 const GSUB_ChainContextSubstFormat1 *ccsf1;
1253 int offset;
1254 int dirLookahead = write_dir;
1255 int dirBacktrack = -1 * write_dir;
1256
1257 ccsf1 = (const GSUB_ChainContextSubstFormat1*)GSUB_get_subtable(look, j);
1258 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
1259 {
1260 static int once;
1261 if (!once++)
1262 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
1263 continue;
1264 }
1265 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
1266 {
1267 WORD offset, count;
1268 const void *backtrack_class_table;
1269 const void *input_class_table;
1270 const void *lookahead_class_table;
1271 int i;
1272 WORD class;
1273
1275 const GSUB_ChainSubClassSet *csc;
1276
1277 TRACE(" subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
1278
1279 offset = GET_BE_WORD(ccsf2->Coverage);
1280
1281 if (GSUB_is_glyph_covered((const BYTE*)ccsf2+offset, glyphs[glyph_index]) == -1)
1282 {
1283 TRACE("Glyph not covered\n");
1284 continue;
1285 }
1287 backtrack_class_table = (const BYTE*)ccsf2+offset;
1289 input_class_table = (const BYTE*)ccsf2+offset;
1291 lookahead_class_table = (const BYTE*)ccsf2+offset;
1293
1294 class = OT_get_glyph_class(input_class_table, glyphs[glyph_index]);
1295 offset = GET_BE_WORD(ccsf2->ChainSubClassSet[class]);
1296
1297 if (offset == 0)
1298 {
1299 TRACE("No rules for class\n");
1300 continue;
1301 }
1302
1303 csc = (const GSUB_ChainSubClassSet*)((BYTE*)ccsf2+offset);
1305
1306 TRACE("%i rules to check\n",count);
1307
1308 for (i = 0; i < count; i++)
1309 {
1310 WORD backtrack_count, input_count, lookahead_count, substitute_count;
1311 int k;
1312 const GSUB_ChainSubClassRule_1 *backtrack;
1314 const GSUB_ChainSubClassRule_3 *lookahead;
1315 const GSUB_ChainSubClassRule_4 *substitute;
1316 int new_index = GSUB_E_NOGLYPH;
1317
1319 backtrack = (const GSUB_ChainSubClassRule_1 *)((BYTE *)csc + offset);
1320 backtrack_count = GET_BE_WORD(backtrack->BacktrackGlyphCount);
1321 k = glyph_index + dirBacktrack * backtrack_count;
1322 if (k < 0 || k >= *glyph_count)
1323 continue;
1324
1325 input = (const GSUB_ChainSubClassRule_2 *)&backtrack->Backtrack[backtrack_count];
1326 input_count = GET_BE_WORD(input->InputGlyphCount) - 1;
1327 k = glyph_index + write_dir * input_count;
1328 if (k < 0 || k >= *glyph_count)
1329 continue;
1330
1331 lookahead = (const GSUB_ChainSubClassRule_3 *)&input->Input[input_count];
1332 lookahead_count = GET_BE_WORD(lookahead->LookaheadGlyphCount);
1333 k = glyph_index + dirLookahead * (input_count + lookahead_count);
1334 if (k < 0 || k >= *glyph_count)
1335 continue;
1336
1337 substitute = (const GSUB_ChainSubClassRule_4 *)&lookahead->LookAhead[lookahead_count];
1338
1339 for (k = 0; k < backtrack_count; ++k)
1340 {
1341 WORD target_class = GET_BE_WORD(backtrack->Backtrack[k]);
1342 WORD glyph_class = OT_get_glyph_class(backtrack_class_table, glyphs[glyph_index + (dirBacktrack * (k+1))]);
1343 if (target_class != glyph_class)
1344 break;
1345 }
1346 if (k != backtrack_count)
1347 continue;
1348 TRACE("Matched Backtrack\n");
1349
1350 for (k = 0; k < input_count; ++k)
1351 {
1352 WORD target_class = GET_BE_WORD(input->Input[k]);
1353 WORD glyph_class = OT_get_glyph_class(input_class_table, glyphs[glyph_index + (write_dir * (k+1))]);
1354 if (target_class != glyph_class)
1355 break;
1356 }
1357 if (k != input_count)
1358 continue;
1359 TRACE("Matched IndexGlyphs\n");
1360
1361 for (k = 0; k < lookahead_count; ++k)
1362 {
1363 WORD target_class = GET_BE_WORD(lookahead->LookAhead[k]);
1364 WORD glyph_class = OT_get_glyph_class(lookahead_class_table,
1365 glyphs[glyph_index + (dirLookahead * (input_count + k + 1))]);
1366 if (target_class != glyph_class)
1367 break;
1368 }
1369 if (k != lookahead_count)
1370 continue;
1371 TRACE("Matched LookAhead\n");
1372
1373 substitute_count = GET_BE_WORD(substitute->SubstCount);
1374 for (k = 0; k < substitute_count; ++k)
1375 {
1376 unsigned int lookup_index = GET_BE_WORD(substitute->SubstLookupRecord[k].LookupListIndex);
1377 unsigned int sequence_index = GET_BE_WORD(substitute->SubstLookupRecord[k].SequenceIndex);
1378 unsigned int g = glyph_index + write_dir * sequence_index;
1379
1380 if (g >= *glyph_count)
1381 {
1382 WARN("Skipping invalid sequence index %u (glyph index %u, write dir %d).\n",
1383 sequence_index, glyph_index, write_dir);
1384 continue;
1385 }
1386
1387 TRACE("SUBST: %u -> %u %u.\n", k, sequence_index, lookup_index);
1388 new_index = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count);
1389 if (new_index == GSUB_E_NOGLYPH)
1390 ERR("Chain failed to generate a glyph.\n");
1391 }
1392 return new_index;
1393 }
1394 }
1395 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
1396 {
1397 WORD backtrack_count, input_count, lookahead_count, substitution_count;
1398 int k;
1399 const GSUB_ChainContextSubstFormat3_1 *backtrack;
1401 const GSUB_ChainContextSubstFormat3_3 *lookahead;
1402 const GSUB_ChainContextSubstFormat3_4 *substitute;
1403 int new_index = GSUB_E_NOGLYPH;
1404
1405 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
1406
1407 backtrack = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
1408 backtrack_count = GET_BE_WORD(backtrack->BacktrackGlyphCount);
1409 k = glyph_index + dirBacktrack * backtrack_count;
1410 if (k < 0 || k >= *glyph_count)
1411 continue;
1412
1413 input = (const GSUB_ChainContextSubstFormat3_2 *)&backtrack->Coverage[backtrack_count];
1414 input_count = GET_BE_WORD(input->InputGlyphCount);
1415 k = glyph_index + write_dir * (input_count - 1);
1416 if (k < 0 || k >= *glyph_count)
1417 continue;
1418
1419 lookahead = (const GSUB_ChainContextSubstFormat3_3 *)&input->Coverage[input_count];
1420 lookahead_count = GET_BE_WORD(lookahead->LookaheadGlyphCount);
1421 k = glyph_index + dirLookahead * (input_count + lookahead_count - 1);
1422 if (k < 0 || k >= *glyph_count)
1423 continue;
1424
1425 substitute = (const GSUB_ChainContextSubstFormat3_4 *)&lookahead->Coverage[lookahead_count];
1426
1427 for (k = 0; k < backtrack_count; ++k)
1428 {
1429 offset = GET_BE_WORD(backtrack->Coverage[k]);
1430 if (GSUB_is_glyph_covered((const BYTE *)ccsf1 + offset,
1431 glyphs[glyph_index + (dirBacktrack * (k + 1))]) == -1)
1432 break;
1433 }
1434 if (k != backtrack_count)
1435 continue;
1436 TRACE("Matched Backtrack\n");
1437
1438 for (k = 0; k < input_count; ++k)
1439 {
1440 offset = GET_BE_WORD(input->Coverage[k]);
1441 if (GSUB_is_glyph_covered((const BYTE *)ccsf1 + offset,
1442 glyphs[glyph_index + (write_dir * k)]) == -1)
1443 break;
1444 }
1445 if (k != input_count)
1446 continue;
1447 TRACE("Matched IndexGlyphs\n");
1448
1449 for (k = 0; k < lookahead_count; ++k)
1450 {
1451 offset = GET_BE_WORD(lookahead->Coverage[k]);
1452 if (GSUB_is_glyph_covered((const BYTE *)ccsf1 + offset,
1453 glyphs[glyph_index + (dirLookahead * (input_count + k))]) == -1)
1454 break;
1455 }
1456 if (k != lookahead_count)
1457 continue;
1458 TRACE("Matched LookAhead\n");
1459
1460 substitution_count = GET_BE_WORD(substitute->SubstCount);
1461 for (k = 0; k < substitution_count; ++k)
1462 {
1463 unsigned int lookup_index = GET_BE_WORD(substitute->SubstLookupRecord[k].LookupListIndex);
1464 unsigned int sequence_index = GET_BE_WORD(substitute->SubstLookupRecord[k].SequenceIndex);
1465 unsigned int g = glyph_index + write_dir * sequence_index;
1466
1467 if (g >= *glyph_count)
1468 {
1469 WARN("Skipping invalid sequence index %u (glyph index %u, write dir %d).\n",
1470 sequence_index, glyph_index, write_dir);
1471 continue;
1472 }
1473
1474 TRACE("SUBST: %u -> %u %u.\n", k, sequence_index, lookup_index);
1475 new_index = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count);
1476 if (new_index == GSUB_E_NOGLYPH)
1477 ERR("Chain failed to generate a glyph.\n");
1478 }
1479 return new_index;
1480 }
1481 }
1482 return GSUB_E_NOGLYPH;
1483}
1484
1485static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1486{
1487 int offset;
1489 const OT_LookupTable *look;
1490
1491 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1492 look = (const OT_LookupTable*)((const BYTE*)lookup + offset);
1493 type = GET_BE_WORD(look->LookupType);
1494 TRACE("type %#x, flag %#x, subtables %u.\n", type,
1496
1498 {
1499 if (GET_BE_WORD(look->SubTableCount))
1500 {
1501 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)look + GET_BE_WORD(look->SubTable[0]));
1502 if (GET_BE_WORD(ext->SubstFormat) == 1)
1503 {
1504 type = GET_BE_WORD(ext->ExtensionLookupType);
1505 TRACE("extension type %i\n",type);
1506 }
1507 else
1508 {
1509 FIXME("Unhandled Extension Substitution Format %i\n",GET_BE_WORD(ext->SubstFormat));
1510 }
1511 }
1512 else
1513 {
1514 WARN("lookup type is Extension Substitution but no extension subtable exists\n");
1515 }
1516 }
1517 switch(type)
1518 {
1519 case GSUB_LOOKUP_SINGLE:
1520 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1522 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1524 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1526 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1528 return GSUB_apply_ContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1530 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1532 FIXME("Extension Substitution types not valid here\n");
1533 break;
1534 default:
1535 FIXME("Unhandled GSUB lookup type %#x.\n", type);
1536 }
1537 return GSUB_E_NOGLYPH;
1538}
1539
1540int OpenType_apply_GSUB_lookup(const void *table, unsigned int lookup_index, WORD *glyphs,
1541 unsigned int glyph_index, int write_dir, int *glyph_count)
1542{
1543 const GSUB_Header *header = (const GSUB_Header *)table;
1544 const OT_LookupList *lookup = (const OT_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1545
1546 return GSUB_apply_lookup(lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count);
1547}
1548
1549/**********
1550 * GPOS
1551 **********/
1552static unsigned int GPOS_apply_lookup(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm,
1553 const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, const OT_LookupList *lookup,
1554 unsigned int lookup_index, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count,
1555 GOFFSET *goffset);
1556
1557static INT GPOS_get_device_table_value(const OT_DeviceTable *DeviceTable, WORD ppem)
1558{
1559 static const WORD mask[3] = {3,0xf,0xff};
1560 if (DeviceTable && ppem >= GET_BE_WORD(DeviceTable->StartSize) && ppem <= GET_BE_WORD(DeviceTable->EndSize))
1561 {
1562 WORD format = GET_BE_WORD(DeviceTable->DeltaFormat);
1563 int index = ppem - GET_BE_WORD(DeviceTable->StartSize);
1564 int value;
1565
1566 TRACE("device table, format %#x, index %i\n", format, index);
1567
1568 if (format < 1 || format > 3)
1569 {
1570 WARN("invalid delta format %#x\n", format);
1571 return 0;
1572 }
1573
1574 index = index << format;
1575 value = (DeviceTable->DeltaValue[index/sizeof(WORD)] << (index%sizeof(WORD)))&mask[format-1];
1576 TRACE("offset %i, value %i\n",index, value);
1577 if (value > mask[format-1]/2)
1578 value = -1 * ((mask[format-1]+1) - value);
1579 return value;
1580 }
1581 return 0;
1582}
1583
1584static void GPOS_get_anchor_values(const void *table, POINT *pt, WORD ppem)
1585{
1586 const GPOS_AnchorFormat1* anchor1 = (const GPOS_AnchorFormat1*)table;
1587
1588 switch (GET_BE_WORD(anchor1->AnchorFormat))
1589 {
1590 case 1:
1591 {
1592 TRACE("Anchor Format 1\n");
1593 pt->x = (short)GET_BE_WORD(anchor1->XCoordinate);
1594 pt->y = (short)GET_BE_WORD(anchor1->YCoordinate);
1595 break;
1596 }
1597 case 2:
1598 {
1599 const GPOS_AnchorFormat2* anchor2 = (const GPOS_AnchorFormat2*)table;
1600 TRACE("Anchor Format 2\n");
1601 pt->x = (short)GET_BE_WORD(anchor2->XCoordinate);
1602 pt->y = (short)GET_BE_WORD(anchor2->YCoordinate);
1603 break;
1604 }
1605 case 3:
1606 {
1607 int offset;
1608 const GPOS_AnchorFormat3* anchor3 = (const GPOS_AnchorFormat3*)table;
1609 TRACE("Anchor Format 3\n");
1610 pt->x = (short)GET_BE_WORD(anchor3->XCoordinate);
1611 pt->y = (short)GET_BE_WORD(anchor3->YCoordinate);
1612 offset = GET_BE_WORD(anchor3->XDeviceTable);
1613 TRACE("ppem %i\n",ppem);
1614 if (offset)
1615 {
1616 const OT_DeviceTable* DeviceTableX = NULL;
1617 DeviceTableX = (const OT_DeviceTable*)((const BYTE*)anchor3 + offset);
1618 pt->x += GPOS_get_device_table_value(DeviceTableX, ppem);
1619 }
1620 offset = GET_BE_WORD(anchor3->YDeviceTable);
1621 if (offset)
1622 {
1623 const OT_DeviceTable* DeviceTableY = NULL;
1624 DeviceTableY = (const OT_DeviceTable*)((const BYTE*)anchor3 + offset);
1625 pt->y += GPOS_get_device_table_value(DeviceTableY, ppem);
1626 }
1627 break;
1628 }
1629 default:
1630 ERR("Unknown Anchor Format %i\n",GET_BE_WORD(anchor1->AnchorFormat));
1631 pt->x = 0;
1632 pt->y = 0;
1633 }
1634}
1635
1637 int desX, int desY, double *devX, double *devY)
1638{
1640
1641 TRACE("emHeight %i lfWidth %i\n",emHeight, logfont->lfWidth);
1642 *devX = (desX * emHeight) / (double)otm->otmEMSquare;
1643 *devY = (desY * emHeight) / (double)otm->otmEMSquare;
1644 if (logfont->lfWidth)
1645 FIXME("Font with lfWidth set not handled properly.\n");
1646}
1647
1649{
1650 INT offset = 0;
1651 if (ValueFormat & 0x0001) { if (data) record->XPlacement = GET_BE_WORD(data[offset]); offset++; }
1652 if (ValueFormat & 0x0002) { if (data) record->YPlacement = GET_BE_WORD(data[offset]); offset++; }
1653 if (ValueFormat & 0x0004) { if (data) record->XAdvance = GET_BE_WORD(data[offset]); offset++; }
1654 if (ValueFormat & 0x0008) { if (data) record->YAdvance = GET_BE_WORD(data[offset]); offset++; }
1655 if (ValueFormat & 0x0010) { if (data) record->XPlaDevice = GET_BE_WORD(data[offset]); offset++; }
1656 if (ValueFormat & 0x0020) { if (data) record->YPlaDevice = GET_BE_WORD(data[offset]); offset++; }
1657 if (ValueFormat & 0x0040) { if (data) record->XAdvDevice = GET_BE_WORD(data[offset]); offset++; }
1658 if (ValueFormat & 0x0080) { if (data) record->YAdvDevice = GET_BE_WORD(data[offset]); offset++; }
1659 return offset;
1660}
1661
1663 WORD ValueFormat, unsigned int ppem, POINT *ptPlacement, POINT *ptAdvance)
1664{
1665 if (ValueFormat & 0x0001) ptPlacement->x += (short)ValueRecord->XPlacement;
1666 if (ValueFormat & 0x0002) ptPlacement->y += (short)ValueRecord->YPlacement;
1667 if (ValueFormat & 0x0004) ptAdvance->x += (short)ValueRecord->XAdvance;
1668 if (ValueFormat & 0x0008) ptAdvance->y += (short)ValueRecord->YAdvance;
1669 if (ValueFormat & 0x0010) ptPlacement->x += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->XPlaDevice), ppem);
1670 if (ValueFormat & 0x0020) ptPlacement->y += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->YPlaDevice), ppem);
1671 if (ValueFormat & 0x0040) ptAdvance->x += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->XAdvDevice), ppem);
1672 if (ValueFormat & 0x0080) ptAdvance->y += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->YAdvDevice), ppem);
1673 if (ValueFormat & 0xFF00) FIXME("Unhandled Value Format %x\n",ValueFormat&0xFF00);
1674}
1675
1676static const BYTE *GPOS_get_subtable(const OT_LookupTable *look, int index)
1677{
1678 int offset = GET_BE_WORD(look->SubTable[index]);
1679
1681 {
1682 const GPOS_ExtensionPosFormat1 *ext = (const GPOS_ExtensionPosFormat1 *)((const BYTE *)look + offset);
1683 if (GET_BE_WORD(ext->PosFormat) == 1)
1684 {
1685 offset += GET_BE_DWORD(ext->ExtensionOffset);
1686 }
1687 else
1688 {
1689 FIXME("Unhandled Extension Positioning Format %i\n",GET_BE_WORD(ext->PosFormat));
1690 }
1691 }
1692 return (const BYTE *)look + offset;
1693}
1694
1695static void GPOS_apply_SingleAdjustment(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis,
1696 const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem,
1697 POINT *adjust, POINT *advance)
1698{
1699 int j;
1700
1701 TRACE("Single Adjustment Positioning Subtable\n");
1702
1703 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1704 {
1706 WORD offset;
1707 if (GET_BE_WORD(spf1->PosFormat) == 1)
1708 {
1709 offset = GET_BE_WORD(spf1->Coverage);
1710 if (GSUB_is_glyph_covered((const BYTE*)spf1+offset, glyphs[glyph_index]) != -1)
1711 {
1712 GPOS_ValueRecord ValueRecord = {0,0,0,0,0,0,0,0};
1713 WORD ValueFormat = GET_BE_WORD(spf1->ValueFormat);
1714 GPOS_get_value_record(ValueFormat, spf1->Value, &ValueRecord);
1715 GPOS_get_value_record_offsets((const BYTE *)spf1, &ValueRecord, ValueFormat, ppem, adjust, advance);
1716 TRACE("Glyph Adjusted by %i,%i\n",ValueRecord.XPlacement,ValueRecord.YPlacement);
1717 }
1718 }
1719 else if (GET_BE_WORD(spf1->PosFormat) == 2)
1720 {
1721 int index;
1722 const GPOS_SinglePosFormat2 *spf2;
1723 spf2 = (const GPOS_SinglePosFormat2*)spf1;
1724 offset = GET_BE_WORD(spf2->Coverage);
1725 index = GSUB_is_glyph_covered((const BYTE*)spf2+offset, glyphs[glyph_index]);
1726 if (index != -1)
1727 {
1728 int size;
1729 GPOS_ValueRecord ValueRecord = {0,0,0,0,0,0,0,0};
1730 WORD ValueFormat = GET_BE_WORD(spf2->ValueFormat);
1731 size = GPOS_get_value_record(ValueFormat, spf2->Value, &ValueRecord);
1732 if (index > 0)
1733 {
1734 offset = size * index;
1735 GPOS_get_value_record(ValueFormat, &spf2->Value[offset], &ValueRecord);
1736 }
1737 GPOS_get_value_record_offsets((const BYTE *)spf2, &ValueRecord, ValueFormat, ppem, adjust, advance);
1738 TRACE("Glyph Adjusted by %i,%i\n",ValueRecord.XPlacement,ValueRecord.YPlacement);
1739 }
1740 }
1741 else
1742 FIXME("Single Adjustment Positioning: Format %i Unhandled\n",GET_BE_WORD(spf1->PosFormat));
1743 }
1744}
1745
1746static void apply_pair_value( const void *pos_table, WORD val_fmt1, WORD val_fmt2, const WORD *pair,
1747 INT ppem, POINT *adjust, POINT *advance )
1748{
1749 GPOS_ValueRecord val_rec1 = {0,0,0,0,0,0,0,0};
1750 GPOS_ValueRecord val_rec2 = {0,0,0,0,0,0,0,0};
1751 INT size;
1752
1753 size = GPOS_get_value_record( val_fmt1, pair, &val_rec1 );
1754 GPOS_get_value_record( val_fmt2, pair + size, &val_rec2 );
1755
1756 if (val_fmt1)
1757 {
1758 GPOS_get_value_record_offsets( pos_table, &val_rec1, val_fmt1, ppem, adjust, advance );
1759 TRACE( "Glyph 1 resulting cumulative offset is %s design units\n", wine_dbgstr_point(&adjust[0]) );
1760 TRACE( "Glyph 1 resulting cumulative advance is %s design units\n", wine_dbgstr_point(&advance[0]) );
1761 }
1762 if (val_fmt2)
1763 {
1764 GPOS_get_value_record_offsets( pos_table, &val_rec2, val_fmt2, ppem, adjust + 1, advance + 1 );
1765 TRACE( "Glyph 2 resulting cumulative offset is %s design units\n", wine_dbgstr_point(&adjust[1]) );
1766 TRACE( "Glyph 2 resulting cumulative advance is %s design units\n", wine_dbgstr_point(&advance[1]) );
1767 }
1768}
1769
1770static int GPOS_apply_PairAdjustment(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis,
1771 const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem,
1772 POINT *adjust, POINT *advance)
1773{
1774 int j;
1775 int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
1776
1777 if (glyph_index + write_dir >= glyph_count)
1778 return 1;
1779
1780 TRACE("Pair Adjustment Positioning Subtable\n");
1781
1782 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1783 {
1784 const GPOS_PairPosFormat1 *ppf1 = (const GPOS_PairPosFormat1*)GPOS_get_subtable(look, j);
1785 WORD offset;
1786 if (GET_BE_WORD(ppf1->PosFormat) == 1)
1787 {
1788 int index;
1789 WORD ValueFormat1 = GET_BE_WORD(ppf1->ValueFormat1);
1790 WORD ValueFormat2 = GET_BE_WORD(ppf1->ValueFormat2);
1791 INT val_fmt1_size = GPOS_get_value_record( ValueFormat1, NULL, NULL );
1792 INT val_fmt2_size = GPOS_get_value_record( ValueFormat2, NULL, NULL );
1793 offset = GET_BE_WORD(ppf1->Coverage);
1794 index = GSUB_is_glyph_covered((const BYTE*)ppf1+offset, glyphs[glyph_index]);
1795 if (index != -1 && index < GET_BE_WORD(ppf1->PairSetCount))
1796 {
1797 int k;
1798 int pair_count;
1799 const GPOS_PairSet *ps;
1800 const GPOS_PairValueRecord *pair_val_rec;
1802 ps = (const GPOS_PairSet*)((const BYTE*)ppf1+offset);
1803 pair_count = GET_BE_WORD(ps->PairValueCount);
1804 pair_val_rec = ps->PairValueRecord;
1805 for (k = 0; k < pair_count; k++)
1806 {
1807 WORD second_glyph = GET_BE_WORD(pair_val_rec->SecondGlyph);
1808 if (glyphs[glyph_index+write_dir] == second_glyph)
1809 {
1810 int next = 1;
1811 TRACE("Format 1: Found Pair %x,%x\n",glyphs[glyph_index],glyphs[glyph_index+write_dir]);
1812 apply_pair_value(ppf1, ValueFormat1, ValueFormat2,
1813 pair_val_rec->Value1, ppem, adjust, advance);
1814 if (ValueFormat2) next++;
1815 return next;
1816 }
1817 pair_val_rec = (const GPOS_PairValueRecord *)(pair_val_rec->Value1 + val_fmt1_size + val_fmt2_size);
1818 }
1819 }
1820 }
1821 else if (GET_BE_WORD(ppf1->PosFormat) == 2)
1822 {
1823 const GPOS_PairPosFormat2 *ppf2 = (const GPOS_PairPosFormat2*)ppf1;
1824 int index;
1825 WORD ValueFormat1 = GET_BE_WORD( ppf2->ValueFormat1 );
1826 WORD ValueFormat2 = GET_BE_WORD( ppf2->ValueFormat2 );
1827 INT val_fmt1_size = GPOS_get_value_record( ValueFormat1, NULL, NULL );
1828 INT val_fmt2_size = GPOS_get_value_record( ValueFormat2, NULL, NULL );
1829 WORD class1_count = GET_BE_WORD( ppf2->Class1Count );
1830 WORD class2_count = GET_BE_WORD( ppf2->Class2Count );
1831
1832 offset = GET_BE_WORD( ppf2->Coverage );
1833 index = GSUB_is_glyph_covered( (const BYTE*)ppf2 + offset, glyphs[glyph_index] );
1834 if (index != -1)
1835 {
1836 WORD class1, class2;
1837 class1 = OT_get_glyph_class( (const BYTE *)ppf2 + GET_BE_WORD(ppf2->ClassDef1), glyphs[glyph_index] );
1838 class2 = OT_get_glyph_class( (const BYTE *)ppf2 + GET_BE_WORD(ppf2->ClassDef2), glyphs[glyph_index + write_dir] );
1839 if (class1 < class1_count && class2 < class2_count)
1840 {
1841 const WORD *pair_val = ppf2->Class1Record + (class1 * class2_count + class2) * (val_fmt1_size + val_fmt2_size);
1842 int next = 1;
1843
1844 TRACE( "Format 2: Found Pair %x,%x\n", glyphs[glyph_index], glyphs[glyph_index + write_dir] );
1845
1846 apply_pair_value(ppf2, ValueFormat1, ValueFormat2, pair_val, ppem, adjust, advance);
1847 if (ValueFormat2) next++;
1848 return next;
1849 }
1850 }
1851 }
1852 else
1853 FIXME("Pair Adjustment Positioning: Format %i Unhandled\n",GET_BE_WORD(ppf1->PosFormat));
1854 }
1855 return 1;
1856}
1857
1858static void GPOS_apply_CursiveAttachment(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis,
1859 const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
1860{
1861 int j;
1862 int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
1863
1864 if (glyph_index + write_dir >= glyph_count)
1865 return;
1866
1867 TRACE("Cursive Attachment Positioning Subtable\n");
1868
1869 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1870 {
1872 if (GET_BE_WORD(cpf1->PosFormat) == 1)
1873 {
1874 int index_exit, index_entry;
1875 WORD offset = GET_BE_WORD( cpf1->Coverage );
1876 index_exit = GSUB_is_glyph_covered((const BYTE*)cpf1+offset, glyphs[glyph_index]);
1877 if (index_exit != -1 && cpf1->EntryExitRecord[index_exit].ExitAnchor!= 0)
1878 {
1879 index_entry = GSUB_is_glyph_covered((const BYTE*)cpf1+offset, glyphs[glyph_index+write_dir]);
1880 if (index_entry != -1 && cpf1->EntryExitRecord[index_entry].EntryAnchor != 0)
1881 {
1882 POINT exit_pt, entry_pt;
1883 offset = GET_BE_WORD(cpf1->EntryExitRecord[index_exit].ExitAnchor);
1884 GPOS_get_anchor_values((const BYTE*)cpf1 + offset, &exit_pt, ppem);
1885 offset = GET_BE_WORD(cpf1->EntryExitRecord[index_entry].EntryAnchor);
1886 GPOS_get_anchor_values((const BYTE*)cpf1 + offset, &entry_pt, ppem);
1887 TRACE("Found linkage %x[%s] %x[%s]\n",glyphs[glyph_index], wine_dbgstr_point(&exit_pt), glyphs[glyph_index+write_dir], wine_dbgstr_point(&entry_pt));
1888 pt->x = entry_pt.x - exit_pt.x;
1889 pt->y = entry_pt.y - exit_pt.y;
1890 return;
1891 }
1892 }
1893 }
1894 else
1895 FIXME("Cursive Attachment Positioning: Format %i Unhandled\n",GET_BE_WORD(cpf1->PosFormat));
1896 }
1897 return;
1898}
1899
1900static int GPOS_apply_MarkToBase(const ScriptCache *script_cache, const OT_LookupTable *look,
1901 const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index,
1902 unsigned int glyph_count, unsigned int ppem, POINT *pt)
1903{
1904 int j;
1905 int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
1906 const void *glyph_class_table = NULL;
1907 int rc = -1;
1908
1909 if (script_cache->GDEF_Table)
1910 {
1911 const GDEF_Header *header = script_cache->GDEF_Table;
1912 WORD offset = GET_BE_WORD( header->GlyphClassDef );
1913 if (offset)
1914 glyph_class_table = (const BYTE *)script_cache->GDEF_Table + offset;
1915 }
1916
1917 TRACE("MarkToBase Attachment Positioning Subtable\n");
1918
1919 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1920 {
1922 if (GET_BE_WORD(mbpf1->PosFormat) == 1)
1923 {
1924 int offset = GET_BE_WORD(mbpf1->MarkCoverage);
1925 int mark_index;
1926 mark_index = GSUB_is_glyph_covered((const BYTE*)mbpf1+offset, glyphs[glyph_index]);
1927 if (mark_index != -1)
1928 {
1929 int base_index;
1930 int base_glyph = glyph_index - write_dir;
1931
1932 if (glyph_class_table)
1933 {
1934 while (OT_get_glyph_class(glyph_class_table, glyphs[base_glyph]) == MarkGlyph && base_glyph > 0 && base_glyph < glyph_count)
1935 base_glyph -= write_dir;
1936 }
1937
1939 base_index = GSUB_is_glyph_covered((const BYTE*)mbpf1+offset, glyphs[base_glyph]);
1940 if (base_index != -1)
1941 {
1942 const GPOS_MarkArray *ma;
1943 const GPOS_MarkRecord *mr;
1944 const GPOS_BaseArray *ba;
1945 const GPOS_BaseRecord *br;
1946 int mark_class;
1947 int class_count = GET_BE_WORD(mbpf1->ClassCount);
1948 int baserecord_size;
1949 POINT base_pt;
1950 POINT mark_pt;
1951 TRACE("Mark %x(%i) and base %x(%i)\n",glyphs[glyph_index], mark_index, glyphs[base_glyph], base_index);
1952 offset = GET_BE_WORD(mbpf1->MarkArray);
1953 ma = (const GPOS_MarkArray*)((const BYTE*)mbpf1 + offset);
1954 if (mark_index > GET_BE_WORD(ma->MarkCount))
1955 {
1956 ERR("Mark index exceeded mark count\n");
1957 return -1;
1958 }
1959 mr = &ma->MarkRecord[mark_index];
1960 mark_class = GET_BE_WORD(mr->Class);
1961 TRACE("Mark Class %i total classes %i\n",mark_class,class_count);
1962 offset = GET_BE_WORD(mbpf1->BaseArray);
1963 ba = (const GPOS_BaseArray*)((const BYTE*)mbpf1 + offset);
1964 baserecord_size = class_count * sizeof(WORD);
1965 br = (const GPOS_BaseRecord*)((const BYTE*)ba + sizeof(WORD) + (baserecord_size * base_index));
1966 offset = GET_BE_WORD(br->BaseAnchor[mark_class]);
1967 GPOS_get_anchor_values((const BYTE*)ba + offset, &base_pt, ppem);
1969 GPOS_get_anchor_values((const BYTE*)ma + offset, &mark_pt, ppem);
1970 TRACE("Offset on base is %s design units\n",wine_dbgstr_point(&base_pt));
1971 TRACE("Offset on mark is %s design units\n",wine_dbgstr_point(&mark_pt));
1972 pt->x += base_pt.x - mark_pt.x;
1973 pt->y += base_pt.y - mark_pt.y;
1974 TRACE("Resulting cumulative offset is %s design units\n",wine_dbgstr_point(pt));
1975 rc = base_glyph;
1976 }
1977 }
1978 }
1979 else
1980 FIXME("Unhandled Mark To Base Format %i\n",GET_BE_WORD(mbpf1->PosFormat));
1981 }
1982 return rc;
1983}
1984
1985static void GPOS_apply_MarkToLigature(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis,
1986 const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
1987{
1988 int j;
1989 int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
1990
1991 TRACE("MarkToLigature Attachment Positioning Subtable\n");
1992
1993 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1994 {
1996 if (GET_BE_WORD(mlpf1->PosFormat) == 1)
1997 {
1998 int offset = GET_BE_WORD(mlpf1->MarkCoverage);
1999 int mark_index;
2000 mark_index = GSUB_is_glyph_covered((const BYTE*)mlpf1+offset, glyphs[glyph_index]);
2001 if (mark_index != -1)
2002 {
2003 int ligature_index;
2005 ligature_index = GSUB_is_glyph_covered((const BYTE*)mlpf1+offset, glyphs[glyph_index - write_dir]);
2006 if (ligature_index != -1)
2007 {
2008 const GPOS_MarkArray *ma;
2009 const GPOS_MarkRecord *mr;
2010
2011 const GPOS_LigatureArray *la;
2012 const GPOS_LigatureAttach *lt;
2013 int mark_class;
2014 int class_count = GET_BE_WORD(mlpf1->ClassCount);
2015 int component_count;
2016 int component_size;
2017 int i;
2018 POINT ligature_pt;
2019 POINT mark_pt;
2020
2021 TRACE("Mark %x(%i) and ligature %x(%i)\n",glyphs[glyph_index], mark_index, glyphs[glyph_index - write_dir], ligature_index);
2022 offset = GET_BE_WORD(mlpf1->MarkArray);
2023 ma = (const GPOS_MarkArray*)((const BYTE*)mlpf1 + offset);
2024 if (mark_index > GET_BE_WORD(ma->MarkCount))
2025 {
2026 ERR("Mark index exceeded mark count\n");
2027 return;
2028 }
2029 mr = &ma->MarkRecord[mark_index];
2030 mark_class = GET_BE_WORD(mr->Class);
2031 TRACE("Mark Class %i total classes %i\n",mark_class,class_count);
2033 la = (const GPOS_LigatureArray*)((const BYTE*)mlpf1 + offset);
2034 if (ligature_index > GET_BE_WORD(la->LigatureCount))
2035 {
2036 ERR("Ligature index exceeded ligature count\n");
2037 return;
2038 }
2039 offset = GET_BE_WORD(la->LigatureAttach[ligature_index]);
2040 lt = (const GPOS_LigatureAttach*)((const BYTE*)la + offset);
2041
2043 component_size = class_count * sizeof(WORD);
2044 offset = 0;
2045 for (i = 0; i < component_count && !offset; i++)
2046 {
2047 int k;
2048 const GPOS_ComponentRecord *cr = (const GPOS_ComponentRecord*)((const BYTE*)lt->ComponentRecord + (component_size * i));
2049 for (k = 0; k < class_count && !offset; k++)
2051 cr = (const GPOS_ComponentRecord*)((const BYTE*)cr + component_size);
2052 }
2053 if (!offset)
2054 {
2055 ERR("Failed to find available ligature connection point\n");
2056 return;
2057 }
2058
2059 GPOS_get_anchor_values((const BYTE*)lt + offset, &ligature_pt, ppem);
2061 GPOS_get_anchor_values((const BYTE*)ma + offset, &mark_pt, ppem);
2062 TRACE("Offset on ligature is %s design units\n",wine_dbgstr_point(&ligature_pt));
2063 TRACE("Offset on mark is %s design units\n",wine_dbgstr_point(&mark_pt));
2064 pt->x += ligature_pt.x - mark_pt.x;
2065 pt->y += ligature_pt.y - mark_pt.y;
2066 TRACE("Resulting cumulative offset is %s design units\n",wine_dbgstr_point(pt));
2067 }
2068 }
2069 }
2070 else
2071 FIXME("Unhandled Mark To Ligature Format %i\n",GET_BE_WORD(mlpf1->PosFormat));
2072 }
2073}
2074
2075static BOOL GPOS_apply_MarkToMark(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis,
2076 const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
2077{
2078 int j;
2079 BOOL rc = FALSE;
2080 int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
2081
2082 TRACE("MarkToMark Attachment Positioning Subtable\n");
2083
2084 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2085 {
2087 if (GET_BE_WORD(mmpf1->PosFormat) == 1)
2088 {
2089 int offset = GET_BE_WORD(mmpf1->Mark1Coverage);
2090 int mark_index;
2091 mark_index = GSUB_is_glyph_covered((const BYTE*)mmpf1+offset, glyphs[glyph_index]);
2092 if (mark_index != -1)
2093 {
2094 int mark2_index;
2096 mark2_index = GSUB_is_glyph_covered((const BYTE*)mmpf1+offset, glyphs[glyph_index - write_dir]);
2097 if (mark2_index != -1)
2098 {
2099 const GPOS_MarkArray *ma;
2100 const GPOS_MarkRecord *mr;
2101 const GPOS_Mark2Array *m2a;
2102 const GPOS_Mark2Record *m2r;
2103 int mark_class;
2104 int class_count = GET_BE_WORD(mmpf1->ClassCount);
2105 int mark2record_size;
2106 POINT mark2_pt;
2107 POINT mark_pt;
2108 TRACE("Mark %x(%i) and Mark2 %x(%i)\n",glyphs[glyph_index], mark_index, glyphs[glyph_index - write_dir], mark2_index);
2109 offset = GET_BE_WORD(mmpf1->Mark1Array);
2110 ma = (const GPOS_MarkArray*)((const BYTE*)mmpf1 + offset);
2111 if (mark_index > GET_BE_WORD(ma->MarkCount))
2112 {
2113 ERR("Mark index exceeded mark count\n");
2114 return FALSE;
2115 }
2116 mr = &ma->MarkRecord[mark_index];
2117 mark_class = GET_BE_WORD(mr->Class);
2118 TRACE("Mark Class %i total classes %i\n",mark_class,class_count);
2119 offset = GET_BE_WORD(mmpf1->Mark2Array);
2120 m2a = (const GPOS_Mark2Array*)((const BYTE*)mmpf1 + offset);
2121 mark2record_size = class_count * sizeof(WORD);
2122 m2r = (const GPOS_Mark2Record*)((const BYTE*)m2a + sizeof(WORD) + (mark2record_size * mark2_index));
2123 offset = GET_BE_WORD(m2r->Mark2Anchor[mark_class]);
2124 GPOS_get_anchor_values((const BYTE*)m2a + offset, &mark2_pt, ppem);
2126 GPOS_get_anchor_values((const BYTE*)ma + offset, &mark_pt, ppem);
2127 TRACE("Offset on mark2 is %s design units\n",wine_dbgstr_point(&mark2_pt));
2128 TRACE("Offset on mark is %s design units\n",wine_dbgstr_point(&mark_pt));
2129 pt->x += mark2_pt.x - mark_pt.x;
2130 pt->y += mark2_pt.y - mark_pt.y;
2131 TRACE("Resulting cumulative offset is %s design units\n",wine_dbgstr_point(pt));
2132 rc = TRUE;
2133 }
2134 }
2135 }
2136 else
2137 FIXME("Unhandled Mark To Mark Format %i\n",GET_BE_WORD(mmpf1->PosFormat));
2138 }
2139 return rc;
2140}
2141
2142static unsigned int GPOS_apply_ContextPos(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm,
2143 const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, const OT_LookupList *lookup,
2144 const OT_LookupTable *look, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count,
2145 GOFFSET *goffset)
2146{
2147 int j;
2148 int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
2149
2150 TRACE("Contextual Positioning Subtable\n");
2151
2152 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2153 {
2155
2156 if (GET_BE_WORD(cpf2->PosFormat) == 1)
2157 {
2158 static int once;
2159 if (!once++)
2160 FIXME(" TODO: subtype 1\n");
2161 continue;
2162 }
2163 else if (GET_BE_WORD(cpf2->PosFormat) == 2)
2164 {
2166 int index;
2167
2168 TRACE("Contextual Positioning Subtable: Format 2\n");
2169
2170 index = GSUB_is_glyph_covered((const BYTE*)cpf2+offset, glyphs[glyph_index]);
2171 TRACE("Coverage index %i\n",index);
2172 if (index != -1)
2173 {
2174 int k, count, class;
2175 const GPOS_PosClassSet *pcs;
2176 const void *glyph_class_table = NULL;
2177
2178 offset = GET_BE_WORD(cpf2->ClassDef);
2179 glyph_class_table = (const BYTE *)cpf2 + offset;
2180
2181 class = OT_get_glyph_class(glyph_class_table,glyphs[glyph_index]);
2182
2183 offset = GET_BE_WORD(cpf2->PosClassSet[class]);
2184 if (offset == 0)
2185 {
2186 TRACE("No class rule table for class %i\n",class);
2187 continue;
2188 }
2189 pcs = (const GPOS_PosClassSet*)((const BYTE*)cpf2+offset);
2191 TRACE("PosClassSet has %i members\n",count);
2192 for (k = 0; k < count; k++)
2193 {
2194 const GPOS_PosClassRule_1 *pr;
2195 const GPOS_PosClassRule_2 *pr_2;
2196 unsigned int g;
2197 int g_count, l;
2198
2200 pr = (const GPOS_PosClassRule_1*)((const BYTE*)pcs+offset);
2201 g_count = GET_BE_WORD(pr->GlyphCount);
2202 TRACE("PosClassRule has %i glyphs classes\n",g_count);
2203
2204 g = glyph_index + write_dir * (g_count - 1);
2205 if (g >= glyph_count)
2206 continue;
2207
2208 for (l = 0; l < g_count-1; l++)
2209 {
2210 int g_class = OT_get_glyph_class(glyph_class_table, glyphs[glyph_index + (write_dir * (l+1))]);
2211 if (g_class != GET_BE_WORD(pr->Class[l])) break;
2212 }
2213
2214 if (l < g_count-1)
2215 {
2216 TRACE("Rule does not match\n");
2217 continue;
2218 }
2219
2220 TRACE("Rule matches\n");
2221 pr_2 = (const GPOS_PosClassRule_2 *)&pr->Class[g_count - 1];
2222
2223 for (l = 0; l < GET_BE_WORD(pr->PosCount); l++)
2224 {
2225 unsigned int lookup_index = GET_BE_WORD(pr_2->PosLookupRecord[l].LookupListIndex);
2226 unsigned int sequence_index = GET_BE_WORD(pr_2->PosLookupRecord[l].SequenceIndex);
2227
2228 g = glyph_index + write_dir * sequence_index;
2229 if (g >= glyph_count)
2230 {
2231 WARN("Invalid sequence index %u (glyph index %u, write dir %d).\n",
2232 sequence_index, glyph_index, write_dir);
2233 continue;
2234 }
2235
2236 TRACE("Position: %u -> %u %u.\n", l, sequence_index, lookup_index);
2237
2238 GPOS_apply_lookup(script_cache, otm, logfont, analysis, advance,
2239 lookup, lookup_index, glyphs, g, glyph_count, goffset);
2240 }
2241 return 1;
2242 }
2243 }
2244
2245 TRACE("Not covered\n");
2246 continue;
2247 }
2248 else if (GET_BE_WORD(cpf2->PosFormat) == 3)
2249 {
2250 static int once;
2251 if (!once++)
2252 FIXME(" TODO: subtype 3\n");
2253 continue;
2254 }
2255 else
2256 FIXME("Unhandled Contextual Positioning Format %i\n",GET_BE_WORD(cpf2->PosFormat));
2257 }
2258 return 1;
2259}
2260
2261static unsigned int GPOS_apply_ChainContextPos(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm,
2262 const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, const OT_LookupList *lookup,
2263 const OT_LookupTable *look, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count,
2264 GOFFSET *goffset)
2265{
2266 int j;
2267 int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
2268
2269 TRACE("Chaining Contextual Positioning Subtable\n");
2270
2271 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2272 {
2273 int offset;
2275 int dirLookahead = write_dir;
2276 int dirBacktrack = -1 * write_dir;
2277
2278 if (GET_BE_WORD(backtrack->PosFormat) == 1)
2279 {
2280 static int once;
2281 if (!once++)
2282 FIXME(" TODO: subtype 1 (Simple Chaining Context Glyph Positioning)\n");
2283 continue;
2284 }
2285 else if (GET_BE_WORD(backtrack->PosFormat) == 2)
2286 {
2287 static int once;
2288 if (!once++)
2289 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Positioning)\n");
2290 continue;
2291 }
2292 else if (GET_BE_WORD(backtrack->PosFormat) == 3)
2293 {
2294 WORD backtrack_count, input_count, lookahead_count, positioning_count;
2295 int k;
2297 const GPOS_ChainContextPosFormat3_3 *lookahead;
2298 const GPOS_ChainContextPosFormat3_4 *positioning;
2299
2300 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Positioning)\n");
2301
2302 backtrack_count = GET_BE_WORD(backtrack->BacktrackGlyphCount);
2303 k = glyph_index + dirBacktrack * backtrack_count;
2304 if (k < 0 || k >= glyph_count)
2305 continue;
2306
2307 input = (const GPOS_ChainContextPosFormat3_2 *)&backtrack->Coverage[backtrack_count];
2308 input_count = GET_BE_WORD(input->InputGlyphCount);
2309 k = glyph_index + write_dir * (input_count - 1);
2310 if (k < 0 || k >= glyph_count)
2311 continue;
2312
2313 lookahead = (const GPOS_ChainContextPosFormat3_3 *)&input->Coverage[input_count];
2314 lookahead_count = GET_BE_WORD(lookahead->LookaheadGlyphCount);
2315 k = glyph_index + dirLookahead * (input_count + lookahead_count - 1);
2316 if (k < 0 || k >= glyph_count)
2317 continue;
2318
2319 positioning = (const GPOS_ChainContextPosFormat3_4 *)&lookahead->Coverage[lookahead_count];
2320
2321 for (k = 0; k < backtrack_count; ++k)
2322 {
2323 offset = GET_BE_WORD(backtrack->Coverage[k]);
2324 if (GSUB_is_glyph_covered((const BYTE *)backtrack + offset,
2325 glyphs[glyph_index + (dirBacktrack * (k + 1))]) == -1)
2326 break;
2327 }
2328 if (k != backtrack_count)
2329 continue;
2330 TRACE("Matched Backtrack\n");
2331
2332 for (k = 0; k < input_count; ++k)
2333 {
2334 offset = GET_BE_WORD(input->Coverage[k]);
2335 if (GSUB_is_glyph_covered((const BYTE *)backtrack + offset,
2336 glyphs[glyph_index + (write_dir * k)]) == -1)
2337 break;
2338 }
2339 if (k != input_count)
2340 continue;
2341 TRACE("Matched IndexGlyphs\n");
2342
2343 for (k = 0; k < lookahead_count; ++k)
2344 {
2345 offset = GET_BE_WORD(lookahead->Coverage[k]);
2346 if (GSUB_is_glyph_covered((const BYTE *)backtrack + offset,
2347 glyphs[glyph_index + (dirLookahead * (input_count + k))]) == -1)
2348 break;
2349 }
2350 if (k != lookahead_count)
2351 continue;
2352 TRACE("Matched LookAhead\n");
2353
2354 if (!(positioning_count = GET_BE_WORD(positioning->PosCount)))
2355 return 1;
2356
2357 for (k = 0; k < positioning_count; ++k)
2358 {
2359 unsigned int lookup_index = GET_BE_WORD(positioning->PosLookupRecord[k].LookupListIndex);
2360 unsigned int sequence_index = GET_BE_WORD(positioning->PosLookupRecord[k].SequenceIndex);
2361 unsigned int g = glyph_index + write_dir * sequence_index;
2362
2363 if (g >= glyph_count)
2364 {
2365 WARN("Skipping invalid sequence index %u (glyph index %u, write dir %d).\n",
2366 sequence_index, glyph_index, write_dir);
2367 continue;
2368 }
2369
2370 TRACE("Position: %u -> %u %u.\n", k, sequence_index, lookup_index);
2371 GPOS_apply_lookup(script_cache, otm, logfont, analysis, advance, lookup, lookup_index,
2372 glyphs, g, glyph_count, goffset);
2373 }
2374 return input_count + lookahead_count;
2375 }
2376 else
2377 FIXME("Unhandled Chaining Contextual Positioning Format %#x.\n", GET_BE_WORD(backtrack->PosFormat));
2378 }
2379 return 1;
2380}
2381
2382static unsigned int GPOS_apply_lookup(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *lpotm,
2383 const LOGFONTW *lplogfont, const SCRIPT_ANALYSIS *analysis, int *piAdvance, const OT_LookupList *lookup,
2384 unsigned int lookup_index, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count,
2385 GOFFSET *pGoffset)
2386{
2387 int offset;
2388 const OT_LookupTable *look;
2391
2392 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
2393 look = (const OT_LookupTable*)((const BYTE*)lookup + offset);
2394 type = GET_BE_WORD(look->LookupType);
2395 TRACE("type %#x, flag %#x, subtables %u.\n", type,
2397
2399 {
2400 if (GET_BE_WORD(look->SubTableCount))
2401 {
2402 const GPOS_ExtensionPosFormat1 *ext = (const GPOS_ExtensionPosFormat1 *)((const BYTE *)look + GET_BE_WORD(look->SubTable[0]));
2403 if (GET_BE_WORD(ext->PosFormat) == 1)
2404 {
2405 type = GET_BE_WORD(ext->ExtensionLookupType);
2406 TRACE("extension type %i\n",type);
2407 }
2408 else
2409 {
2410 FIXME("Unhandled Extension Positioning Format %i\n",GET_BE_WORD(ext->PosFormat));
2411 }
2412 }
2413 else
2414 {
2415 WARN("lookup type is Extension Positioning but no extension subtable exists\n");
2416 }
2417 }
2418 switch (type)
2419 {
2421 {
2422 double devX, devY;
2423 POINT adjust = {0,0};
2424 POINT advance = {0,0};
2425 GPOS_apply_SingleAdjustment(look, analysis, glyphs, glyph_index, glyph_count, ppem, &adjust, &advance);
2426 if (adjust.x || adjust.y)
2427 {
2428 GPOS_convert_design_units_to_device(lpotm, lplogfont, adjust.x, adjust.y, &devX, &devY);
2429 pGoffset[glyph_index].du += round(devX);
2430 pGoffset[glyph_index].dv += round(devY);
2431 }
2432 if (advance.x || advance.y)
2433 {
2434 GPOS_convert_design_units_to_device(lpotm, lplogfont, advance.x, advance.y, &devX, &devY);
2435 piAdvance[glyph_index] += round(devX);
2436 if (advance.y)
2437 FIXME("Unhandled adjustment to Y advancement\n");
2438 }
2439 break;
2440 }
2441
2443 {
2444 POINT advance[2]= {{0,0},{0,0}};
2445 POINT adjust[2]= {{0,0},{0,0}};
2446 double devX, devY;
2447 int index_offset;
2448 int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
2449 int offset_sign = (analysis->fRTL && analysis->fLogicalOrder) ? -1 : 1;
2450
2451 index_offset = GPOS_apply_PairAdjustment(look, analysis, glyphs,
2452 glyph_index, glyph_count, ppem, adjust, advance);
2453 if (adjust[0].x || adjust[0].y)
2454 {
2455 GPOS_convert_design_units_to_device(lpotm, lplogfont, adjust[0].x, adjust[0].y, &devX, &devY);
2456 pGoffset[glyph_index].du += round(devX) * offset_sign;
2457 pGoffset[glyph_index].dv += round(devY);
2458 }
2459 if (advance[0].x || advance[0].y)
2460 {
2461 GPOS_convert_design_units_to_device(lpotm, lplogfont, advance[0].x, advance[0].y, &devX, &devY);
2462 piAdvance[glyph_index] += round(devX);
2463 }
2464 if (adjust[1].x || adjust[1].y)
2465 {
2466 GPOS_convert_design_units_to_device(lpotm, lplogfont, adjust[1].x, adjust[1].y, &devX, &devY);
2467 pGoffset[glyph_index + write_dir].du += round(devX) * offset_sign;
2468 pGoffset[glyph_index + write_dir].dv += round(devY);
2469 }
2470 if (advance[1].x || advance[1].y)
2471 {
2472 GPOS_convert_design_units_to_device(lpotm, lplogfont, advance[1].x, advance[1].y, &devX, &devY);
2473 piAdvance[glyph_index + write_dir] += round(devX);
2474 }
2475 return index_offset;
2476 }
2477
2479 {
2480 POINT desU = {0,0};
2481 double devX, devY;
2482 int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
2483
2484 GPOS_apply_CursiveAttachment(look, analysis, glyphs, glyph_index, glyph_count, ppem, &desU);
2485 if (desU.x || desU.y)
2486 {
2487 GPOS_convert_design_units_to_device(lpotm, lplogfont, desU.x, desU.y, &devX, &devY);
2488 /* Windows does not appear to apply X offsets here */
2489 pGoffset[glyph_index].dv = round(devY) + pGoffset[glyph_index+write_dir].dv;
2490 }
2491 break;
2492 }
2493
2495 {
2496 double devX, devY;
2497 POINT desU = {0,0};
2498 int base_index = GPOS_apply_MarkToBase(script_cache, look, analysis,
2499 glyphs, glyph_index, glyph_count, ppem, &desU);
2500 if (base_index != -1)
2501 {
2502 GPOS_convert_design_units_to_device(lpotm, lplogfont, desU.x, desU.y, &devX, &devY);
2503 if (!analysis->fRTL) pGoffset[glyph_index].du = round(devX) - piAdvance[base_index];
2504 else
2505 {
2506 if (analysis->fLogicalOrder) devX *= -1;
2507 pGoffset[glyph_index].du = round(devX);
2508 }
2509 pGoffset[glyph_index].dv = round(devY);
2510 }
2511 break;
2512 }
2513
2515 {
2516 double devX, devY;
2517 POINT desU = {0,0};
2518 GPOS_apply_MarkToLigature(look, analysis, glyphs, glyph_index, glyph_count, ppem, &desU);
2519 if (desU.x || desU.y)
2520 {
2521 GPOS_convert_design_units_to_device(lpotm, lplogfont, desU.x, desU.y, &devX, &devY);
2522 pGoffset[glyph_index].du = (round(devX) - piAdvance[glyph_index-1]);
2523 pGoffset[glyph_index].dv = round(devY);
2524 }
2525 break;
2526 }
2527
2529 {
2530 double devX, devY;
2531 POINT desU = {0,0};
2532 int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
2533 if (GPOS_apply_MarkToMark(look, analysis, glyphs, glyph_index, glyph_count, ppem, &desU))
2534 {
2535 GPOS_convert_design_units_to_device(lpotm, lplogfont, desU.x, desU.y, &devX, &devY);
2536 if (analysis->fRTL && analysis->fLogicalOrder) devX *= -1;
2537 pGoffset[glyph_index].du = round(devX) + pGoffset[glyph_index - write_dir].du;
2538 pGoffset[glyph_index].dv = round(devY) + pGoffset[glyph_index - write_dir].dv;
2539 }
2540 break;
2541 }
2542
2544 return GPOS_apply_ContextPos(script_cache, lpotm, lplogfont, analysis, piAdvance,
2545 lookup, look, glyphs, glyph_index, glyph_count, pGoffset);
2546
2548 return GPOS_apply_ChainContextPos(script_cache, lpotm, lplogfont, analysis, piAdvance,
2549 lookup, look, glyphs, glyph_index, glyph_count, pGoffset);
2550
2551 default:
2552 FIXME("Unhandled GPOS lookup type %#x.\n", type);
2553 }
2554 return 1;
2555}
2556
2557unsigned int OpenType_apply_GPOS_lookup(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm,
2558 const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, unsigned int lookup_index,
2559 const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, GOFFSET *goffset)
2560{
2561 const GPOS_Header *header = (const GPOS_Header *)script_cache->GPOS_Table;
2562 const OT_LookupList *lookup = (const OT_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
2563
2564 return GPOS_apply_lookup(script_cache, otm, logfont, analysis, advance, lookup,
2565 lookup_index, glyphs, glyph_index, glyph_count, goffset);
2566}
2567
2569{
2571
2572 if (!usp10_array_reserve((void **)&script_cache->scripts, &script_cache->scripts_size,
2573 script_cache->script_count + 1, sizeof(*script_cache->scripts)))
2574 {
2575 ERR("Failed to grow scripts array.\n");
2576 return NULL;
2577 }
2578
2579 script = &script_cache->scripts[script_cache->script_count++];
2580 script->tag = tag;
2581
2582 return script;
2583}
2584
2586{
2587 size_t i;
2588
2589 for (i = 0; i < script_cache->script_count; ++i)
2590 {
2591 if (script_cache->scripts[i].tag == tag)
2592 return &script_cache->scripts[i];
2593 }
2594
2595 return NULL;
2596}
2597
2600{
2601 SIZE_T initial_count, count, i;
2604
2605 TRACE("script_cache %p, table %#x, list %p.\n", script_cache, table, list);
2606
2607 if (!(count = GET_BE_WORD(list->ScriptCount)))
2608 return;
2609
2610 TRACE("Adding %lu scripts.\n", count);
2611
2612 initial_count = script_cache->script_count;
2613 for (i = 0; i < count; ++i)
2614 {
2615 tag = MS_MAKE_TAG(list->ScriptRecord[i].ScriptTag[0],
2616 list->ScriptRecord[i].ScriptTag[1],
2617 list->ScriptRecord[i].ScriptTag[2],
2618 list->ScriptRecord[i].ScriptTag[3]);
2619
2620 if (!(initial_count && (script = usp10_script_cache_get_script(script_cache, tag)))
2621 && !(script = usp10_script_cache_add_script(script_cache, tag)))
2622 return;
2623
2624 script->table[table] = (const BYTE *)list + GET_BE_WORD(list->ScriptRecord[i].Script);
2625 }
2626}
2627
2628static void _initialize_script_cache(ScriptCache *script_cache)
2629{
2630 const GPOS_Header *gpos_header;
2631 const GSUB_Header *gsub_header;
2632
2633 if (script_cache->scripts_initialized)
2634 return;
2635
2636 if ((gsub_header = script_cache->GSUB_Table))
2638 (const OT_ScriptList *)((const BYTE *)gsub_header + GET_BE_WORD(gsub_header->ScriptList)));
2639
2640 if ((gpos_header = script_cache->GPOS_Table))
2642 (const OT_ScriptList *)((const BYTE *)gpos_header + GET_BE_WORD(gpos_header->ScriptList)));
2643
2644 script_cache->scripts_initialized = TRUE;
2645}
2646
2648{
2649 int i;
2650 const LoadedScript *script;
2651 HRESULT rc = S_OK;
2652
2654
2655 *pcTags = psc->script_count;
2656
2657 if (searchingFor)
2658 {
2659 if (!(script = usp10_script_cache_get_script(psc, searchingFor)))
2661
2662 *pScriptTags = script->tag;
2663 *pcTags = 1;
2664 return S_OK;
2665 }
2666
2667 if (cMaxTags < *pcTags)
2668 rc = E_OUTOFMEMORY;
2669
2670 cMaxTags = min(cMaxTags, psc->script_count);
2671 for (i = 0; i < cMaxTags; ++i)
2672 {
2673 pScriptTags[i] = psc->scripts[i].tag;
2674 }
2675 return rc;
2676}
2677
2679{
2680 LoadedLanguage *language;
2681
2682 if (!usp10_array_reserve((void **)&script->languages, &script->languages_size,
2683 script->language_count + 1, sizeof(*script->languages)))
2684 {
2685 ERR("Failed to grow languages array.\n");
2686 return NULL;
2687 }
2688
2689 language = &script->languages[script->language_count++];
2690 language->tag = tag;
2691
2692 return language;
2693}
2694
2696{
2697 size_t i;
2698
2699 for (i = 0; i < script->language_count; ++i)
2700 {
2701 if (script->languages[i].tag == tag)
2702 return &script->languages[i];
2703 }
2704
2705 return NULL;
2706}
2707
2710{
2711 SIZE_T initial_count, count, i;
2712 LoadedLanguage *language;
2714 DWORD offset;
2715
2716 TRACE("script %p, table %#x, list %p.\n", script, table, list);
2717
2718 if ((offset = GET_BE_WORD(list->DefaultLangSys)))
2719 {
2720 script->default_language.tag = MS_MAKE_TAG('d','f','l','t');
2721 script->default_language.table[table] = (const BYTE *)list + offset;
2722 TRACE("Default language %p.\n", script->default_language.table[table]);
2723 }
2724
2725 if (!(count = GET_BE_WORD(list->LangSysCount)))
2726 return;
2727
2728 TRACE("Adding %lu languages.\n", count);
2729
2730 initial_count = script->language_count;
2731 for (i = 0; i < count; ++i)
2732 {
2733 tag = MS_MAKE_TAG(list->LangSysRecord[i].LangSysTag[0],
2734 list->LangSysRecord[i].LangSysTag[1],
2735 list->LangSysRecord[i].LangSysTag[2],
2736 list->LangSysRecord[i].LangSysTag[3]);
2737
2738 if (!(initial_count && (language = usp10_script_get_language(script, tag)))
2739 && !(language = usp10_script_add_language(script, tag)))
2740 return;
2741
2742 language->table[table] = (const BYTE *)list + GET_BE_WORD(list->LangSysRecord[i].LangSys);
2743 }
2744}
2745
2747{
2748 const OT_Script *list;
2749
2750 if (script->languages_initialized)
2751 return;
2752
2753 if ((list = script->table[USP10_SCRIPT_TABLE_GSUB]))
2755 if ((list = script->table[USP10_SCRIPT_TABLE_GPOS]))
2757
2758 script->languages_initialized = TRUE;
2759}
2760
2762{
2763 int i;
2764 HRESULT rc = S_OK;
2766
2768 if (!(script = usp10_script_cache_get_script(psc, script_tag)))
2769 return E_INVALIDARG;
2770
2772
2773 if (!searchingFor && cMaxTags < script->language_count)
2774 rc = E_OUTOFMEMORY;
2775 else if (searchingFor)
2776 rc = E_INVALIDARG;
2777
2778 *pcTags = script->language_count;
2779
2780 for (i = 0; i < script->language_count; i++)
2781 {
2782 if (i < cMaxTags)
2783 pLanguageTags[i] = script->languages[i].tag;
2784
2785 if (searchingFor)
2786 {
2787 if (searchingFor == script->languages[i].tag)
2788 {
2789 pLanguageTags[0] = script->languages[i].tag;
2790 *pcTags = 1;
2791 rc = S_OK;
2792 break;
2793 }
2794 }
2795 }
2796
2797 if (script->default_language.table[USP10_LANGUAGE_TABLE_GSUB])
2798 {
2799 if (i < cMaxTags)
2800 pLanguageTags[i] = script->default_language.tag;
2801
2802 if (searchingFor && FAILED(rc))
2803 {
2804 pLanguageTags[0] = script->default_language.tag;
2805 }
2806 i++;
2807 *pcTags = (*pcTags) + 1;
2808 }
2809
2810 return rc;
2811}
2812
2813static void usp10_language_add_feature_list(LoadedLanguage *language, char table_type,
2814 const OT_LangSys *lang, const OT_FeatureList *feature_list)
2815{
2816 unsigned int count = GET_BE_WORD(lang->FeatureCount);
2817 unsigned int i, j;
2818
2819 TRACE("table_type %#x, %u features.\n", table_type, count);
2820
2821 if (!count || !usp10_array_reserve((void **)&language->features, &language->features_size,
2822 language->feature_count + count, sizeof(*language->features)))
2823 return;
2824
2825 for (i = 0; i < count; ++i)
2826 {
2827 const OT_FeatureRecord *record;
2828 LoadedFeature *loaded_feature;
2829 const OT_Feature *feature;
2830
2831 record = &feature_list->FeatureRecord[GET_BE_WORD(lang->FeatureIndex[i])];
2832 feature = (const OT_Feature *)((const BYTE *)feature_list + GET_BE_WORD(record->Feature));
2833
2834 loaded_feature = &language->features[language->feature_count + i];
2835 loaded_feature->tag = MS_MAKE_TAG(record->FeatureTag[0], record->FeatureTag[1],
2836 record->FeatureTag[2], record->FeatureTag[3]);
2837 loaded_feature->tableType = table_type;
2838 loaded_feature->feature = feature;
2839 loaded_feature->lookup_count = GET_BE_WORD(feature->LookupCount);
2840 loaded_feature->lookups = heap_calloc(loaded_feature->lookup_count, sizeof(*loaded_feature->lookups));
2841 for (j = 0; j < loaded_feature->lookup_count; ++j)
2842 loaded_feature->lookups[j] = GET_BE_WORD(feature->LookupListIndex[j]);
2843 }
2844 language->feature_count += count;
2845}
2846
2848{
2849 const GSUB_Header *gsub_header = psc->GSUB_Table;
2850 const GPOS_Header *gpos_header = psc->GPOS_Table;
2851 const OT_FeatureList *feature_list;
2852 const OT_LangSys *lang;
2853
2854 if (language->features_initialized)
2855 return;
2856
2857 if ((lang = language->table[USP10_LANGUAGE_TABLE_GSUB]))
2858 {
2859 feature_list = (const OT_FeatureList *)((const BYTE *)gsub_header + GET_BE_WORD(gsub_header->FeatureList));
2861 }
2862
2863 if ((lang = language->table[USP10_LANGUAGE_TABLE_GPOS]))
2864 {
2865 feature_list = (const OT_FeatureList *)((const BYTE *)gpos_header + GET_BE_WORD(gpos_header->FeatureList));
2867 }
2868
2869 language->features_initialized = TRUE;
2870}
2871
2873{
2874 int i;
2875 LoadedLanguage *language;
2877 HRESULT rc = S_OK;
2878
2880 if (!(script = usp10_script_cache_get_script(psc, script_tag)))
2881 {
2882 *pcTags = 0;
2883 if (!filtered)
2884 return S_OK;
2885 else
2886 return E_INVALIDARG;
2887 }
2888
2890
2891 language = &script->default_language;
2892 if (language->tag != language_tag || (!language->table[USP10_LANGUAGE_TABLE_GSUB]
2893 && !language->table[USP10_LANGUAGE_TABLE_GPOS]))
2894 language = usp10_script_get_language(script, language_tag);
2895
2896 if (!language)
2897 {
2898 *pcTags = 0;
2899 return S_OK;
2900 }
2901
2902 _initialize_feature_cache(psc, language);
2903
2904 if (tableType)
2905 {
2906 *pcTags = 0;
2907 for (i = 0; i < language->feature_count; i++)
2908 if (language->features[i].tableType == tableType)
2909 *pcTags = (*pcTags)+1;
2910 }
2911 else
2912 *pcTags = language->feature_count;
2913
2914 if (!searchingFor && cMaxTags < *pcTags)
2915 rc = E_OUTOFMEMORY;
2916 else if (searchingFor)
2917 rc = E_INVALIDARG;
2918
2919 for (i = 0; i < language->feature_count; i++)
2920 {
2921 if (i < cMaxTags)
2922 {
2923 if (!tableType || language->features[i].tableType == tableType)
2924 pFeatureTags[i] = language->features[i].tag;
2925 }
2926
2927 if (searchingFor)
2928 {
2929 if ((searchingFor == language->features[i].tag) &&
2930 (!tableType || language->features[i].tableType == tableType))
2931 {
2932 pFeatureTags[0] = language->features[i].tag;
2933 *pcTags = 1;
2934 if (feature)
2935 *feature = &language->features[i];
2936 rc = S_OK;
2937 break;
2938 }
2939 }
2940 }
2941 return rc;
2942}
static VOID Substitute(_Out_writes_bytes_(BufferSize) PWCHAR Buffer, _In_ ULONG BufferSize, _In_ PCWSTR Template, _In_ PCWSTR SystemDriveName, _In_ PCWSTR SystemRootName)
Definition: IoFilesystem.c:231
_STLP_MOVE_TO_STD_NAMESPACE void _STLP_CALL advance(_InputIterator &__i, _Distance __n)
#define __cdecl
Definition: accygwin.h:79
struct outqueuenode * head
Definition: adnsresfilter.c:66
static void * heap_alloc(size_t len)
Definition: appwiz.h:66
static const char * wine_dbgstr_point(const POINT *ppt)
Definition: atltest.h:138
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define index(s, c)
Definition: various.h:29
void ls(int argc, const char *argv[])
Definition: cmds.c:1136
#define FIXME(fmt,...)
Definition: debug.h:111
#define WARN(fmt,...)
Definition: debug.h:112
#define ERR(fmt,...)
Definition: debug.h:110
r l[0]
Definition: byte_order.h:168
Definition: list.h:37
unsigned int component_count
unsigned int component_size
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define TRACE_ON(x)
Definition: compat.h:75
static const WCHAR *const ext[]
Definition: module.c:53
#define MS_MAKE_TAG(ch0, ch1, ch2, ch3)
Definition: font.c:113
static void Lookup(RTF_Info *, char *)
Definition: reader.c:2228
BOOL usp10_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
Definition: usp10.c:730
int USP10_FindGlyphInLogClust(const WORD *pwLogClust, int cChars, WORD target)
Definition: usp10.c:1044
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:94
#define pt(x, y)
Definition: drawing.c:79
static ULONG lookup[16]
Definition: vga.c:48
struct nls_table * tables
Definition: nls_base.c:22
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
GLsizeiptr size
Definition: glext.h:5919
GLsizei GLuint * groups
Definition: glext.h:11113
GLuint index
Definition: glext.h:6031
GLenum GLint GLuint mask
Definition: glext.h:6028
GLdouble GLdouble GLdouble GLdouble top
Definition: glext.h:10859
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLbitfield flags
Definition: glext.h:7161
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLboolean GLuint group
Definition: glext.h:11120
GLboolean GLboolean g
Definition: glext.h:6204
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLenum GLenum GLenum input
Definition: glext.h:9031
GLintptr offset
Definition: glext.h:5920
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define S_OK
Definition: intsafe.h:52
#define FAILED(hr)
Definition: intsafe.h:51
ROSDATA LIGATURE2 Ligature[]
Definition: kbda1.c:341
#define a
Definition: ke_i.h:78
#define b
Definition: ke_i.h:79
if(dx< 0)
Definition: linetemp.h:194
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define for
Definition: utility.h:88
HDC hdc
Definition: main.c:9
static HDC
Definition: imagelist.c:92
static UINT UINT LPWORD glyphs
Definition: font.c:44
INTERNETFEATURELIST feature
Definition: misc.c:1719
static SCRIPT_CACHE SCRIPT_ANALYSIS OPENTYPE_TAG OPENTYPE_TAG int TEXTRANGE_PROPERTIES int const WCHAR int cChars
Definition: usp10.c:64
static SCRIPT_CACHE * psc
Definition: usp10.c:64
static SCRIPT_CACHE SCRIPT_ANALYSIS OPENTYPE_TAG OPENTYPE_TAG int OPENTYPE_TAG * pFeatureTags
Definition: usp10.c:68
static int int const SCRIPT_CONTROL const SCRIPT_STATE SCRIPT_ITEM ULONG * pScriptTags
Definition: usp10.c:62
static SCRIPT_CACHE SCRIPT_ANALYSIS OPENTYPE_TAG OPENTYPE_TAG int TEXTRANGE_PROPERTIES int const WCHAR int int WORD * pwLogClust
Definition: usp10.c:64
static SCRIPT_CACHE SCRIPT_ANALYSIS int cMaxTags
Definition: usp10.c:66
static SCRIPT_CACHE SCRIPT_ANALYSIS int OPENTYPE_TAG int * pcTags
Definition: usp10.c:66
#define min(a, b)
Definition: monoChain.cc:55
int k
Definition: mpi.c:3369
script
Definition: msipriv.h:383
static int GSUB_is_glyph_covered(const void *table, unsigned int glyph)
Definition: opentype.c:819
@ LigatureGlyph
Definition: opentype.c:105
@ ComponentGlyph
Definition: opentype.c:105
@ BaseGlyph
Definition: opentype.c:105
@ MarkGlyph
Definition: opentype.c:105
static void GPOS_apply_SingleAdjustment(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *adjust, POINT *advance)
Definition: opentype.c:1695
static INT GSUB_apply_ContextSubst(const OT_LookupList *lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:1074
static void apply_pair_value(const void *pos_table, WORD val_fmt1, WORD val_fmt2, const WORD *pair, INT ppem, POINT *adjust, POINT *advance)
Definition: opentype.c:1746
static void usp10_language_add_feature_list(LoadedLanguage *language, char table_type, const OT_LangSys *lang, const OT_FeatureList *feature_list)
Definition: opentype.c:2813
gpos_lookup_type
Definition: opentype.c:53
@ GPOS_LOOKUP_POSITION_CONTEXT_CHAINED
Definition: opentype.c:61
@ GPOS_LOOKUP_ATTACH_MARK_TO_LIGATURE
Definition: opentype.c:58
@ GPOS_LOOKUP_ADJUST_SINGLE
Definition: opentype.c:54
@ GPOS_LOOKUP_ADJUST_PAIR
Definition: opentype.c:55
@ GPOS_LOOKUP_ATTACH_MARK_TO_BASE
Definition: opentype.c:57
@ GPOS_LOOKUP_POSITION_EXTENSION
Definition: opentype.c:62
@ GPOS_LOOKUP_ATTACH_MARK_TO_MARK
Definition: opentype.c:59
@ GPOS_LOOKUP_ATTACH_CURSIVE
Definition: opentype.c:56
@ GPOS_LOOKUP_POSITION_CONTEXT
Definition: opentype.c:60
static int GPOS_apply_PairAdjustment(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *adjust, POINT *advance)
Definition: opentype.c:1770
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)
Definition: opentype.c:2872
static INT GSUB_apply_ChainContextSubst(const OT_LookupList *lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:1245
static void _initialize_script_cache(ScriptCache *script_cache)
Definition: opentype.c:2628
HRESULT OpenType_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags)
Definition: opentype.c:2761
static void _initialize_language_cache(LoadedScript *script)
Definition: opentype.c:2746
static LoadedLanguage * usp10_script_add_language(LoadedScript *script, OPENTYPE_TAG tag)
Definition: opentype.c:2678
static INT GPOS_get_value_record(WORD ValueFormat, const WORD data[], GPOS_ValueRecord *record)
Definition: opentype.c:1648
static unsigned int GPOS_apply_ChainContextPos(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm, const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, const OT_LookupList *lookup, const OT_LookupTable *look, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, GOFFSET *goffset)
Definition: opentype.c:2261
static void GPOS_apply_CursiveAttachment(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
Definition: opentype.c:1858
static INT GSUB_apply_LigatureSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:1011
static WORD OT_get_glyph_class(const void *table, WORD glyph)
Definition: opentype.c:714
static void usp10_script_add_language_list(LoadedScript *script, enum usp10_language_table table, const OT_Script *list)
Definition: opentype.c:2708
#define round(x)
Definition: opentype.c:47
static void usp10_script_cache_add_script_list(ScriptCache *script_cache, enum usp10_script_table table, const OT_ScriptList *list)
Definition: opentype.c:2598
static const BYTE * GSUB_get_subtable(const OT_LookupTable *look, int index)
Definition: opentype.c:863
static INT GSUB_apply_SingleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:882
gsub_lookup_type
Definition: opentype.c:66
@ GSUB_LOOKUP_CONTEXT_CHAINED_REVERSE
Definition: opentype.c:74
@ GSUB_LOOKUP_LIGATURE
Definition: opentype.c:70
@ GSUB_LOOKUP_SINGLE
Definition: opentype.c:67
@ GSUB_LOOKUP_MULTIPLE
Definition: opentype.c:68
@ GSUB_LOOKUP_EXTENSION
Definition: opentype.c:73
@ GSUB_LOOKUP_CONTEXT_CHAINED
Definition: opentype.c:72
@ GSUB_LOOKUP_CONTEXT
Definition: opentype.c:71
@ GSUB_LOOKUP_ALTERNATE
Definition: opentype.c:69
static int GPOS_apply_MarkToBase(const ScriptCache *script_cache, const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
Definition: opentype.c:1900
static LoadedScript * usp10_script_cache_get_script(ScriptCache *script_cache, OPENTYPE_TAG tag)
Definition: opentype.c:2585
static void GPOS_convert_design_units_to_device(const OUTLINETEXTMETRICW *otm, const LOGFONTW *logfont, int desX, int desY, double *devX, double *devY)
Definition: opentype.c:1636
static void GPOS_apply_MarkToLigature(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
Definition: opentype.c:1985
unsigned int OpenType_apply_GPOS_lookup(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm, const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, unsigned int lookup_index, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, GOFFSET *goffset)
Definition: opentype.c:2557
static void GPOS_get_anchor_values(const void *table, POINT *pt, WORD ppem)
Definition: opentype.c:1584
static unsigned int GPOS_apply_lookup(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm, const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, const OT_LookupList *lookup, unsigned int lookup_index, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, GOFFSET *goffset)
Definition: opentype.c:2382
#define CMAP_TAG
Definition: opentype.c:50
static INT GSUB_apply_lookup(const OT_LookupList *lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:1485
static BOOL GPOS_apply_MarkToMark(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
Definition: opentype.c:2075
static void _initialize_feature_cache(ScriptCache *psc, LoadedLanguage *language)
Definition: opentype.c:2847
void OpenType_GDEF_UpdateGlyphProps(ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD *pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
Definition: opentype.c:751
static void GPOS_get_value_record_offsets(const BYTE *head, GPOS_ValueRecord *ValueRecord, WORD ValueFormat, unsigned int ppem, POINT *ptPlacement, POINT *ptAdvance)
Definition: opentype.c:1662
static INT GSUB_apply_MultipleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:928
static VOID * load_CMAP_format12_table(HDC hdc, ScriptCache *psc)
Definition: opentype.c:627
DWORD OpenType_CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, WORD *glyph_index, DWORD flags)
Definition: opentype.c:673
static LoadedLanguage * usp10_script_get_language(LoadedScript *script, OPENTYPE_TAG tag)
Definition: opentype.c:2695
static INT GSUB_apply_AlternateSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:978
static LoadedScript * usp10_script_cache_add_script(ScriptCache *script_cache, OPENTYPE_TAG tag)
Definition: opentype.c:2568
static const BYTE * GPOS_get_subtable(const OT_LookupTable *look, int index)
Definition: opentype.c:1676
int OpenType_apply_GSUB_lookup(const void *table, unsigned int lookup_index, WORD *glyphs, unsigned int glyph_index, int write_dir, int *glyph_count)
Definition: opentype.c:1540
#define GET_BE_WORD(x)
Definition: opentype.c:43
#define GET_BE_DWORD(x)
Definition: opentype.c:44
HRESULT OpenType_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
Definition: opentype.c:2647
static unsigned int GPOS_apply_ContextPos(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm, const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, const OT_LookupList *lookup, const OT_LookupTable *look, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, GOFFSET *goffset)
Definition: opentype.c:2142
static int __cdecl compare_group(const void *a, const void *b)
Definition: opentype.c:661
static INT GPOS_get_device_table_value(const OT_DeviceTable *DeviceTable, WORD ppem)
Definition: opentype.c:1557
static unsigned __int64 next
Definition: rand_nt.c:6
#define list
Definition: rosglue.h:35
@ Input
Definition: arc.h:84
static void * heap_calloc(SIZE_T count, SIZE_T size)
Definition: heap.h:49
#define TRACE(s)
Definition: solgame.cpp:4
CMAP_EncodingRecord tables[1]
Definition: opentype.c:86
WORD numTables
Definition: opentype.c:85
WORD version
Definition: opentype.c:84
WORD MarkAttachClassDef
Definition: opentype.c:112
WORD LigCaretList
Definition: opentype.c:111
WORD AttachList
Definition: opentype.c:110
WORD GlyphClassDef
Definition: opentype.c:109
DWORD Version
Definition: opentype.c:108
WORD BaseCount
Definition: opentype.c:513
WORD BaseAnchor[1]
Definition: opentype.c:509
GPOS_PosLookupRecord PosLookupRecord[1]
Definition: opentype.c:614
WORD LigatureAnchor[1]
Definition: opentype.c:542
GPOS_EntryExitRecord EntryExitRecord[1]
Definition: opentype.c:496
WORD LookupList
Definition: opentype.c:398
WORD ScriptList
Definition: opentype.c:396
WORD FeatureList
Definition: opentype.c:397
DWORD version
Definition: opentype.c:395
WORD LigatureAttach[1]
Definition: opentype.c:538
GPOS_ComponentRecord ComponentRecord[1]
Definition: opentype.c:547
WORD Mark2Anchor[1]
Definition: opentype.c:560
GPOS_MarkRecord MarkRecord[1]
Definition: opentype.c:524
WORD MarkCount
Definition: opentype.c:523
WORD PairSetOffset[1]
Definition: opentype.c:461
WORD Class1Record[1]
Definition: opentype.c:473
WORD PairValueCount
Definition: opentype.c:483
GPOS_PairValueRecord PairValueRecord[1]
Definition: opentype.c:484
GPOS_PosLookupRecord PosLookupRecord[1]
Definition: opentype.c:593
WORD PosClassRuleCnt
Definition: opentype.c:582
WORD PosClassRule[1]
Definition: opentype.c:583
WORD Alternate[1]
Definition: opentype.c:383
GSUB_SubstLookupRecord SubstLookupRecord[1]
Definition: opentype.c:371
GSUB_SubstLookupRecord SubstLookupRecord[1]
Definition: opentype.c:350
WORD ChainSubClassRule[1]
Definition: opentype.c:330
WORD FeatureList
Definition: opentype.c:139
WORD LookupList
Definition: opentype.c:140
WORD ScriptList
Definition: opentype.c:138
DWORD version
Definition: opentype.c:137
WORD LigatureCount
Definition: opentype.c:250
WORD Component[1]
Definition: opentype.c:257
WORD CompCount
Definition: opentype.c:256
WORD LigGlyph
Definition: opentype.c:255
WORD Substitute[1]
Definition: opentype.c:239
WORD GlyphCount
Definition: opentype.c:238
GSUB_SubstLookupRecord SubstLookupRecord[1]
Definition: opentype.c:308
WORD SubClassRuleCnt
Definition: opentype.c:297
WORD SubClassRule[1]
Definition: opentype.c:298
WORD SubRule[1]
Definition: opentype.c:275
WORD SubRuleCount
Definition: opentype.c:274
WORD SubstCount
Definition: opentype.c:280
WORD Input[1]
Definition: opentype.c:281
WORD GlyphCount
Definition: opentype.c:279
GSUB_SubstLookupRecord SubstLookupRecord[1]
Definition: opentype.c:285
LONG lfWidth
Definition: dimm.idl:60
OPENTYPE_TAG tag
const void * feature
OPENTYPE_TAG tag
LoadedFeature * features
const void * table[USP10_LANGUAGE_TABLE_COUNT]
OPENTYPE_TAG tag
OT_ClassRangeRecord ClassRangeRecord[1]
Definition: opentype.c:131
WORD GlyphArray[1]
Definition: opentype.c:202
OT_RangeRecord RangeRecord[1]
Definition: opentype.c:214
WORD DeltaValue[1]
Definition: opentype.c:405
WORD DeltaFormat
Definition: opentype.c:404
WORD StartSize
Definition: opentype.c:402
WORD FeatureCount
Definition: opentype.c:177
OT_FeatureRecord FeatureRecord[1]
Definition: opentype.c:178
WORD FeatureParams
Definition: opentype.c:182
WORD LookupCount
Definition: opentype.c:183
WORD ReqFeatureIndex
Definition: opentype.c:166
WORD LookupOrder
Definition: opentype.c:165
WORD FeatureCount
Definition: opentype.c:167
WORD LookupCount
Definition: opentype.c:188
WORD SubTable[1]
Definition: opentype.c:196
WORD SubTableCount
Definition: opentype.c:195
WORD LookupFlag
Definition: opentype.c:194
WORD LookupType
Definition: opentype.c:193
WORD StartCoverageIndex
Definition: opentype.c:208
WORD ScriptCount
Definition: opentype.c:149
WORD DefaultLangSys
Definition: opentype.c:159
WORD LangSysCount
Definition: opentype.c:160
void * GPOS_Table
BOOL scripts_initialized
void * GDEF_Table
SIZE_T script_count
void * GSUB_Table
LoadedScript * scripts
SIZE_T scripts_size
TEXTMETRICW otmTextMetrics
Definition: wingdi.h:2514
Definition: _pair.h:47
LONG dv
Definition: usp10.h:201
LONG du
Definition: usp10.h:200
long y
Definition: polytest.cpp:48
long x
Definition: polytest.cpp:48
SCRIPT_VISATTR sva
Definition: usp10.h:215
LONG tmAscent
Definition: wingdi.h:2384
LONG tmInternalLeading
Definition: wingdi.h:2386
LONG tmDescent
Definition: wingdi.h:2385
WORD fLogicalOrder
Definition: usp10.h:144
WORD fClusterStart
Definition: usp10.h:179
Definition: ecma_167.h:138
#define bsearch
ULONG_PTR SIZE_T
Definition: typedefs.h:80
int32_t INT
Definition: typedefs.h:58
Definition: pdh_main.c:94
#define USP_E_SCRIPT_NOT_IN_FONT
Definition: usp10.h:71
ULONG OPENTYPE_TAG
Definition: usp10.h:205
#define FEATURE_GSUB_TABLE
#define GSUB_E_NOGLYPH
usp10_language_table
@ USP10_LANGUAGE_TABLE_GSUB
@ USP10_LANGUAGE_TABLE_GPOS
#define FEATURE_GPOS_TABLE
usp10_script_table
@ USP10_SCRIPT_TABLE_GSUB
@ USP10_SCRIPT_TABLE_GPOS
static const WCHAR lang[]
Definition: wbemdisp.c:287
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
DWORD WINAPI GetFontData(HDC hdc, DWORD dwTable, DWORD dwOffset, LPVOID lpvBuffer, DWORD cbData)
Definition: font.c:2654
_In_ FONTOBJ _In_ ULONG _In_ ULONG cGlyphs
Definition: winddi.h:3799
DWORD WINAPI GetGlyphIndicesW(_In_ HDC hdc, _In_reads_(c) LPCWSTR lpstr, _In_ int c, _Out_writes_(c) LPWORD pgi, _In_ DWORD fl)
#define GDI_ERROR
Definition: wingdi.h:1309
#define GGI_MARK_NONEXISTING_GLYPHS
Definition: wingdi.h:1085
_In_ ULONG Component
Definition: potypes.h:496
__wchar_t WCHAR
Definition: xmlstorage.h:180
char CHAR
Definition: xmlstorage.h:175
unsigned char BYTE
Definition: xxhash.c:193