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