2 * Methods for dealing with opentype font tables
4 * Copyright 2014 Aric Stewart for CodeWeavers
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.
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.
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
22 #define NONAMELESSUNION
25 #include "dwrite_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
30 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
31 #define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
32 #define MS_OTTO_TAG DWRITE_MAKE_OPENTYPE_TAG('O','T','T','O')
33 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
34 #define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
35 #define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f')
36 #define MS_GDEF_TAG DWRITE_MAKE_OPENTYPE_TAG('G','D','E','F')
37 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
38 #define MS_GLYF_TAG DWRITE_MAKE_OPENTYPE_TAG('g','l','y','f')
39 #define MS_CFF__TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F',' ')
40 #define MS_CFF2_TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F','2')
41 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
42 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
43 #define MS_SVG__TAG DWRITE_MAKE_OPENTYPE_TAG('S','V','G',' ')
44 #define MS_SBIX_TAG DWRITE_MAKE_OPENTYPE_TAG('s','b','i','x')
45 #define MS_MAXP_TAG DWRITE_MAKE_OPENTYPE_TAG('m','a','x','p')
46 #define MS_CBLC_TAG DWRITE_MAKE_OPENTYPE_TAG('C','B','L','C')
47 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
48 #define MS_META_TAG DWRITE_MAKE_OPENTYPE_TAG('m','e','t','a')
51 #define MS_PNG__TAG DWRITE_MAKE_OPENTYPE_TAG('p','n','g',' ')
52 #define MS_JPG__TAG DWRITE_MAKE_OPENTYPE_TAG('j','p','g',' ')
53 #define MS_TIFF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','i','f','f')
55 #define MS_WOFF_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','F')
56 #define MS_WOF2_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','2')
59 #define MS_DLNG_TAG DWRITE_MAKE_OPENTYPE_TAG('d','l','n','g')
60 #define MS_SLNG_TAG DWRITE_MAKE_OPENTYPE_TAG('s','l','n','g')
62 #ifdef WORDS_BIGENDIAN
63 #define GET_BE_WORD(x) (x)
64 #define GET_BE_DWORD(x) (x)
66 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
67 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
70 #define GLYPH_CONTEXT_MAX_LENGTH 64
71 #define SHAPE_MAX_NESTING_LEVEL 6
95 struct cmap_encoding_record
106 struct cmap_encoding_record tables
[1];
109 enum OPENTYPE_CMAP_TABLE_FORMAT
111 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
= 4,
112 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
= 12
115 enum opentype_cmap_table_platform
117 OPENTYPE_CMAP_TABLE_PLATFORM_WIN
= 3,
120 enum opentype_cmap_table_encoding
122 OPENTYPE_CMAP_TABLE_ENCODING_SYMBOL
= 0,
123 OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_BMP
= 1,
124 OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_FULL
= 10,
127 /* PANOSE is 10 bytes in size, need to pack the structure properly */
128 #include "pshpack2.h"
145 USHORT lowestRecPPEM
;
146 SHORT direction_hint
;
148 SHORT glyphdata_format
;
151 enum tt_head_macstyle
153 TT_HEAD_MACSTYLE_BOLD
= 1 << 0,
154 TT_HEAD_MACSTYLE_ITALIC
= 1 << 1,
155 TT_HEAD_MACSTYLE_UNDERLINE
= 1 << 2,
156 TT_HEAD_MACSTYLE_OUTLINE
= 1 << 3,
157 TT_HEAD_MACSTYLE_SHADOW
= 1 << 4,
158 TT_HEAD_MACSTYLE_CONDENSED
= 1 << 5,
159 TT_HEAD_MACSTYLE_EXTENDED
= 1 << 6,
166 SHORT underlinePosition
;
167 SHORT underlineThickness
;
179 USHORT usWeightClass
;
182 SHORT ySubscriptXSize
;
183 SHORT ySubscriptYSize
;
184 SHORT ySubscriptXOffset
;
185 SHORT ySubscriptYOffset
;
186 SHORT ySuperscriptXSize
;
187 SHORT ySuperscriptYSize
;
188 SHORT ySuperscriptXOffset
;
189 SHORT ySuperscriptYOffset
;
190 SHORT yStrikeoutSize
;
191 SHORT yStrikeoutPosition
;
194 ULONG ulUnicodeRange1
;
195 ULONG ulUnicodeRange2
;
196 ULONG ulUnicodeRange3
;
197 ULONG ulUnicodeRange4
;
200 USHORT usFirstCharIndex
;
201 USHORT usLastCharIndex
;
202 /* According to the Apple spec, original version didn't have the below fields,
203 * version numbers were taken from the OpenType spec.
205 /* version 0 (TrueType 1.5) */
206 USHORT sTypoAscender
;
207 USHORT sTypoDescender
;
211 /* version 1 (TrueType 1.66) */
212 ULONG ulCodePageRange1
;
213 ULONG ulCodePageRange2
;
214 /* version 2 (OpenType 1.2) */
217 USHORT usDefaultChar
;
229 USHORT advanceWidthMax
;
230 SHORT minLeftSideBearing
;
231 SHORT minRightSideBearing
;
233 SHORT caretSlopeRise
;
237 SHORT metricDataFormat
;
238 USHORT numberOfHMetrics
;
246 DWORD strike_offset
[1];
253 DWORD glyphdata_offsets
[1];
256 struct sbix_glyph_data
281 struct cblc_bitmapsize_table
283 DWORD indexSubTableArrayOffset
;
284 DWORD indexTablesSize
;
285 DWORD numberofIndexSubTables
;
287 sbitLineMetrics hori
;
288 sbitLineMetrics vert
;
289 WORD startGlyphIndex
;
307 struct gasp_range ranges
[1];
310 enum OS2_FSSELECTION
{
311 OS2_FSSELECTION_ITALIC
= 1 << 0,
312 OS2_FSSELECTION_UNDERSCORE
= 1 << 1,
313 OS2_FSSELECTION_NEGATIVE
= 1 << 2,
314 OS2_FSSELECTION_OUTLINED
= 1 << 3,
315 OS2_FSSELECTION_STRIKEOUT
= 1 << 4,
316 OS2_FSSELECTION_BOLD
= 1 << 5,
317 OS2_FSSELECTION_REGULAR
= 1 << 6,
318 OS2_FSSELECTION_USE_TYPO_METRICS
= 1 << 7,
319 OS2_FSSELECTION_WWS
= 1 << 8,
320 OS2_FSSELECTION_OBLIQUE
= 1 << 9
338 struct name_record records
[1];
368 struct vdmx_vtable entries
[1];
371 struct ot_feature_record
377 struct ot_feature_list
380 struct ot_feature_record features
[1];
385 WORD lookup_order
; /* Reserved */
386 WORD required_feature_index
;
388 WORD feature_index
[1];
391 struct ot_langsys_record
399 WORD default_langsys
;
401 struct ot_langsys_record langsys
[1];
404 struct ot_script_record
410 struct ot_script_list
413 struct ot_script_record scripts
[1];
418 GDEF_CLASS_UNCLASSIFIED
= 0,
420 GDEF_CLASS_LIGATURE
= 2,
422 GDEF_CLASS_COMPONENT
= 4,
423 GDEF_CLASS_MAX
= GDEF_CLASS_COMPONENT
,
431 UINT16 ligcaret_list
;
432 UINT16 markattach_classdef
;
433 UINT16 markglyphsetdef
;
436 struct ot_gdef_classdef_format1
444 struct ot_gdef_class_range
451 struct ot_gdef_classdef_format2
455 struct ot_gdef_class_range ranges
[1];
458 struct gpos_gsub_header
466 enum gsub_gpos_lookup_flags
468 LOOKUP_FLAG_RTL
= 0x1, /* Only used for GPOS cursive attachments. */
470 LOOKUP_FLAG_IGNORE_BASE
= 0x2,
471 LOOKUP_FLAG_IGNORE_LIGATURES
= 0x4,
472 LOOKUP_FLAG_IGNORE_MARKS
= 0x8,
473 LOOKUP_FLAG_IGNORE_MASK
= 0xe,
475 LOOKUP_FLAG_USE_MARK_FILTERING_SET
= 0x10,
476 LOOKUP_FLAG_MARK_ATTACHMENT_TYPE
= 0xff00,
479 enum glyph_prop_flags
481 GLYPH_PROP_BASE
= LOOKUP_FLAG_IGNORE_BASE
,
482 GLYPH_PROP_LIGATURE
= LOOKUP_FLAG_IGNORE_LIGATURES
,
483 GLYPH_PROP_MARK
= LOOKUP_FLAG_IGNORE_MARKS
,
484 GLYPH_PROP_ZWNJ
= 0x10,
485 GLYPH_PROP_ZWJ
= 0x20,
486 GLYPH_PROP_IGNORABLE
= 0x40,
487 GLYPH_PROP_HIDDEN
= 0x80,
490 enum gpos_lookup_type
492 GPOS_LOOKUP_SINGLE_ADJUSTMENT
= 1,
493 GPOS_LOOKUP_PAIR_ADJUSTMENT
= 2,
494 GPOS_LOOKUP_CURSIVE_ATTACHMENT
= 3,
495 GPOS_LOOKUP_MARK_TO_BASE_ATTACHMENT
= 4,
496 GPOS_LOOKUP_MARK_TO_LIGATURE_ATTACHMENT
= 5,
497 GPOS_LOOKUP_MARK_TO_MARK_ATTACHMENT
= 6,
498 GPOS_LOOKUP_CONTEXTUAL_POSITION
= 7,
499 GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION
= 8,
500 GPOS_LOOKUP_EXTENSION_POSITION
= 9,
503 enum gsub_lookup_type
505 GSUB_LOOKUP_SINGLE_SUBST
= 1,
506 GSUB_LOOKUP_MULTIPLE_SUBST
= 2,
507 GSUB_LOOKUP_ALTERNATE_SUBST
= 3,
508 GSUB_LOOKUP_LIGATURE_SUBST
= 4,
509 GSUB_LOOKUP_CONTEXTUAL_SUBST
= 5,
510 GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST
= 6,
511 GSUB_LOOKUP_EXTENSION_SUBST
= 7,
512 GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST
= 8,
515 enum gpos_value_format
517 GPOS_VALUE_X_PLACEMENT
= 0x1,
518 GPOS_VALUE_Y_PLACEMENT
= 0x2,
519 GPOS_VALUE_X_ADVANCE
= 0x4,
520 GPOS_VALUE_Y_ADVANCE
= 0x8,
521 GPOS_VALUE_X_PLACEMENT_DEVICE
= 0x10,
522 GPOS_VALUE_Y_PLACEMENT_DEVICE
= 0x20,
523 GPOS_VALUE_X_ADVANCE_DEVICE
= 0x40,
524 GPOS_VALUE_Y_ADVANCE_DEVICE
= 0x80,
527 enum OPENTYPE_PLATFORM_ID
529 OPENTYPE_PLATFORM_UNICODE
= 0,
530 OPENTYPE_PLATFORM_MAC
,
531 OPENTYPE_PLATFORM_ISO
,
532 OPENTYPE_PLATFORM_WIN
,
533 OPENTYPE_PLATFORM_CUSTOM
536 struct ot_gsubgpos_extension_format1
540 DWORD extension_offset
;
543 struct ot_gsub_singlesubst_format1
550 struct ot_gsub_singlesubst_format2
555 UINT16 substitutes
[1];
558 struct ot_gsub_multsubst_format1
566 struct ot_gsub_altsubst_format1
574 struct ot_gsub_ligsubst_format1
578 UINT16 lig_set_count
;
582 struct ot_gsub_ligset
592 UINT16 components
[1];
595 struct ot_gsubgpos_context_format1
599 UINT16 ruleset_count
;
603 struct ot_gsubgpos_ruleset
613 WORD lookuplist_index
[1];
616 struct ot_lookup_list
622 struct ot_lookup_table
630 #define GLYPH_NOT_COVERED (~0u)
632 struct ot_coverage_format1
639 struct ot_coverage_range
643 WORD startcoverage_index
;
646 struct ot_coverage_format2
650 struct ot_coverage_range ranges
[1];
653 struct ot_gpos_device_table
661 struct ot_gpos_singlepos_format1
669 struct ot_gpos_singlepos_format2
678 struct ot_gpos_pairvalue
684 struct ot_gpos_pairset
686 WORD pairvalue_count
;
687 struct ot_gpos_pairvalue pairvalues
[1];
690 struct ot_gpos_pairpos_format1
700 struct ot_gpos_pairpos_format2
713 struct ot_gpos_anchor_format1
720 struct ot_gpos_anchor_format2
728 struct ot_gpos_anchor_format3
737 struct ot_gpos_cursive_format1
745 struct ot_gpos_mark_record
751 struct ot_gpos_mark_array
754 struct ot_gpos_mark_record records
[1];
757 struct ot_gpos_base_array
763 struct ot_gpos_mark_to_base_format1
768 WORD mark_class_count
;
773 struct ot_gpos_mark_to_lig_format1
778 WORD mark_class_count
;
783 struct ot_gpos_mark_to_mark_format1
788 WORD mark_class_count
;
797 } GSUB_SingleSubstFormat1
;
804 } GSUB_SingleSubstFormat2
;
808 WORD ExtensionLookupType
;
809 DWORD ExtensionOffset
;
810 } GSUB_ExtensionPosFormat1
;
814 enum TT_NAME_WINDOWS_ENCODING_ID
816 TT_NAME_WINDOWS_ENCODING_SYMBOL
= 0,
817 TT_NAME_WINDOWS_ENCODING_UNICODE_BMP
,
818 TT_NAME_WINDOWS_ENCODING_SJIS
,
819 TT_NAME_WINDOWS_ENCODING_PRC
,
820 TT_NAME_WINDOWS_ENCODING_BIG5
,
821 TT_NAME_WINDOWS_ENCODING_WANSUNG
,
822 TT_NAME_WINDOWS_ENCODING_JOHAB
,
823 TT_NAME_WINDOWS_ENCODING_RESERVED1
,
824 TT_NAME_WINDOWS_ENCODING_RESERVED2
,
825 TT_NAME_WINDOWS_ENCODING_RESERVED3
,
826 TT_NAME_WINDOWS_ENCODING_UNICODE_FULL
829 enum TT_NAME_MAC_ENCODING_ID
831 TT_NAME_MAC_ENCODING_ROMAN
= 0,
832 TT_NAME_MAC_ENCODING_JAPANESE
,
833 TT_NAME_MAC_ENCODING_TRAD_CHINESE
,
834 TT_NAME_MAC_ENCODING_KOREAN
,
835 TT_NAME_MAC_ENCODING_ARABIC
,
836 TT_NAME_MAC_ENCODING_HEBREW
,
837 TT_NAME_MAC_ENCODING_GREEK
,
838 TT_NAME_MAC_ENCODING_RUSSIAN
,
839 TT_NAME_MAC_ENCODING_RSYMBOL
,
840 TT_NAME_MAC_ENCODING_DEVANAGARI
,
841 TT_NAME_MAC_ENCODING_GURMUKHI
,
842 TT_NAME_MAC_ENCODING_GUJARATI
,
843 TT_NAME_MAC_ENCODING_ORIYA
,
844 TT_NAME_MAC_ENCODING_BENGALI
,
845 TT_NAME_MAC_ENCODING_TAMIL
,
846 TT_NAME_MAC_ENCODING_TELUGU
,
847 TT_NAME_MAC_ENCODING_KANNADA
,
848 TT_NAME_MAC_ENCODING_MALAYALAM
,
849 TT_NAME_MAC_ENCODING_SINHALESE
,
850 TT_NAME_MAC_ENCODING_BURMESE
,
851 TT_NAME_MAC_ENCODING_KHMER
,
852 TT_NAME_MAC_ENCODING_THAI
,
853 TT_NAME_MAC_ENCODING_LAOTIAN
,
854 TT_NAME_MAC_ENCODING_GEORGIAN
,
855 TT_NAME_MAC_ENCODING_ARMENIAN
,
856 TT_NAME_MAC_ENCODING_SIMPL_CHINESE
,
857 TT_NAME_MAC_ENCODING_TIBETAN
,
858 TT_NAME_MAC_ENCODING_MONGOLIAN
,
859 TT_NAME_MAC_ENCODING_GEEZ
,
860 TT_NAME_MAC_ENCODING_SLAVIC
,
861 TT_NAME_MAC_ENCODING_VIETNAMESE
,
862 TT_NAME_MAC_ENCODING_SINDHI
,
863 TT_NAME_MAC_ENCODING_UNINTERPRETED
866 enum TT_NAME_MAC_LANGUAGE_ID
868 TT_NAME_MAC_LANGID_ENGLISH
= 0,
869 TT_NAME_MAC_LANGID_FRENCH
,
870 TT_NAME_MAC_LANGID_GERMAN
,
871 TT_NAME_MAC_LANGID_ITALIAN
,
872 TT_NAME_MAC_LANGID_DUTCH
,
873 TT_NAME_MAC_LANGID_SWEDISH
,
874 TT_NAME_MAC_LANGID_SPANISH
,
875 TT_NAME_MAC_LANGID_DANISH
,
876 TT_NAME_MAC_LANGID_PORTUGUESE
,
877 TT_NAME_MAC_LANGID_NORWEGIAN
,
878 TT_NAME_MAC_LANGID_HEBREW
,
879 TT_NAME_MAC_LANGID_JAPANESE
,
880 TT_NAME_MAC_LANGID_ARABIC
,
881 TT_NAME_MAC_LANGID_FINNISH
,
882 TT_NAME_MAC_LANGID_GREEK
,
883 TT_NAME_MAC_LANGID_ICELANDIC
,
884 TT_NAME_MAC_LANGID_MALTESE
,
885 TT_NAME_MAC_LANGID_TURKISH
,
886 TT_NAME_MAC_LANGID_CROATIAN
,
887 TT_NAME_MAC_LANGID_TRAD_CHINESE
,
888 TT_NAME_MAC_LANGID_URDU
,
889 TT_NAME_MAC_LANGID_HINDI
,
890 TT_NAME_MAC_LANGID_THAI
,
891 TT_NAME_MAC_LANGID_KOREAN
,
892 TT_NAME_MAC_LANGID_LITHUANIAN
,
893 TT_NAME_MAC_LANGID_POLISH
,
894 TT_NAME_MAC_LANGID_HUNGARIAN
,
895 TT_NAME_MAC_LANGID_ESTONIAN
,
896 TT_NAME_MAC_LANGID_LATVIAN
,
897 TT_NAME_MAC_LANGID_SAMI
,
898 TT_NAME_MAC_LANGID_FAROESE
,
899 TT_NAME_MAC_LANGID_FARSI
,
900 TT_NAME_MAC_LANGID_RUSSIAN
,
901 TT_NAME_MAC_LANGID_SIMPL_CHINESE
,
902 TT_NAME_MAC_LANGID_FLEMISH
,
903 TT_NAME_MAC_LANGID_GAELIC
,
904 TT_NAME_MAC_LANGID_ALBANIAN
,
905 TT_NAME_MAC_LANGID_ROMANIAN
,
906 TT_NAME_MAC_LANGID_CZECH
,
907 TT_NAME_MAC_LANGID_SLOVAK
,
908 TT_NAME_MAC_LANGID_SLOVENIAN
,
909 TT_NAME_MAC_LANGID_YIDDISH
,
910 TT_NAME_MAC_LANGID_SERBIAN
,
911 TT_NAME_MAC_LANGID_MACEDONIAN
,
912 TT_NAME_MAC_LANGID_BULGARIAN
,
913 TT_NAME_MAC_LANGID_UKRAINIAN
,
914 TT_NAME_MAC_LANGID_BYELORUSSIAN
,
915 TT_NAME_MAC_LANGID_UZBEK
,
916 TT_NAME_MAC_LANGID_KAZAKH
,
917 TT_NAME_MAC_LANGID_AZERB_CYR
,
918 TT_NAME_MAC_LANGID_AZERB_ARABIC
,
919 TT_NAME_MAC_LANGID_ARMENIAN
,
920 TT_NAME_MAC_LANGID_GEORGIAN
,
921 TT_NAME_MAC_LANGID_MOLDAVIAN
,
922 TT_NAME_MAC_LANGID_KIRGHIZ
,
923 TT_NAME_MAC_LANGID_TAJIKI
,
924 TT_NAME_MAC_LANGID_TURKMEN
,
925 TT_NAME_MAC_LANGID_MONGOLIAN
,
926 TT_NAME_MAC_LANGID_MONGOLIAN_CYR
,
927 TT_NAME_MAC_LANGID_PASHTO
,
928 TT_NAME_MAC_LANGID_KURDISH
,
929 TT_NAME_MAC_LANGID_KASHMIRI
,
930 TT_NAME_MAC_LANGID_SINDHI
,
931 TT_NAME_MAC_LANGID_TIBETAN
,
932 TT_NAME_MAC_LANGID_NEPALI
,
933 TT_NAME_MAC_LANGID_SANSKRIT
,
934 TT_NAME_MAC_LANGID_MARATHI
,
935 TT_NAME_MAC_LANGID_BENGALI
,
936 TT_NAME_MAC_LANGID_ASSAMESE
,
937 TT_NAME_MAC_LANGID_GUJARATI
,
938 TT_NAME_MAC_LANGID_PUNJABI
,
939 TT_NAME_MAC_LANGID_ORIYA
,
940 TT_NAME_MAC_LANGID_MALAYALAM
,
941 TT_NAME_MAC_LANGID_KANNADA
,
942 TT_NAME_MAC_LANGID_TAMIL
,
943 TT_NAME_MAC_LANGID_TELUGU
,
944 TT_NAME_MAC_LANGID_SINHALESE
,
945 TT_NAME_MAC_LANGID_BURMESE
,
946 TT_NAME_MAC_LANGID_KHMER
,
947 TT_NAME_MAC_LANGID_LAO
,
948 TT_NAME_MAC_LANGID_VIETNAMESE
,
949 TT_NAME_MAC_LANGID_INDONESIAN
,
950 TT_NAME_MAC_LANGID_TAGALOG
,
951 TT_NAME_MAC_LANGID_MALAY_ROMAN
,
952 TT_NAME_MAC_LANGID_MALAY_ARABIC
,
953 TT_NAME_MAC_LANGID_AMHARIC
,
954 TT_NAME_MAC_LANGID_TIGRINYA
,
955 TT_NAME_MAC_LANGID_GALLA
,
956 TT_NAME_MAC_LANGID_SOMALI
,
957 TT_NAME_MAC_LANGID_SWAHILI
,
958 TT_NAME_MAC_LANGID_KINYARWANDA
,
959 TT_NAME_MAC_LANGID_RUNDI
,
960 TT_NAME_MAC_LANGID_NYANJA
,
961 TT_NAME_MAC_LANGID_MALAGASY
,
962 TT_NAME_MAC_LANGID_ESPERANTO
,
963 TT_NAME_MAC_LANGID_WELSH
= 128,
964 TT_NAME_MAC_LANGID_BASQUE
,
965 TT_NAME_MAC_LANGID_CATALAN
,
966 TT_NAME_MAC_LANGID_LATIN
,
967 TT_NAME_MAC_LANGID_QUECHUA
,
968 TT_NAME_MAC_LANGID_GUARANI
,
969 TT_NAME_MAC_LANGID_AYMARA
,
970 TT_NAME_MAC_LANGID_TATAR
,
971 TT_NAME_MAC_LANGID_UIGHUR
,
972 TT_NAME_MAC_LANGID_DZONGKHA
,
973 TT_NAME_MAC_LANGID_JAVANESE
,
974 TT_NAME_MAC_LANGID_SUNDANESE
,
975 TT_NAME_MAC_LANGID_GALICIAN
,
976 TT_NAME_MAC_LANGID_AFRIKAANS
,
977 TT_NAME_MAC_LANGID_BRETON
,
978 TT_NAME_MAC_LANGID_INUKTITUT
,
979 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC
,
980 TT_NAME_MAC_LANGID_MANX_GAELIC
,
981 TT_NAME_MAC_LANGID_IRISH_GAELIC
,
982 TT_NAME_MAC_LANGID_TONGAN
,
983 TT_NAME_MAC_LANGID_GREEK_POLYTONIC
,
984 TT_NAME_MAC_LANGID_GREENLANDIC
,
985 TT_NAME_MAC_LANGID_AZER_ROMAN
988 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
989 static const char name_mac_langid_to_locale
[][10] = {
1143 enum OPENTYPE_STRING_ID
1145 OPENTYPE_STRING_COPYRIGHT_NOTICE
= 0,
1146 OPENTYPE_STRING_FAMILY_NAME
,
1147 OPENTYPE_STRING_SUBFAMILY_NAME
,
1148 OPENTYPE_STRING_UNIQUE_IDENTIFIER
,
1149 OPENTYPE_STRING_FULL_FONTNAME
,
1150 OPENTYPE_STRING_VERSION_STRING
,
1151 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
1152 OPENTYPE_STRING_TRADEMARK
,
1153 OPENTYPE_STRING_MANUFACTURER
,
1154 OPENTYPE_STRING_DESIGNER
,
1155 OPENTYPE_STRING_DESCRIPTION
,
1156 OPENTYPE_STRING_VENDOR_URL
,
1157 OPENTYPE_STRING_DESIGNER_URL
,
1158 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
1159 OPENTYPE_STRING_LICENSE_INFO_URL
,
1160 OPENTYPE_STRING_RESERVED_ID15
,
1161 OPENTYPE_STRING_TYPOGRAPHIC_FAMILY_NAME
,
1162 OPENTYPE_STRING_TYPOGRAPHIC_SUBFAMILY_NAME
,
1163 OPENTYPE_STRING_COMPATIBLE_FULLNAME
,
1164 OPENTYPE_STRING_SAMPLE_TEXT
,
1165 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
1166 OPENTYPE_STRING_WWS_FAMILY_NAME
,
1167 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
1170 static const UINT16 dwriteid_to_opentypeid
[DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME
+ 1] =
1172 (UINT16
)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
1173 OPENTYPE_STRING_COPYRIGHT_NOTICE
,
1174 OPENTYPE_STRING_VERSION_STRING
,
1175 OPENTYPE_STRING_TRADEMARK
,
1176 OPENTYPE_STRING_MANUFACTURER
,
1177 OPENTYPE_STRING_DESIGNER
,
1178 OPENTYPE_STRING_DESIGNER_URL
,
1179 OPENTYPE_STRING_DESCRIPTION
,
1180 OPENTYPE_STRING_VENDOR_URL
,
1181 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
1182 OPENTYPE_STRING_LICENSE_INFO_URL
,
1183 OPENTYPE_STRING_FAMILY_NAME
,
1184 OPENTYPE_STRING_SUBFAMILY_NAME
,
1185 OPENTYPE_STRING_TYPOGRAPHIC_FAMILY_NAME
,
1186 OPENTYPE_STRING_TYPOGRAPHIC_SUBFAMILY_NAME
,
1187 OPENTYPE_STRING_SAMPLE_TEXT
,
1188 OPENTYPE_STRING_FULL_FONTNAME
,
1189 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
1190 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
1191 OPENTYPE_STRING_WWS_FAMILY_NAME
,
1195 struct cpal_header_0
1198 USHORT num_palette_entries
;
1199 USHORT num_palettes
;
1200 USHORT num_color_records
;
1201 ULONG offset_first_color_record
;
1202 USHORT color_record_indices
[1];
1205 struct cpal_color_record
1217 USHORT num_baseglyph_records
;
1218 ULONG offset_baseglyph_records
;
1219 ULONG offset_layer_records
;
1220 USHORT num_layer_records
;
1223 struct colr_baseglyph_record
1226 USHORT first_layer_index
;
1230 struct colr_layer_record
1233 USHORT palette_index
;
1236 struct meta_data_map
1248 DWORD data_maps_count
;
1249 struct meta_data_map maps
[1];
1252 static const void *table_read_ensure(const struct dwrite_fonttable
*table
, unsigned int offset
, unsigned int size
)
1254 if (size
> table
->size
|| offset
> table
->size
- size
)
1257 return table
->data
+ offset
;
1260 static WORD
table_read_be_word(const struct dwrite_fonttable
*table
, unsigned int offset
)
1262 const WORD
*ptr
= table_read_ensure(table
, offset
, sizeof(*ptr
));
1263 return ptr
? GET_BE_WORD(*ptr
) : 0;
1266 static DWORD
table_read_be_dword(const struct dwrite_fonttable
*table
, unsigned int offset
)
1268 const DWORD
*ptr
= table_read_ensure(table
, offset
, sizeof(*ptr
));
1269 return ptr
? GET_BE_DWORD(*ptr
) : 0;
1272 static DWORD
table_read_dword(const struct dwrite_fonttable
*table
, unsigned int offset
)
1274 const DWORD
*ptr
= table_read_ensure(table
, offset
, sizeof(*ptr
));
1275 return ptr
? *ptr
: 0;
1278 BOOL
is_face_type_supported(DWRITE_FONT_FACE_TYPE type
)
1280 return (type
== DWRITE_FONT_FACE_TYPE_CFF
) ||
1281 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE
) ||
1282 (type
== DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
) ||
1283 (type
== DWRITE_FONT_FACE_TYPE_RAW_CFF
);
1286 typedef HRESULT (*dwrite_fontfile_analyzer
)(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1287 DWRITE_FONT_FACE_TYPE
*face_type
);
1289 static HRESULT
opentype_ttc_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1290 DWRITE_FONT_FACE_TYPE
*face_type
)
1292 static const DWORD ttctag
= MS_TTCF_TAG
;
1293 const TTC_Header_V1
*header
;
1297 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(header
), &context
);
1301 if (!memcmp(header
->TTCTag
, &ttctag
, sizeof(ttctag
))) {
1302 *font_count
= GET_BE_DWORD(header
->numFonts
);
1303 *file_type
= DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION
;
1304 *face_type
= DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
;
1307 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1309 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1312 static HRESULT
opentype_ttf_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1313 DWRITE_FONT_FACE_TYPE
*face_type
)
1315 const DWORD
*header
;
1319 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
1323 if (GET_BE_DWORD(*header
) == 0x10000) {
1325 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE
;
1326 *face_type
= DWRITE_FONT_FACE_TYPE_TRUETYPE
;
1329 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1331 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1334 static HRESULT
opentype_otf_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1335 DWRITE_FONT_FACE_TYPE
*face_type
)
1337 const DWORD
*header
;
1341 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
1345 if (GET_BE_DWORD(*header
) == MS_OTTO_TAG
) {
1347 *file_type
= DWRITE_FONT_FILE_TYPE_CFF
;
1348 *face_type
= DWRITE_FONT_FACE_TYPE_CFF
;
1351 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1353 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1356 static HRESULT
opentype_type1_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1357 DWRITE_FONT_FACE_TYPE
*face_type
)
1359 #include "pshpack1.h"
1360 /* Specified in Adobe TechNote #5178 */
1368 #include "poppack.h"
1369 struct type1_header
{
1373 const struct type1_header
*header
;
1377 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
1381 /* tag is followed by plain text section */
1382 if (header
->tag
== 0x8001 &&
1383 (!memcmp(header
->data
, "%!PS-AdobeFont", 14) ||
1384 !memcmp(header
->data
, "%!FontType", 10))) {
1386 *file_type
= DWRITE_FONT_FILE_TYPE_TYPE1_PFB
;
1387 *face_type
= DWRITE_FONT_FACE_TYPE_TYPE1
;
1390 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1392 /* let's see if it's a .pfm metrics file */
1393 if (*file_type
== DWRITE_FONT_FILE_TYPE_UNKNOWN
) {
1394 const struct pfm_header
*pfm_header
;
1397 BOOL header_checked
;
1399 hr
= IDWriteFontFileStream_GetFileSize(stream
, &filesize
);
1403 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&pfm_header
, 0, sizeof(*pfm_header
), &context
);
1407 offset
= pfm_header
->dfDevice
;
1408 header_checked
= pfm_header
->dfVersion
== 0x100 && pfm_header
->dfSize
== filesize
;
1409 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1411 /* as a last test check static string in PostScript information section */
1412 if (header_checked
) {
1413 static const char postscript
[] = "PostScript";
1416 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&devtype_name
, offset
, sizeof(postscript
), &context
);
1420 if (!memcmp(devtype_name
, postscript
, sizeof(postscript
))) {
1422 *file_type
= DWRITE_FONT_FILE_TYPE_TYPE1_PFM
;
1423 *face_type
= DWRITE_FONT_FACE_TYPE_TYPE1
;
1426 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1430 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1433 HRESULT
opentype_analyze_font(IDWriteFontFileStream
*stream
, BOOL
*supported
, DWRITE_FONT_FILE_TYPE
*file_type
,
1434 DWRITE_FONT_FACE_TYPE
*face_type
, UINT32
*face_count
)
1436 static dwrite_fontfile_analyzer fontfile_analyzers
[] = {
1437 opentype_ttf_analyzer
,
1438 opentype_otf_analyzer
,
1439 opentype_ttc_analyzer
,
1440 opentype_type1_analyzer
,
1443 dwrite_fontfile_analyzer
*analyzer
= fontfile_analyzers
;
1444 DWRITE_FONT_FACE_TYPE face
;
1450 *file_type
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
1451 *face_type
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
1455 hr
= (*analyzer
)(stream
, face_count
, file_type
, face_type
);
1465 *supported
= is_face_type_supported(*face_type
);
1469 HRESULT
opentype_try_get_font_table(const struct file_stream_desc
*stream_desc
, UINT32 tag
, const void **table_data
,
1470 void **table_context
, UINT32
*table_size
, BOOL
*found
)
1472 void *table_directory_context
, *sfnt_context
;
1473 TT_TableRecord
*table_record
= NULL
;
1474 TTC_SFNT_V1
*font_header
= NULL
;
1475 UINT32 table_offset
= 0;
1479 if (found
) *found
= FALSE
;
1480 if (table_size
) *table_size
= 0;
1483 *table_context
= NULL
;
1485 if (stream_desc
->face_type
== DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
) {
1486 const TTC_Header_V1
*ttc_header
;
1488 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&ttc_header
, 0, sizeof(*ttc_header
), &ttc_context
);
1489 if (SUCCEEDED(hr
)) {
1490 if (stream_desc
->face_index
>= GET_BE_DWORD(ttc_header
->numFonts
))
1493 table_offset
= GET_BE_DWORD(ttc_header
->OffsetTable
[stream_desc
->face_index
]);
1494 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&font_header
, table_offset
, sizeof(*font_header
), &sfnt_context
);
1496 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, ttc_context
);
1500 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&font_header
, 0, sizeof(*font_header
), &sfnt_context
);
1505 table_count
= GET_BE_WORD(font_header
->numTables
);
1506 table_offset
+= sizeof(*font_header
);
1508 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, sfnt_context
);
1510 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void **)&table_record
, table_offset
,
1511 table_count
* sizeof(*table_record
), &table_directory_context
);
1515 for (i
= 0; i
< table_count
; i
++) {
1516 if (table_record
->tag
== tag
) {
1517 UINT32 offset
= GET_BE_DWORD(table_record
->offset
);
1518 UINT32 length
= GET_BE_DWORD(table_record
->length
);
1523 *table_size
= length
;
1524 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, table_data
, offset
,
1525 length
, table_context
);
1531 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, table_directory_context
);
1537 static HRESULT
opentype_get_font_table(const struct file_stream_desc
*stream_desc
, UINT32 tag
,
1538 struct dwrite_fonttable
*table
)
1540 return opentype_try_get_font_table(stream_desc
, tag
, (const void **)&table
->data
, &table
->context
, &table
->size
, &table
->exists
);
1547 static UINT16
opentype_cmap_format0_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1549 const UINT8
*glyphs
= cmap
->data
;
1550 return (ch
< 0xff) ? glyphs
[ch
] : 0;
1553 static unsigned int opentype_cmap_format0_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1554 DWRITE_UNICODE_RANGE
*ranges
)
1565 struct cmap_format4_compare_context
1567 const struct dwrite_cmap
*cmap
;
1571 static int cmap_format4_compare_range(const void *a
, const void *b
)
1573 const struct cmap_format4_compare_context
*key
= a
;
1574 const UINT16
*end
= b
;
1577 if (key
->ch
> GET_BE_WORD(*end
))
1580 idx
= end
- key
->cmap
->u
.format4
.ends
;
1581 if (key
->ch
< GET_BE_WORD(key
->cmap
->u
.format4
.starts
[idx
]))
1587 static UINT16
opentype_cmap_format4_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1589 struct cmap_format4_compare_context key
= { .cmap
= cmap
, .ch
= ch
};
1590 unsigned int glyph
, idx
, range_offset
;
1591 const UINT16
*end_found
;
1593 /* Look up range. */
1594 end_found
= bsearch(&key
, cmap
->u
.format4
.ends
, cmap
->u
.format4
.seg_count
, sizeof(*cmap
->u
.format4
.ends
),
1595 cmap_format4_compare_range
);
1599 idx
= end_found
- cmap
->u
.format4
.ends
;
1601 range_offset
= GET_BE_WORD(cmap
->u
.format4
.id_range_offset
[idx
]);
1605 glyph
= ch
+ GET_BE_WORD(cmap
->u
.format4
.id_delta
[idx
]);
1609 unsigned int index
= range_offset
/ 2 + (ch
- GET_BE_WORD(cmap
->u
.format4
.starts
[idx
])) + idx
- cmap
->u
.format4
.seg_count
;
1610 if (index
>= cmap
->u
.format4
.glyph_id_array_len
)
1612 glyph
= GET_BE_WORD(cmap
->u
.format4
.glyph_id_array
[index
]);
1615 glyph
+= GET_BE_WORD(cmap
->u
.format4
.id_delta
[idx
]);
1618 return glyph
& 0xffff;
1621 static unsigned int opentype_cmap_format4_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1622 DWRITE_UNICODE_RANGE
*ranges
)
1626 count
= min(count
, cmap
->u
.format4
.seg_count
);
1628 for (i
= 0; i
< count
; ++i
)
1630 ranges
[i
].first
= GET_BE_WORD(cmap
->u
.format4
.starts
[i
]);
1631 ranges
[i
].last
= GET_BE_WORD(cmap
->u
.format4
.ends
[i
]);
1634 return cmap
->u
.format4
.seg_count
;
1637 static UINT16
opentype_cmap_format6_10_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1639 const UINT16
*glyphs
= cmap
->data
;
1640 if (ch
< cmap
->u
.format6_10
.first
|| ch
> cmap
->u
.format6_10
.last
) return 0;
1641 return glyphs
[ch
- cmap
->u
.format6_10
.first
];
1644 static unsigned int opentype_cmap_format6_10_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1645 DWRITE_UNICODE_RANGE
*ranges
)
1649 ranges
->first
= cmap
->u
.format6_10
.first
;
1650 ranges
->last
= cmap
->u
.format6_10
.last
;
1656 static int cmap_format12_13_compare_group(const void *a
, const void *b
)
1658 const unsigned int *ch
= a
;
1659 const UINT32
*group
= b
;
1661 if (*ch
> GET_BE_DWORD(group
[1]))
1664 if (*ch
< GET_BE_DWORD(group
[0]))
1670 static UINT16
opentype_cmap_format12_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1672 const UINT32
*groups
= cmap
->data
;
1673 const UINT32
*group_found
;
1675 if (!(group_found
= bsearch(&ch
, groups
, cmap
->u
.format12_13
.group_count
, 3 * sizeof(*groups
),
1676 cmap_format12_13_compare_group
)))
1679 return GET_BE_DWORD(group_found
[0]) <= GET_BE_DWORD(group_found
[1]) ?
1680 GET_BE_DWORD(group_found
[2]) + (ch
- GET_BE_DWORD(group_found
[0])) : 0;
1683 static unsigned int opentype_cmap_format12_13_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1684 DWRITE_UNICODE_RANGE
*ranges
)
1686 unsigned int i
, group_count
= cmap
->u
.format12_13
.group_count
;
1687 const UINT32
*groups
= cmap
->data
;
1689 count
= min(count
, group_count
);
1691 for (i
= 0; i
< count
; ++i
)
1693 ranges
[i
].first
= GET_BE_DWORD(groups
[3 * i
]);
1694 ranges
[i
].last
= GET_BE_DWORD(groups
[3 * i
+ 1]);
1700 static UINT16
opentype_cmap_format13_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1702 const UINT32
*groups
= cmap
->data
;
1703 const UINT32
*group_found
;
1705 if (!(group_found
= bsearch(&ch
, groups
, cmap
->u
.format12_13
.group_count
, 3 * sizeof(*groups
),
1706 cmap_format12_13_compare_group
)))
1709 return GET_BE_DWORD(group_found
[2]);
1712 static UINT16
opentype_cmap_dummy_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1717 static unsigned int opentype_cmap_dummy_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1718 DWRITE_UNICODE_RANGE
*ranges
)
1723 UINT16
opentype_cmap_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1727 if (!cmap
->get_glyph
) return 0;
1728 glyph
= cmap
->get_glyph(cmap
, ch
);
1729 if (!glyph
&& cmap
->symbol
&& ch
<= 0xff)
1730 glyph
= cmap
->get_glyph(cmap
, ch
+ 0xf000);
1734 static int cmap_header_compare(const void *a
, const void *b
)
1736 const UINT16
*key
= a
;
1737 const UINT16
*record
= b
;
1740 if (key
[0] < GET_BE_WORD(record
[0])) return -1;
1741 if (key
[0] > GET_BE_WORD(record
[0])) return 1;
1743 if (key
[1] < GET_BE_WORD(record
[1])) return -1;
1744 if (key
[1] > GET_BE_WORD(record
[1])) return 1;
1749 void dwrite_cmap_init(struct dwrite_cmap
*cmap
, IDWriteFontFile
*file
, unsigned int face_index
,
1750 DWRITE_FONT_FACE_TYPE face_type
)
1752 static const UINT16 encodings
[][2] =
1754 { 3, 0 }, /* MS Symbol encoding is preferred. */
1764 const struct cmap_encoding_record
*records
, *found_record
= NULL
;
1765 unsigned int length
, offset
, format
, count
, f
, i
, num_records
;
1766 struct file_stream_desc stream_desc
;
1767 struct dwrite_fonttable table
;
1768 const UINT16
*pair
= NULL
;
1771 if (cmap
->data
) return;
1773 /* For fontface stream is already available and preset. */
1774 if (!cmap
->stream
&& FAILED(hr
= get_filestream_from_file(file
, &cmap
->stream
)))
1776 WARN("Failed to get file stream, hr %#x.\n", hr
);
1780 stream_desc
.stream
= cmap
->stream
;
1781 stream_desc
.face_type
= face_type
;
1782 stream_desc
.face_index
= face_index
;
1784 opentype_get_font_table(&stream_desc
, MS_CMAP_TAG
, &table
);
1787 cmap
->table_context
= table
.context
;
1789 num_records
= table_read_be_word(&table
, 2);
1790 records
= table_read_ensure(&table
, 4, sizeof(*records
) * num_records
);
1792 for (i
= 0; i
< ARRAY_SIZE(encodings
); ++i
)
1794 pair
= encodings
[i
];
1795 if ((found_record
= bsearch(pair
, records
, num_records
, sizeof(*records
), cmap_header_compare
)))
1801 WARN("No suitable cmap table were found.\n");
1805 /* Symbol encoding. */
1806 cmap
->symbol
= pair
[0] == 3 && pair
[1] == 0;
1807 offset
= GET_BE_DWORD(found_record
->offset
);
1809 format
= table_read_be_word(&table
, offset
);
1814 cmap
->data
= table_read_ensure(&table
, offset
+ 6, 256);
1815 cmap
->get_glyph
= opentype_cmap_format0_get_glyph
;
1816 cmap
->get_ranges
= opentype_cmap_format0_get_ranges
;
1819 length
= table_read_be_word(&table
, offset
+ 2);
1820 cmap
->u
.format4
.seg_count
= count
= table_read_be_word(&table
, offset
+ 6) / 2;
1821 cmap
->u
.format4
.ends
= table_read_ensure(&table
, offset
+ 14, count
* 2);
1822 cmap
->u
.format4
.starts
= cmap
->u
.format4
.ends
+ count
+ 1;
1823 cmap
->u
.format4
.id_delta
= cmap
->u
.format4
.starts
+ count
;
1824 cmap
->u
.format4
.id_range_offset
= cmap
->u
.format4
.id_delta
+ count
;
1825 cmap
->u
.format4
.glyph_id_array
= cmap
->data
= cmap
->u
.format4
.id_range_offset
+ count
;
1826 cmap
->u
.format4
.glyph_id_array_len
= (length
- 16 - 8 * count
) / 2;
1827 cmap
->get_glyph
= opentype_cmap_format4_get_glyph
;
1828 cmap
->get_ranges
= opentype_cmap_format4_get_ranges
;
1832 /* Format 10 uses 4 byte fields. */
1833 f
= format
== 6 ? 1 : 2;
1834 cmap
->u
.format6_10
.first
= table_read_be_word(&table
, offset
+ f
* 6);
1835 count
= table_read_be_word(&table
, offset
+ f
* 8);
1836 cmap
->u
.format6_10
.last
= cmap
->u
.format6_10
.first
+ count
;
1837 cmap
->data
= table_read_ensure(&table
, offset
+ f
* 10, count
* 2);
1838 cmap
->get_glyph
= opentype_cmap_format6_10_get_glyph
;
1839 cmap
->get_ranges
= opentype_cmap_format6_10_get_ranges
;
1843 cmap
->u
.format12_13
.group_count
= count
= table_read_be_dword(&table
, offset
+ 12);
1844 cmap
->data
= table_read_ensure(&table
, offset
+ 16, count
* 3 * 4);
1845 cmap
->get_glyph
= format
== 12 ? opentype_cmap_format12_get_glyph
: opentype_cmap_format13_get_glyph
;
1846 cmap
->get_ranges
= opentype_cmap_format12_13_get_ranges
;
1849 WARN("Unhandled subtable format %u.\n", format
);
1856 /* Dummy implementation, returns 0 unconditionally. */
1858 cmap
->get_glyph
= opentype_cmap_dummy_get_glyph
;
1859 cmap
->get_ranges
= opentype_cmap_dummy_get_ranges
;
1863 void dwrite_cmap_release(struct dwrite_cmap
*cmap
)
1867 IDWriteFontFileStream_ReleaseFileFragment(cmap
->stream
, cmap
->table_context
);
1868 IDWriteFontFileStream_Release(cmap
->stream
);
1871 cmap
->stream
= NULL
;
1874 HRESULT
opentype_cmap_get_unicode_ranges(const struct dwrite_cmap
*cmap
, unsigned int max_count
, DWRITE_UNICODE_RANGE
*ranges
,
1875 unsigned int *count
)
1880 *count
= cmap
->get_ranges(cmap
, max_count
, ranges
);
1882 return *count
> max_count
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
1885 void opentype_get_font_typo_metrics(struct file_stream_desc
*stream_desc
, unsigned int *ascent
, unsigned int *descent
)
1887 struct dwrite_fonttable os2
;
1889 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
1891 *ascent
= *descent
= 0;
1893 if (os2
.size
>= FIELD_OFFSET(struct tt_os2
, sTypoLineGap
))
1895 SHORT value
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoDescender
));
1896 *ascent
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoAscender
));
1897 *descent
= value
< 0 ? -value
: 0;
1901 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
1904 void opentype_get_font_metrics(struct file_stream_desc
*stream_desc
, DWRITE_FONT_METRICS1
*metrics
, DWRITE_CARET_METRICS
*caret
)
1906 struct dwrite_fonttable os2
, head
, post
, hhea
;
1908 memset(metrics
, 0, sizeof(*metrics
));
1910 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
1911 opentype_get_font_table(stream_desc
, MS_HEAD_TAG
, &head
);
1912 opentype_get_font_table(stream_desc
, MS_POST_TAG
, &post
);
1913 opentype_get_font_table(stream_desc
, MS_HHEA_TAG
, &hhea
);
1917 metrics
->designUnitsPerEm
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, unitsPerEm
));
1918 metrics
->glyphBoxLeft
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, xMin
));
1919 metrics
->glyphBoxTop
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, yMax
));
1920 metrics
->glyphBoxRight
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, xMax
));
1921 metrics
->glyphBoxBottom
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, yMin
));
1928 caret
->slopeRise
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, caretSlopeRise
));
1929 caret
->slopeRun
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, caretSlopeRun
));
1930 caret
->offset
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, caretOffset
));
1933 memset(caret
, 0, sizeof(*caret
));
1938 USHORT version
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, version
));
1940 metrics
->ascent
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, usWinAscent
));
1941 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
1942 interpreted as large unsigned value. */
1943 metrics
->descent
= abs((SHORT
)table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, usWinDescent
)));
1945 /* Line gap is estimated using two sets of ascender/descender values and 'hhea' line gap. */
1948 SHORT descender
= (SHORT
)table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, descender
));
1951 linegap
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, ascender
)) + abs(descender
) +
1952 table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, linegap
)) - metrics
->ascent
- metrics
->descent
;
1953 metrics
->lineGap
= linegap
> 0 ? linegap
: 0;
1956 metrics
->strikethroughPosition
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, yStrikeoutPosition
));
1957 metrics
->strikethroughThickness
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, yStrikeoutSize
));
1958 metrics
->subscriptPositionX
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySubscriptXOffset
));
1959 /* Y offset is stored as positive offset below baseline */
1960 metrics
->subscriptPositionY
= -table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySubscriptYOffset
));
1961 metrics
->subscriptSizeX
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySubscriptXSize
));
1962 metrics
->subscriptSizeY
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySubscriptYSize
));
1963 metrics
->superscriptPositionX
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySuperscriptXOffset
));
1964 metrics
->superscriptPositionY
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySuperscriptYOffset
));
1965 metrics
->superscriptSizeX
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySuperscriptXSize
));
1966 metrics
->superscriptSizeY
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySuperscriptYSize
));
1968 /* version 2 fields */
1971 metrics
->capHeight
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sCapHeight
));
1972 metrics
->xHeight
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sxHeight
));
1975 if (table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, fsSelection
)) & OS2_FSSELECTION_USE_TYPO_METRICS
)
1977 SHORT descent
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoDescender
));
1978 metrics
->ascent
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoAscender
));
1979 metrics
->descent
= descent
< 0 ? -descent
: 0;
1980 metrics
->lineGap
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoLineGap
));
1981 metrics
->hasTypographicMetrics
= TRUE
;
1986 metrics
->strikethroughPosition
= metrics
->designUnitsPerEm
/ 3;
1989 metrics
->ascent
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, ascender
));
1990 metrics
->descent
= abs((SHORT
)table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, descender
)));
1996 metrics
->underlinePosition
= table_read_be_word(&post
, FIELD_OFFSET(struct tt_post
, underlinePosition
));
1997 metrics
->underlineThickness
= table_read_be_word(&post
, FIELD_OFFSET(struct tt_post
, underlineThickness
));
2000 if (metrics
->underlineThickness
== 0)
2001 metrics
->underlineThickness
= metrics
->designUnitsPerEm
/ 14;
2002 if (metrics
->strikethroughThickness
== 0)
2003 metrics
->strikethroughThickness
= metrics
->underlineThickness
;
2005 /* estimate missing metrics */
2006 if (metrics
->xHeight
== 0)
2007 metrics
->xHeight
= metrics
->designUnitsPerEm
/ 2;
2008 if (metrics
->capHeight
== 0)
2009 metrics
->capHeight
= metrics
->designUnitsPerEm
* 7 / 10;
2012 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
2014 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, head
.context
);
2016 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, post
.context
);
2018 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, hhea
.context
);
2021 void opentype_get_font_properties(struct file_stream_desc
*stream_desc
, struct dwrite_font_props
*props
)
2023 struct dwrite_fonttable os2
, head
, colr
, cpal
;
2024 BOOL is_symbol
, is_monospaced
;
2026 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
2027 opentype_get_font_table(stream_desc
, MS_HEAD_TAG
, &head
);
2029 /* default stretch, weight and style to normal */
2030 props
->stretch
= DWRITE_FONT_STRETCH_NORMAL
;
2031 props
->weight
= DWRITE_FONT_WEIGHT_NORMAL
;
2032 props
->style
= DWRITE_FONT_STYLE_NORMAL
;
2033 memset(&props
->panose
, 0, sizeof(props
->panose
));
2034 memset(&props
->fontsig
, 0, sizeof(props
->fontsig
));
2035 memset(&props
->lf
, 0, sizeof(props
->lf
));
2038 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
2041 USHORT version
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, version
));
2042 USHORT fsSelection
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, fsSelection
));
2043 USHORT usWeightClass
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, usWeightClass
));
2044 USHORT usWidthClass
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, usWidthClass
));
2047 if (usWidthClass
> DWRITE_FONT_STRETCH_UNDEFINED
&& usWidthClass
<= DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
2048 props
->stretch
= usWidthClass
;
2050 if (usWeightClass
>= 1 && usWeightClass
<= 9)
2051 usWeightClass
*= 100;
2053 if (usWeightClass
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
2054 props
->weight
= DWRITE_FONT_WEIGHT_ULTRA_BLACK
;
2055 else if (usWeightClass
> 0)
2056 props
->weight
= usWeightClass
;
2058 if (version
>= 4 && (fsSelection
& OS2_FSSELECTION_OBLIQUE
))
2059 props
->style
= DWRITE_FONT_STYLE_OBLIQUE
;
2060 else if (fsSelection
& OS2_FSSELECTION_ITALIC
)
2061 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
2062 props
->lf
.lfItalic
= !!(fsSelection
& OS2_FSSELECTION_ITALIC
);
2064 if ((panose
= table_read_ensure(&os2
, FIELD_OFFSET(struct tt_os2
, panose
), sizeof(props
->panose
))))
2065 memcpy(&props
->panose
, panose
, sizeof(props
->panose
));
2068 props
->fontsig
.fsUsb
[0] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulUnicodeRange1
));
2069 props
->fontsig
.fsUsb
[1] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulUnicodeRange2
));
2070 props
->fontsig
.fsUsb
[2] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulUnicodeRange3
));
2071 props
->fontsig
.fsUsb
[3] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulUnicodeRange4
));
2075 props
->fontsig
.fsCsb
[0] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulCodePageRange1
));
2076 props
->fontsig
.fsCsb
[1] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulCodePageRange2
));
2081 USHORT macStyle
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, macStyle
));
2083 if (macStyle
& TT_HEAD_MACSTYLE_CONDENSED
)
2084 props
->stretch
= DWRITE_FONT_STRETCH_CONDENSED
;
2085 else if (macStyle
& TT_HEAD_MACSTYLE_EXTENDED
)
2086 props
->stretch
= DWRITE_FONT_STRETCH_EXPANDED
;
2088 if (macStyle
& TT_HEAD_MACSTYLE_BOLD
)
2089 props
->weight
= DWRITE_FONT_WEIGHT_BOLD
;
2091 if (macStyle
& TT_HEAD_MACSTYLE_ITALIC
) {
2092 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
2093 props
->lf
.lfItalic
= 1;
2097 props
->lf
.lfWeight
= props
->weight
;
2099 /* FONT_IS_SYMBOL */
2100 if (!(is_symbol
= props
->panose
.familyKind
== DWRITE_PANOSE_FAMILY_SYMBOL
))
2102 struct dwrite_fonttable cmap
;
2103 int i
, offset
, num_tables
;
2105 opentype_get_font_table(stream_desc
, MS_CMAP_TAG
, &cmap
);
2109 num_tables
= table_read_be_word(&cmap
, FIELD_OFFSET(struct cmap_header
, num_tables
));
2110 offset
= FIELD_OFFSET(struct cmap_header
, tables
);
2112 for (i
= 0; !is_symbol
&& i
< num_tables
; ++i
)
2114 WORD platform
, encoding
;
2116 platform
= table_read_be_word(&cmap
, offset
+ i
* sizeof(struct cmap_encoding_record
) +
2117 FIELD_OFFSET(struct cmap_encoding_record
, platformID
));
2118 encoding
= table_read_be_word(&cmap
, offset
+ i
* sizeof(struct cmap_encoding_record
) +
2119 FIELD_OFFSET(struct cmap_encoding_record
, encodingID
));
2121 is_symbol
= platform
== OPENTYPE_CMAP_TABLE_PLATFORM_WIN
&&
2122 encoding
== OPENTYPE_CMAP_TABLE_ENCODING_SYMBOL
;
2125 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, cmap
.context
);
2129 props
->flags
|= FONT_IS_SYMBOL
;
2131 /* FONT_IS_MONOSPACED */
2132 if (!(is_monospaced
= props
->panose
.text
.proportion
== DWRITE_PANOSE_PROPORTION_MONOSPACED
))
2134 struct dwrite_fonttable post
;
2136 opentype_get_font_table(stream_desc
, MS_POST_TAG
, &post
);
2140 is_monospaced
= !!table_read_dword(&post
, FIELD_OFFSET(struct tt_post
, fixed_pitch
));
2142 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, post
.context
);
2146 props
->flags
|= FONT_IS_MONOSPACED
;
2148 /* FONT_IS_COLORED */
2149 opentype_get_font_table(stream_desc
, MS_COLR_TAG
, &colr
);
2152 opentype_get_font_table(stream_desc
, MS_CPAL_TAG
, &cpal
);
2155 props
->flags
|= FONT_IS_COLORED
;
2156 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, cpal
.context
);
2159 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, colr
.context
);
2162 TRACE("stretch %d, weight %d, style %d\n", props
->stretch
, props
->weight
, props
->style
);
2165 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
2167 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, head
.context
);
2170 static UINT
get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform
, USHORT encoding
)
2175 case OPENTYPE_PLATFORM_UNICODE
:
2177 case OPENTYPE_PLATFORM_MAC
:
2180 case TT_NAME_MAC_ENCODING_ROMAN
:
2183 case TT_NAME_MAC_ENCODING_JAPANESE
:
2186 case TT_NAME_MAC_ENCODING_TRAD_CHINESE
:
2189 case TT_NAME_MAC_ENCODING_KOREAN
:
2192 case TT_NAME_MAC_ENCODING_ARABIC
:
2195 case TT_NAME_MAC_ENCODING_HEBREW
:
2198 case TT_NAME_MAC_ENCODING_GREEK
:
2201 case TT_NAME_MAC_ENCODING_RUSSIAN
:
2204 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE
:
2207 case TT_NAME_MAC_ENCODING_THAI
:
2211 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
2215 case OPENTYPE_PLATFORM_WIN
:
2218 case TT_NAME_WINDOWS_ENCODING_SYMBOL
:
2219 case TT_NAME_WINDOWS_ENCODING_UNICODE_BMP
:
2220 case TT_NAME_WINDOWS_ENCODING_UNICODE_FULL
:
2222 case TT_NAME_WINDOWS_ENCODING_SJIS
:
2225 case TT_NAME_WINDOWS_ENCODING_PRC
:
2228 case TT_NAME_WINDOWS_ENCODING_BIG5
:
2231 case TT_NAME_WINDOWS_ENCODING_WANSUNG
:
2234 case TT_NAME_WINDOWS_ENCODING_JOHAB
:
2238 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
2243 FIXME("unknown platform %d\n", platform
);
2249 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform
, USHORT lang_id
, WCHAR
*locale
, USHORT locale_len
)
2251 static const WCHAR enusW
[] = {'e','n','-','U','S',0};
2254 case OPENTYPE_PLATFORM_MAC
:
2256 const char *locale_name
= NULL
;
2258 if (lang_id
> TT_NAME_MAC_LANGID_AZER_ROMAN
)
2259 WARN("invalid mac lang id %d\n", lang_id
);
2260 else if (!name_mac_langid_to_locale
[lang_id
][0])
2261 FIXME("failed to map mac lang id %d to locale name\n", lang_id
);
2263 locale_name
= name_mac_langid_to_locale
[lang_id
];
2266 MultiByteToWideChar(CP_ACP
, 0, name_mac_langid_to_locale
[lang_id
], -1, locale
, locale_len
);
2268 strcpyW(locale
, enusW
);
2271 case OPENTYPE_PLATFORM_WIN
:
2272 if (!LCIDToLocaleName(MAKELCID(lang_id
, SORT_DEFAULT
), locale
, locale_len
, 0)) {
2273 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id
, SORT_DEFAULT
));
2274 strcpyW(locale
, enusW
);
2277 case OPENTYPE_PLATFORM_UNICODE
:
2278 strcpyW(locale
, enusW
);
2281 FIXME("unknown platform %d\n", platform
);
2285 static BOOL
opentype_decode_namerecord(const struct dwrite_fonttable
*table
, unsigned int idx
,
2286 IDWriteLocalizedStrings
*strings
)
2288 USHORT lang_id
, length
, offset
, encoding
, platform
;
2289 const struct name_header
*header
= (const struct name_header
*)table
->data
;
2290 const struct name_record
*record
;
2291 unsigned int i
, string_offset
;
2295 string_offset
= table_read_be_word(table
, FIELD_OFFSET(struct name_header
, stringOffset
));
2297 record
= &header
->records
[idx
];
2299 platform
= GET_BE_WORD(record
->platformID
);
2300 lang_id
= GET_BE_WORD(record
->languageID
);
2301 length
= GET_BE_WORD(record
->length
);
2302 offset
= GET_BE_WORD(record
->offset
);
2303 encoding
= GET_BE_WORD(record
->encodingID
);
2305 if (!(name
= table_read_ensure(table
, string_offset
+ offset
, length
)))
2308 if (lang_id
< 0x8000)
2310 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
2314 codepage
= get_name_record_codepage(platform
, encoding
);
2315 get_name_record_locale(platform
, lang_id
, locale
, ARRAY_SIZE(locale
));
2319 DWORD len
= MultiByteToWideChar(codepage
, 0, name
, length
, NULL
, 0);
2320 name_string
= heap_alloc(sizeof(WCHAR
) * (len
+1));
2321 MultiByteToWideChar(codepage
, 0, name
, length
, name_string
, len
);
2322 name_string
[len
] = 0;
2326 length
/= sizeof(WCHAR
);
2327 name_string
= heap_strdupnW(name
, length
);
2328 for (i
= 0; i
< length
; i
++)
2329 name_string
[i
] = GET_BE_WORD(name_string
[i
]);
2332 TRACE("string %s for locale %s found\n", debugstr_w(name_string
), debugstr_w(locale
));
2333 add_localizedstring(strings
, locale
, name_string
);
2334 heap_free(name_string
);
2338 FIXME("handle NAME format 1\n");
2343 static HRESULT
opentype_get_font_strings_from_id(const struct dwrite_fonttable
*table
, enum OPENTYPE_STRING_ID id
,
2344 IDWriteLocalizedStrings
**strings
)
2346 int i
, count
, candidate_mac
, candidate_unicode
;
2347 const struct name_record
*records
;
2355 if (FAILED(hr
= create_localizedstrings(strings
)))
2358 format
= table_read_be_word(table
, FIELD_OFFSET(struct name_header
, format
));
2360 if (format
!= 0 && format
!= 1)
2361 FIXME("unsupported NAME format %d\n", format
);
2363 count
= table_read_be_word(table
, FIELD_OFFSET(struct name_header
, count
));
2365 if (!(records
= table_read_ensure(table
, FIELD_OFFSET(struct name_header
, records
),
2366 count
* sizeof(struct name_record
))))
2372 candidate_unicode
= candidate_mac
= -1;
2374 for (i
= 0; i
< count
; i
++)
2376 unsigned short platform
;
2378 if (GET_BE_WORD(records
[i
].nameID
) != id
)
2381 platform
= GET_BE_WORD(records
[i
].platformID
);
2384 /* Skip Unicode or Mac entries for now, fonts tend to duplicate those
2385 strings as WIN platform entries. If font does not have WIN entry for
2386 this id, we will use Mac or Unicode platform entry while assuming
2388 case OPENTYPE_PLATFORM_UNICODE
:
2389 if (candidate_unicode
== -1)
2390 candidate_unicode
= i
;
2392 case OPENTYPE_PLATFORM_MAC
:
2393 if (candidate_mac
== -1)
2396 case OPENTYPE_PLATFORM_WIN
:
2397 if (opentype_decode_namerecord(table
, i
, *strings
))
2401 FIXME("platform %i not supported\n", platform
);
2408 if (candidate_mac
!= -1)
2409 exists
= opentype_decode_namerecord(table
, candidate_mac
, *strings
);
2410 if (!exists
&& candidate_unicode
!= -1)
2411 exists
= opentype_decode_namerecord(table
, candidate_unicode
, *strings
);
2415 IDWriteLocalizedStrings_Release(*strings
);
2421 sort_localizedstrings(*strings
);
2423 return exists
? S_OK
: E_FAIL
;
2426 static WCHAR
*meta_get_lng_name(WCHAR
*str
, WCHAR
**ctx
)
2428 static const WCHAR delimW
[] = {',',' ',0};
2431 if (!str
) str
= *ctx
;
2432 while (*str
&& strchrW(delimW
, *str
)) str
++;
2433 if (!*str
) return NULL
;
2435 while (*str
&& !strchrW(delimW
, *str
)) str
++;
2436 if (*str
) *str
++ = 0;
2442 static HRESULT
opentype_get_font_strings_from_meta(const struct file_stream_desc
*stream_desc
,
2443 DWRITE_INFORMATIONAL_STRING_ID id
, IDWriteLocalizedStrings
**ret
)
2445 static const WCHAR emptyW
[] = { 0 };
2446 const struct meta_data_map
*maps
;
2447 IDWriteLocalizedStrings
*strings
;
2448 struct dwrite_fonttable meta
;
2449 DWORD version
, i
, count
, tag
;
2456 case DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG
:
2459 case DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
:
2463 WARN("Unexpected id %d.\n", id
);
2467 if (FAILED(hr
= create_localizedstrings(&strings
)))
2470 opentype_get_font_table(stream_desc
, MS_META_TAG
, &meta
);
2474 version
= table_read_be_dword(&meta
, 0);
2477 WARN("Unexpected meta table version %d.\n", version
);
2481 count
= table_read_be_dword(&meta
, FIELD_OFFSET(struct meta_header
, data_maps_count
));
2482 if (!(maps
= table_read_ensure(&meta
, FIELD_OFFSET(struct meta_header
, maps
),
2483 count
* sizeof(struct meta_data_map
))))
2486 for (i
= 0; i
< count
; ++i
)
2490 if (maps
[i
].tag
== tag
&& maps
[i
].length
)
2492 DWORD length
= GET_BE_DWORD(maps
[i
].length
), j
;
2494 if ((data
= table_read_ensure(&meta
, GET_BE_DWORD(maps
[i
].offset
), length
)))
2496 WCHAR
*ptrW
= heap_alloc((length
+ 1) * sizeof(WCHAR
)), *ctx
, *token
;
2504 /* Data is stored in comma separated list, ASCII range only. */
2505 for (j
= 0; j
< length
; ++j
)
2509 token
= meta_get_lng_name(ptrW
, &ctx
);
2513 add_localizedstring(strings
, emptyW
, token
);
2514 token
= meta_get_lng_name(NULL
, &ctx
);
2522 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, meta
.context
);
2525 if (IDWriteLocalizedStrings_GetCount(strings
))
2528 IDWriteLocalizedStrings_Release(strings
);
2533 HRESULT
opentype_get_font_info_strings(const struct file_stream_desc
*stream_desc
, DWRITE_INFORMATIONAL_STRING_ID id
,
2534 IDWriteLocalizedStrings
**strings
)
2536 struct dwrite_fonttable name
;
2540 case DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG
:
2541 case DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
:
2542 opentype_get_font_strings_from_meta(stream_desc
, id
, strings
);
2545 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name
);
2546 opentype_get_font_strings_from_id(&name
, dwriteid_to_opentypeid
[id
], strings
);
2548 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name
.context
);
2554 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
2555 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
2556 HRESULT
opentype_get_font_familyname(struct file_stream_desc
*stream_desc
, IDWriteLocalizedStrings
**names
)
2558 struct dwrite_fonttable os2
, name
;
2562 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
2563 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name
);
2567 /* If Preferred Family doesn't conform to WWS model try WWS name. */
2568 fsselection
= os2
.data
? table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, fsSelection
)) : 0;
2569 if (os2
.data
&& !(fsselection
& OS2_FSSELECTION_WWS
))
2570 hr
= opentype_get_font_strings_from_id(&name
, OPENTYPE_STRING_WWS_FAMILY_NAME
, names
);
2575 hr
= opentype_get_font_strings_from_id(&name
, OPENTYPE_STRING_TYPOGRAPHIC_FAMILY_NAME
, names
);
2577 hr
= opentype_get_font_strings_from_id(&name
, OPENTYPE_STRING_FAMILY_NAME
, names
);
2580 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
2582 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name
.context
);
2587 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
2588 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
2589 HRESULT
opentype_get_font_facename(struct file_stream_desc
*stream_desc
, WCHAR
*lfname
, IDWriteLocalizedStrings
**names
)
2591 struct dwrite_fonttable os2
, name
;
2592 IDWriteLocalizedStrings
*lfnames
;
2596 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
2597 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name
);
2601 /* if Preferred Family doesn't conform to WWS model try WWS name */
2602 fsselection
= os2
.data
? table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, fsSelection
)) : 0;
2603 if (os2
.data
&& !(fsselection
& OS2_FSSELECTION_WWS
))
2604 hr
= opentype_get_font_strings_from_id(&name
, OPENTYPE_STRING_WWS_SUBFAMILY_NAME
, names
);
2609 hr
= opentype_get_font_strings_from_id(&name
, OPENTYPE_STRING_TYPOGRAPHIC_SUBFAMILY_NAME
, names
);
2611 hr
= opentype_get_font_strings_from_id(&name
, OPENTYPE_STRING_SUBFAMILY_NAME
, names
);
2613 /* User locale is preferred, with fallback to en-us. */
2615 if (SUCCEEDED(opentype_get_font_strings_from_id(&name
, OPENTYPE_STRING_FAMILY_NAME
, &lfnames
)))
2617 static const WCHAR enusW
[] = {'e','n','-','u','s',0};
2618 WCHAR localeW
[LOCALE_NAME_MAX_LENGTH
];
2623 if (GetSystemDefaultLocaleName(localeW
, ARRAY_SIZE(localeW
)))
2624 IDWriteLocalizedStrings_FindLocaleName(lfnames
, localeW
, &index
, &exists
);
2627 IDWriteLocalizedStrings_FindLocaleName(lfnames
, enusW
, &index
, &exists
);
2633 IDWriteLocalizedStrings_GetStringLength(lfnames
, index
, &length
);
2634 nameW
= heap_alloc((length
+ 1) * sizeof(WCHAR
));
2637 IDWriteLocalizedStrings_GetString(lfnames
, index
, nameW
, length
+ 1);
2638 lstrcpynW(lfname
, nameW
, LF_FACESIZE
);
2643 IDWriteLocalizedStrings_Release(lfnames
);
2647 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
2649 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name
.context
);
2654 static const struct ot_langsys
*opentype_get_langsys(const struct ot_gsubgpos_table
*table
, unsigned int script_index
,
2655 unsigned int language_index
, unsigned int *feature_count
)
2657 unsigned int table_offset
, langsys_offset
;
2658 const struct ot_langsys
*langsys
= NULL
;
2662 if (!table
->table
.data
|| script_index
== ~0u)
2665 /* ScriptTable offset. */
2666 table_offset
= table_read_be_word(&table
->table
, table
->script_list
+ FIELD_OFFSET(struct ot_script_list
, scripts
) +
2667 script_index
* sizeof(struct ot_script_record
) + FIELD_OFFSET(struct ot_script_record
, script
));
2671 if (language_index
== ~0u)
2672 langsys_offset
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
);
2674 langsys_offset
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
+
2675 FIELD_OFFSET(struct ot_script
, langsys
) + language_index
* sizeof(struct ot_langsys_record
) +
2676 FIELD_OFFSET(struct ot_langsys_record
, langsys
));
2677 langsys_offset
+= table
->script_list
+ table_offset
;
2679 *feature_count
= table_read_be_word(&table
->table
, langsys_offset
+ FIELD_OFFSET(struct ot_langsys
, feature_count
));
2681 langsys
= table_read_ensure(&table
->table
, langsys_offset
, FIELD_OFFSET(struct ot_langsys
, feature_index
[*feature_count
]));
2688 void opentype_get_typographic_features(struct ot_gsubgpos_table
*table
, unsigned int script_index
,
2689 unsigned int language_index
, struct tag_array
*t
)
2691 unsigned int i
, total_feature_count
, script_feature_count
;
2692 const struct ot_feature_list
*feature_list
;
2693 const struct ot_langsys
*langsys
= NULL
;
2695 langsys
= opentype_get_langsys(table
, script_index
, language_index
, &script_feature_count
);
2697 total_feature_count
= table_read_be_word(&table
->table
, table
->feature_list
);
2698 if (!total_feature_count
)
2701 feature_list
= table_read_ensure(&table
->table
, table
->feature_list
,
2702 FIELD_OFFSET(struct ot_feature_list
, features
[total_feature_count
]));
2706 for (i
= 0; i
< script_feature_count
; ++i
)
2708 unsigned int feature_index
= GET_BE_WORD(langsys
->feature_index
[i
]);
2709 if (feature_index
>= total_feature_count
)
2712 if (!dwrite_array_reserve((void **)&t
->tags
, &t
->capacity
, t
->count
+ 1, sizeof(*t
->tags
)))
2715 t
->tags
[t
->count
++] = feature_list
->features
[feature_index
].tag
;
2719 static unsigned int find_vdmx_group(const struct vdmx_header
*hdr
)
2722 const struct vdmx_ratio
*ratios
= (struct vdmx_ratio
*)(hdr
+ 1);
2723 BYTE dev_x_ratio
= 1, dev_y_ratio
= 1;
2724 unsigned int group_offset
= 0;
2726 num_ratios
= GET_BE_WORD(hdr
->num_ratios
);
2728 for (i
= 0; i
< num_ratios
; i
++) {
2730 if (!ratios
[i
].bCharSet
) continue;
2732 if ((ratios
[i
].xRatio
== 0 && ratios
[i
].yStartRatio
== 0 &&
2733 ratios
[i
].yEndRatio
== 0) ||
2734 (ratios
[i
].xRatio
== dev_x_ratio
&& ratios
[i
].yStartRatio
<= dev_y_ratio
&&
2735 ratios
[i
].yEndRatio
>= dev_y_ratio
))
2737 group_offset
= GET_BE_WORD(*((WORD
*)(ratios
+ num_ratios
) + i
));
2742 return group_offset
;
2745 BOOL
opentype_get_vdmx_size(const struct dwrite_fonttable
*vdmx
, INT emsize
, UINT16
*ascent
, UINT16
*descent
)
2747 unsigned int num_ratios
, num_recs
, group_offset
, i
;
2748 const struct vdmx_header
*header
;
2749 const struct vdmx_group
*group
;
2754 num_ratios
= table_read_be_word(vdmx
, FIELD_OFFSET(struct vdmx_header
, num_ratios
));
2755 num_recs
= table_read_be_word(vdmx
, FIELD_OFFSET(struct vdmx_header
, num_recs
));
2757 header
= table_read_ensure(vdmx
, 0, sizeof(*header
) + num_ratios
* sizeof(struct vdmx_ratio
) +
2758 num_recs
* sizeof(*group
));
2763 group_offset
= find_vdmx_group(header
);
2767 num_recs
= table_read_be_word(vdmx
, group_offset
);
2768 group
= table_read_ensure(vdmx
, group_offset
, FIELD_OFFSET(struct vdmx_group
, entries
[num_recs
]));
2773 if (emsize
< group
->startsz
|| emsize
>= group
->endsz
)
2776 for (i
= 0; i
< num_recs
; ++i
)
2778 WORD ppem
= GET_BE_WORD(group
->entries
[i
].yPelHeight
);
2779 if (ppem
> emsize
) {
2780 FIXME("interpolate %d\n", emsize
);
2784 if (ppem
== emsize
) {
2785 *ascent
= (SHORT
)GET_BE_WORD(group
->entries
[i
].yMax
);
2786 *descent
= -(SHORT
)GET_BE_WORD(group
->entries
[i
].yMin
);
2794 unsigned int opentype_get_gasp_flags(const struct dwrite_fonttable
*gasp
, float emsize
)
2796 unsigned int version
, num_ranges
, i
;
2797 const struct gasp_header
*table
;
2803 num_ranges
= table_read_be_word(gasp
, FIELD_OFFSET(struct gasp_header
, num_ranges
));
2805 table
= table_read_ensure(gasp
, 0, FIELD_OFFSET(struct gasp_header
, ranges
[num_ranges
]));
2809 version
= GET_BE_WORD(table
->version
);
2812 ERR("Unsupported gasp table format version %u.\n", version
);
2816 for (i
= 0; i
< num_ranges
; ++i
)
2818 flags
= GET_BE_WORD(table
->ranges
[i
].flags
);
2819 if (emsize
<= GET_BE_WORD(table
->ranges
[i
].max_ppem
)) break;
2826 unsigned int opentype_get_cpal_palettecount(const struct dwrite_fonttable
*cpal
)
2828 return table_read_be_word(cpal
, FIELD_OFFSET(struct cpal_header_0
, num_palettes
));
2831 unsigned int opentype_get_cpal_paletteentrycount(const struct dwrite_fonttable
*cpal
)
2833 return table_read_be_word(cpal
, FIELD_OFFSET(struct cpal_header_0
, num_palette_entries
));
2836 HRESULT
opentype_get_cpal_entries(const struct dwrite_fonttable
*cpal
, unsigned int palette
,
2837 unsigned int first_entry_index
, unsigned int entry_count
, DWRITE_COLOR_F
*entries
)
2839 unsigned int num_palettes
, num_palette_entries
, i
;
2840 const struct cpal_color_record
*records
;
2841 const struct cpal_header_0
*header
;
2843 header
= table_read_ensure(cpal
, 0, sizeof(*header
));
2845 if (!cpal
->exists
|| !header
)
2846 return DWRITE_E_NOCOLOR
;
2848 num_palettes
= GET_BE_WORD(header
->num_palettes
);
2849 if (palette
>= num_palettes
)
2850 return DWRITE_E_NOCOLOR
;
2852 header
= table_read_ensure(cpal
, 0, FIELD_OFFSET(struct cpal_header_0
, color_record_indices
[palette
]));
2854 return DWRITE_E_NOCOLOR
;
2856 num_palette_entries
= GET_BE_WORD(header
->num_palette_entries
);
2857 if (first_entry_index
+ entry_count
> num_palette_entries
)
2858 return E_INVALIDARG
;
2860 records
= table_read_ensure(cpal
, GET_BE_DWORD(header
->offset_first_color_record
),
2861 sizeof(*records
) * GET_BE_WORD(header
->num_color_records
));
2863 return DWRITE_E_NOCOLOR
;
2865 first_entry_index
+= GET_BE_WORD(header
->color_record_indices
[palette
]);
2867 for (i
= 0; i
< entry_count
; i
++) {
2868 entries
[i
].u1
.r
= records
[first_entry_index
+ i
].red
/ 255.0f
;
2869 entries
[i
].u2
.g
= records
[first_entry_index
+ i
].green
/ 255.0f
;
2870 entries
[i
].u3
.b
= records
[first_entry_index
+ i
].blue
/ 255.0f
;
2871 entries
[i
].u4
.a
= records
[first_entry_index
+ i
].alpha
/ 255.0f
;
2877 static int colr_compare_gid(const void *g
, const void *r
)
2879 const struct colr_baseglyph_record
*record
= r
;
2880 UINT16 glyph
= *(UINT16
*)g
, GID
= GET_BE_WORD(record
->glyph
);
2885 else if (glyph
< GID
)
2891 HRESULT
opentype_get_colr_glyph(const struct dwrite_fonttable
*colr
, UINT16 glyph
, struct dwrite_colorglyph
*ret
)
2893 unsigned int num_baseglyph_records
, offset_baseglyph_records
;
2894 const struct colr_baseglyph_record
*record
;
2895 const struct colr_layer_record
*layer
;
2896 const struct colr_header
*header
;
2898 memset(ret
, 0, sizeof(*ret
));
2900 ret
->palette_index
= 0xffff;
2902 header
= table_read_ensure(colr
, 0, sizeof(*header
));
2906 num_baseglyph_records
= GET_BE_WORD(header
->num_baseglyph_records
);
2907 offset_baseglyph_records
= GET_BE_DWORD(header
->offset_baseglyph_records
);
2908 if (!table_read_ensure(colr
, offset_baseglyph_records
, num_baseglyph_records
* sizeof(*record
)))
2913 record
= bsearch(&glyph
, colr
->data
+ offset_baseglyph_records
, num_baseglyph_records
,
2914 sizeof(*record
), colr_compare_gid
);
2918 ret
->first_layer
= GET_BE_WORD(record
->first_layer_index
);
2919 ret
->num_layers
= GET_BE_WORD(record
->num_layers
);
2921 if ((layer
= table_read_ensure(colr
, GET_BE_DWORD(header
->offset_layer_records
),
2922 (ret
->first_layer
+ ret
->layer
) * sizeof(*layer
))))
2924 layer
+= ret
->first_layer
+ ret
->layer
;
2925 ret
->glyph
= GET_BE_WORD(layer
->glyph
);
2926 ret
->palette_index
= GET_BE_WORD(layer
->palette_index
);
2932 void opentype_colr_next_glyph(const struct dwrite_fonttable
*colr
, struct dwrite_colorglyph
*glyph
)
2934 const struct colr_layer_record
*layer
;
2935 const struct colr_header
*header
;
2937 /* iterated all the way through */
2938 if (glyph
->layer
== glyph
->num_layers
)
2941 if (!(header
= table_read_ensure(colr
, 0, sizeof(*header
))))
2946 if ((layer
= table_read_ensure(colr
, GET_BE_DWORD(header
->offset_layer_records
),
2947 (glyph
->first_layer
+ glyph
->layer
) * sizeof(*layer
))))
2949 layer
+= glyph
->first_layer
+ glyph
->layer
;
2950 glyph
->glyph
= GET_BE_WORD(layer
->glyph
);
2951 glyph
->palette_index
= GET_BE_WORD(layer
->palette_index
);
2955 static BOOL
opentype_has_font_table(IDWriteFontFace5
*fontface
, UINT32 tag
)
2957 BOOL exists
= FALSE
;
2963 hr
= IDWriteFontFace5_TryGetFontTable(fontface
, tag
, &data
, &size
, &context
, &exists
);
2968 IDWriteFontFace5_ReleaseFontTable(fontface
, context
);
2973 static unsigned int opentype_get_sbix_formats(IDWriteFontFace5
*fontface
)
2975 unsigned int num_strikes
, num_glyphs
, i
, j
, ret
= 0;
2976 const struct sbix_header
*sbix_header
;
2977 struct dwrite_fonttable table
;
2979 memset(&table
, 0, sizeof(table
));
2980 table
.exists
= TRUE
;
2982 if (!get_fontface_table(fontface
, MS_MAXP_TAG
, &table
))
2985 num_glyphs
= table_read_be_word(&table
, FIELD_OFFSET(struct maxp
, num_glyphs
));
2987 IDWriteFontFace5_ReleaseFontTable(fontface
, table
.context
);
2989 memset(&table
, 0, sizeof(table
));
2990 table
.exists
= TRUE
;
2992 if (!get_fontface_table(fontface
, MS_SBIX_TAG
, &table
))
2995 num_strikes
= table_read_be_dword(&table
, FIELD_OFFSET(struct sbix_header
, num_strikes
));
2996 sbix_header
= table_read_ensure(&table
, 0, FIELD_OFFSET(struct sbix_header
, strike_offset
[num_strikes
]));
3000 for (i
= 0; i
< num_strikes
; ++i
)
3002 unsigned int strike_offset
= GET_BE_DWORD(sbix_header
->strike_offset
[i
]);
3003 const struct sbix_strike
*strike
= table_read_ensure(&table
, strike_offset
,
3004 FIELD_OFFSET(struct sbix_strike
, glyphdata_offsets
[num_glyphs
+ 1]));
3009 for (j
= 0; j
< num_glyphs
; j
++)
3011 unsigned int offset
= GET_BE_DWORD(strike
->glyphdata_offsets
[j
]);
3012 unsigned int next_offset
= GET_BE_DWORD(strike
->glyphdata_offsets
[j
+ 1]);
3013 const struct sbix_glyph_data
*glyph_data
;
3015 if (offset
== next_offset
)
3018 glyph_data
= table_read_ensure(&table
, strike_offset
+ offset
, sizeof(*glyph_data
));
3022 switch (glyph_data
->graphic_type
)
3025 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_PNG
;
3028 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_JPEG
;
3031 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_TIFF
;
3034 FIXME("unexpected bitmap format %s\n", debugstr_tag(GET_BE_DWORD(glyph_data
->graphic_type
)));
3040 IDWriteFontFace5_ReleaseFontTable(fontface
, table
.context
);
3045 static unsigned int opentype_get_cblc_formats(IDWriteFontFace5
*fontface
)
3047 const unsigned int format_mask
= DWRITE_GLYPH_IMAGE_FORMATS_PNG
|
3048 DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8
;
3049 const struct cblc_bitmapsize_table
*sizes
;
3050 struct dwrite_fonttable cblc
= { 0 };
3051 unsigned int num_sizes
, i
, ret
= 0;
3052 const struct cblc_header
*header
;
3055 if (!get_fontface_table(fontface
, MS_CBLC_TAG
, &cblc
))
3058 num_sizes
= table_read_be_dword(&cblc
, FIELD_OFFSET(struct cblc_header
, num_sizes
));
3059 sizes
= table_read_ensure(&cblc
, sizeof(*header
), num_sizes
* sizeof(*sizes
));
3063 for (i
= 0; i
< num_sizes
; ++i
)
3065 BYTE bpp
= sizes
[i
].bit_depth
;
3067 if ((ret
& format_mask
) == format_mask
)
3070 if (bpp
== 1 || bpp
== 2 || bpp
== 4 || bpp
== 8)
3071 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_PNG
;
3073 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8
;
3077 IDWriteFontFace5_ReleaseFontTable(fontface
, cblc
.context
);
3082 UINT32
opentype_get_glyph_image_formats(IDWriteFontFace5
*fontface
)
3084 UINT32 ret
= DWRITE_GLYPH_IMAGE_FORMATS_NONE
;
3086 if (opentype_has_font_table(fontface
, MS_GLYF_TAG
))
3087 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE
;
3089 if (opentype_has_font_table(fontface
, MS_CFF__TAG
) ||
3090 opentype_has_font_table(fontface
, MS_CFF2_TAG
))
3091 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_CFF
;
3093 if (opentype_has_font_table(fontface
, MS_COLR_TAG
))
3094 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_COLR
;
3096 if (opentype_has_font_table(fontface
, MS_SVG__TAG
))
3097 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_SVG
;
3099 if (opentype_has_font_table(fontface
, MS_SBIX_TAG
))
3100 ret
|= opentype_get_sbix_formats(fontface
);
3102 if (opentype_has_font_table(fontface
, MS_CBLC_TAG
))
3103 ret
|= opentype_get_cblc_formats(fontface
);
3108 DWRITE_CONTAINER_TYPE
opentype_analyze_container_type(void const *data
, UINT32 data_size
)
3112 if (data_size
< sizeof(DWORD
))
3113 return DWRITE_CONTAINER_TYPE_UNKNOWN
;
3115 /* Both WOFF and WOFF2 start with 4 bytes signature. */
3116 signature
= *(DWORD
*)data
;
3121 return DWRITE_CONTAINER_TYPE_WOFF
;
3123 return DWRITE_CONTAINER_TYPE_WOFF2
;
3125 return DWRITE_CONTAINER_TYPE_UNKNOWN
;
3129 void opentype_layout_scriptshaping_cache_init(struct scriptshaping_cache
*cache
)
3131 cache
->font
->grab_font_table(cache
->context
, MS_GSUB_TAG
, &cache
->gsub
.table
.data
, &cache
->gsub
.table
.size
,
3132 &cache
->gsub
.table
.context
);
3134 if (cache
->gsub
.table
.data
)
3136 cache
->gsub
.script_list
= table_read_be_word(&cache
->gsub
.table
, FIELD_OFFSET(struct gpos_gsub_header
, script_list
));
3137 cache
->gsub
.feature_list
= table_read_be_word(&cache
->gsub
.table
, FIELD_OFFSET(struct gpos_gsub_header
, feature_list
));
3138 cache
->gsub
.lookup_list
= table_read_be_word(&cache
->gsub
.table
, FIELD_OFFSET(struct gpos_gsub_header
, lookup_list
));
3141 cache
->font
->grab_font_table(cache
->context
, MS_GPOS_TAG
, &cache
->gpos
.table
.data
, &cache
->gpos
.table
.size
,
3142 &cache
->gpos
.table
.context
);
3144 if (cache
->gpos
.table
.data
)
3146 cache
->gpos
.script_list
= table_read_be_word(&cache
->gpos
.table
,
3147 FIELD_OFFSET(struct gpos_gsub_header
, script_list
));
3148 cache
->gpos
.feature_list
= table_read_be_word(&cache
->gpos
.table
,
3149 FIELD_OFFSET(struct gpos_gsub_header
, feature_list
));
3150 cache
->gpos
.lookup_list
= table_read_be_word(&cache
->gpos
.table
,
3151 FIELD_OFFSET(struct gpos_gsub_header
, lookup_list
));
3154 cache
->font
->grab_font_table(cache
->context
, MS_GDEF_TAG
, &cache
->gdef
.table
.data
, &cache
->gdef
.table
.size
,
3155 &cache
->gdef
.table
.context
);
3157 if (cache
->gdef
.table
.data
)
3159 unsigned int version
= table_read_be_dword(&cache
->gdef
.table
, 0);
3161 cache
->gdef
.classdef
= table_read_be_word(&cache
->gdef
.table
, FIELD_OFFSET(struct gdef_header
, classdef
));
3162 cache
->gdef
.markattachclassdef
= table_read_be_word(&cache
->gdef
.table
,
3163 FIELD_OFFSET(struct gdef_header
, markattach_classdef
));
3164 if (version
>= 0x00010002)
3165 cache
->gdef
.markglyphsetdef
= table_read_be_word(&cache
->gdef
.table
,
3166 FIELD_OFFSET(struct gdef_header
, markglyphsetdef
));
3170 unsigned int opentype_layout_find_script(const struct scriptshaping_cache
*cache
, unsigned int kind
, DWORD script
,
3171 unsigned int *script_index
)
3173 const struct ot_gsubgpos_table
*table
= kind
== MS_GSUB_TAG
? &cache
->gsub
: &cache
->gpos
;
3174 UINT16 script_count
;
3177 *script_index
= ~0u;
3179 script_count
= table_read_be_word(&table
->table
, table
->script_list
);
3183 for (i
= 0; i
< script_count
; i
++)
3185 unsigned int tag
= table_read_dword(&table
->table
, table
->script_list
+ FIELD_OFFSET(struct ot_script_list
, scripts
) +
3186 i
* sizeof(struct ot_script_record
));
3200 unsigned int opentype_layout_find_language(const struct scriptshaping_cache
*cache
, unsigned int kind
, DWORD language
,
3201 unsigned int script_index
, unsigned int *language_index
)
3203 const struct ot_gsubgpos_table
*table
= kind
== MS_GSUB_TAG
? &cache
->gsub
: &cache
->gpos
;
3204 UINT16 table_offset
, lang_count
;
3207 *language_index
= ~0u;
3209 table_offset
= table_read_be_word(&table
->table
, table
->script_list
+ FIELD_OFFSET(struct ot_script_list
, scripts
) +
3210 script_index
* sizeof(struct ot_script_record
) + FIELD_OFFSET(struct ot_script_record
, script
));
3214 lang_count
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
+
3215 FIELD_OFFSET(struct ot_script
, langsys_count
));
3216 for (i
= 0; i
< lang_count
; i
++)
3218 unsigned int tag
= table_read_dword(&table
->table
, table
->script_list
+ table_offset
+
3219 FIELD_OFFSET(struct ot_script
, langsys
) + i
* sizeof(struct ot_langsys_record
));
3221 if (tag
== language
)
3223 *language_index
= i
;
3228 /* Try 'defaultLangSys' if it's set. */
3229 if (table_read_be_word(&table
->table
, table
->script_list
+ table_offset
))
3235 static int gdef_class_compare_format2(const void *g
, const void *r
)
3237 const struct ot_gdef_class_range
*range
= r
;
3238 UINT16 glyph
= *(UINT16
*)g
;
3240 if (glyph
< GET_BE_WORD(range
->start_glyph
))
3242 else if (glyph
> GET_BE_WORD(range
->end_glyph
))
3248 static unsigned int opentype_layout_get_glyph_class(const struct dwrite_fonttable
*table
,
3249 unsigned int offset
, UINT16 glyph
)
3251 WORD format
= table_read_be_word(table
, offset
), count
;
3252 unsigned int glyph_class
= GDEF_CLASS_UNCLASSIFIED
;
3256 const struct ot_gdef_classdef_format1
*format1
;
3258 count
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gdef_classdef_format1
, glyph_count
));
3259 format1
= table_read_ensure(table
, offset
, FIELD_OFFSET(struct ot_gdef_classdef_format1
, classes
[count
]));
3262 WORD start_glyph
= GET_BE_WORD(format1
->start_glyph
);
3263 if (glyph
>= start_glyph
&& (glyph
- start_glyph
) < count
)
3265 glyph_class
= GET_BE_WORD(format1
->classes
[glyph
- start_glyph
]);
3266 if (glyph_class
> GDEF_CLASS_MAX
)
3267 glyph_class
= GDEF_CLASS_UNCLASSIFIED
;
3271 else if (format
== 2)
3273 const struct ot_gdef_classdef_format2
*format2
;
3275 count
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gdef_classdef_format2
, range_count
));
3276 format2
= table_read_ensure(table
, offset
, FIELD_OFFSET(struct ot_gdef_classdef_format2
, ranges
[count
]));
3279 const struct ot_gdef_class_range
*range
= bsearch(&glyph
, format2
->ranges
, count
,
3280 sizeof(struct ot_gdef_class_range
), gdef_class_compare_format2
);
3281 glyph_class
= range
&& glyph
<= GET_BE_WORD(range
->end_glyph
) ?
3282 GET_BE_WORD(range
->glyph_class
) : GDEF_CLASS_UNCLASSIFIED
;
3283 if (glyph_class
> GDEF_CLASS_MAX
)
3284 glyph_class
= GDEF_CLASS_UNCLASSIFIED
;
3288 WARN("Unknown GDEF format %u.\n", format
);
3293 static unsigned int opentype_set_glyph_props(struct scriptshaping_context
*context
, unsigned int idx
)
3295 struct scriptshaping_cache
*cache
= context
->cache
;
3296 unsigned int glyph_class
= 0, props
;
3298 if (cache
->gdef
.classdef
)
3300 glyph_class
= opentype_layout_get_glyph_class(&cache
->gdef
.table
, cache
->gdef
.classdef
,
3301 context
->u
.buffer
.glyphs
[idx
]);
3304 switch (glyph_class
)
3306 case GDEF_CLASS_BASE
:
3307 props
= GLYPH_PROP_BASE
;
3309 case GDEF_CLASS_LIGATURE
:
3310 props
= GLYPH_PROP_LIGATURE
;
3312 case GDEF_CLASS_MARK
:
3313 props
= GLYPH_PROP_MARK
;
3314 if (cache
->gdef
.markattachclassdef
)
3316 glyph_class
= opentype_layout_get_glyph_class(&cache
->gdef
.table
, cache
->gdef
.markattachclassdef
,
3317 context
->u
.buffer
.glyphs
[idx
]);
3318 props
|= glyph_class
<< 8;
3325 context
->glyph_infos
[idx
].props
= props
;
3330 static void opentype_set_subst_glyph_props(struct scriptshaping_context
*context
, unsigned int idx
)
3332 unsigned int glyph_props
= opentype_set_glyph_props(context
, idx
) & LOOKUP_FLAG_IGNORE_MASK
;
3333 context
->u
.subst
.glyph_props
[idx
].isDiacritic
= !!(glyph_props
== GLYPH_PROP_MARK
);
3334 context
->u
.subst
.glyph_props
[idx
].isZeroWidthSpace
= !!(glyph_props
== GLYPH_PROP_MARK
);
3337 struct coverage_compare_format1_context
3340 const UINT16
*table_base
;
3341 unsigned int *coverage_index
;
3344 static int coverage_compare_format1(const void *left
, const void *right
)
3346 const struct coverage_compare_format1_context
*context
= left
;
3347 UINT16 glyph
= GET_BE_WORD(*(UINT16
*)right
);
3350 ret
= context
->glyph
- glyph
;
3352 *context
->coverage_index
= (UINT16
*)right
- context
->table_base
;
3357 static int coverage_compare_format2(const void *g
, const void *r
)
3359 const struct ot_coverage_range
*range
= r
;
3360 UINT16 glyph
= *(UINT16
*)g
;
3362 if (glyph
< GET_BE_WORD(range
->start_glyph
))
3364 else if (glyph
> GET_BE_WORD(range
->end_glyph
))
3370 static unsigned int opentype_layout_is_glyph_covered(const struct dwrite_fonttable
*table
, unsigned int coverage
,
3373 WORD format
= table_read_be_word(table
, coverage
), count
;
3375 count
= table_read_be_word(table
, coverage
+ 2);
3379 const struct ot_coverage_format1
*format1
= table_read_ensure(table
, coverage
,
3380 FIELD_OFFSET(struct ot_coverage_format1
, glyphs
[count
]));
3381 struct coverage_compare_format1_context context
;
3382 unsigned int coverage_index
= GLYPH_NOT_COVERED
;
3386 context
.glyph
= glyph
;
3387 context
.table_base
= format1
->glyphs
;
3388 context
.coverage_index
= &coverage_index
;
3390 bsearch(&context
, format1
->glyphs
, count
, sizeof(glyph
), coverage_compare_format1
);
3393 return coverage_index
;
3395 else if (format
== 2)
3397 const struct ot_coverage_format2
*format2
= table_read_ensure(table
, coverage
,
3398 FIELD_OFFSET(struct ot_coverage_format2
, ranges
[count
]));
3401 const struct ot_coverage_range
*range
= bsearch(&glyph
, format2
->ranges
, count
,
3402 sizeof(struct ot_coverage_range
), coverage_compare_format2
);
3403 return range
&& glyph
<= GET_BE_WORD(range
->end_glyph
) ?
3404 GET_BE_WORD(range
->startcoverage_index
) + glyph
- GET_BE_WORD(range
->start_glyph
) :
3409 WARN("Unknown coverage format %u.\n", format
);
3414 static inline unsigned int dwrite_popcount(unsigned int x
)
3416 #ifdef HAVE___BUILTIN_POPCOUNT
3417 return __builtin_popcount(x
);
3419 x
-= x
>> 1 & 0x55555555;
3420 x
= (x
& 0x33333333) + (x
>> 2 & 0x33333333);
3421 return ((x
+ (x
>> 4)) & 0x0f0f0f0f) * 0x01010101 >> 24;
3425 static float opentype_scale_gpos_be_value(WORD value
, float emsize
, UINT16 upem
)
3427 return (short)GET_BE_WORD(value
) * emsize
/ upem
;
3430 static int opentype_layout_gpos_get_dev_value(const struct scriptshaping_context
*context
, unsigned int offset
)
3432 const struct dwrite_fonttable
*table
= &context
->table
->table
;
3433 unsigned int start_size
, end_size
, format
, value_word
;
3434 unsigned int index
, ppem
, mask
;
3440 start_size
= table_read_be_word(table
, offset
);
3441 end_size
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gpos_device_table
, end_size
));
3443 ppem
= context
->emsize
;
3444 if (ppem
< start_size
|| ppem
> end_size
)
3447 format
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gpos_device_table
, format
));
3449 if (format
< 1 || format
> 3)
3452 index
= ppem
- start_size
;
3454 value_word
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gpos_device_table
, values
[index
>> (4 - format
)]));
3455 mask
= 0xffff >> (16 - (1 << format
));
3457 value
= (value_word
>> ((index
% (4 - format
)) * (1 << format
))) & mask
;
3459 if ((unsigned int)value
>= ((mask
+ 1) >> 1))
3465 static void opentype_layout_apply_gpos_value(struct scriptshaping_context
*context
, unsigned int table_offset
,
3466 WORD value_format
, const WORD
*values
, unsigned int glyph
)
3468 const struct scriptshaping_cache
*cache
= context
->cache
;
3469 DWRITE_GLYPH_OFFSET
*offset
= &context
->offsets
[glyph
];
3470 float *advance
= &context
->advances
[glyph
];
3475 if (value_format
& GPOS_VALUE_X_PLACEMENT
)
3477 offset
->advanceOffset
+= opentype_scale_gpos_be_value(*values
, context
->emsize
, cache
->upem
);
3480 if (value_format
& GPOS_VALUE_Y_PLACEMENT
)
3482 offset
->ascenderOffset
+= opentype_scale_gpos_be_value(*values
, context
->emsize
, cache
->upem
);
3485 if (value_format
& GPOS_VALUE_X_ADVANCE
)
3487 *advance
+= opentype_scale_gpos_be_value(*values
, context
->emsize
, cache
->upem
);
3490 if (value_format
& GPOS_VALUE_Y_ADVANCE
)
3494 if (value_format
& GPOS_VALUE_X_PLACEMENT_DEVICE
)
3496 offset
->advanceOffset
+= opentype_layout_gpos_get_dev_value(context
, table_offset
+ GET_BE_WORD(*values
));
3499 if (value_format
& GPOS_VALUE_Y_PLACEMENT_DEVICE
)
3501 offset
->ascenderOffset
+= opentype_layout_gpos_get_dev_value(context
, table_offset
+ GET_BE_WORD(*values
));
3504 if (value_format
& GPOS_VALUE_X_ADVANCE_DEVICE
)
3506 *advance
+= opentype_layout_gpos_get_dev_value(context
, table_offset
+ GET_BE_WORD(*values
));
3509 if (value_format
& GPOS_VALUE_Y_ADVANCE_DEVICE
)
3517 unsigned short index
;
3518 unsigned short type
;
3519 unsigned short flags
;
3520 unsigned short subtable_count
;
3523 unsigned int offset
;
3524 unsigned int auto_zwnj
: 1;
3525 unsigned int auto_zwj
: 1;
3528 static unsigned int opentype_layout_get_gsubgpos_subtable(const struct scriptshaping_context
*context
,
3529 const struct lookup
*lookup
, unsigned int subtable
, unsigned int *lookup_type
)
3531 unsigned int subtable_offset
= table_read_be_word(&context
->table
->table
, lookup
->offset
+
3532 FIELD_OFFSET(struct ot_lookup_table
, subtable
[subtable
]));
3533 const struct ot_gsubgpos_extension_format1
*format1
;
3535 subtable_offset
+= lookup
->offset
;
3537 if ((context
->table
== &context
->cache
->gsub
&& lookup
->type
!= GSUB_LOOKUP_EXTENSION_SUBST
) ||
3538 (context
->table
== &context
->cache
->gpos
&& lookup
->type
!= GPOS_LOOKUP_EXTENSION_POSITION
))
3540 *lookup_type
= lookup
->type
;
3541 return subtable_offset
;
3546 if (!(format1
= table_read_ensure(&context
->table
->table
, subtable_offset
, sizeof(*format1
))))
3549 if (GET_BE_WORD(format1
->format
) != 1)
3551 WARN("Unexpected extension table format %#x.\n", format1
->format
);
3555 *lookup_type
= GET_BE_WORD(format1
->lookup_type
);
3556 return subtable_offset
+ GET_BE_DWORD(format1
->extension_offset
);
3561 unsigned int offset
;
3562 unsigned int subtable_count
;
3568 /* First two to fit matching callback result. */
3574 struct match_context
;
3577 const struct match_context
*mc
;
3578 unsigned int subtable_offset
;
3581 typedef BOOL (*p_match_func
)(UINT16 glyph
, UINT16 glyph_data
, const struct match_data
*match_data
);
3583 struct match_context
3585 struct scriptshaping_context
*context
;
3586 unsigned int backtrack_offset
;
3587 unsigned int input_offset
;
3588 unsigned int lookahead_offset
;
3589 p_match_func match_func
;
3590 const struct lookup
*lookup
;
3593 struct glyph_iterator
3595 struct scriptshaping_context
*context
;
3600 p_match_func match_func
;
3601 const UINT16
*glyph_data
;
3602 const struct match_data
*match_data
;
3603 unsigned int ignore_zwnj
;
3604 unsigned int ignore_zwj
;
3607 static void glyph_iterator_init(struct scriptshaping_context
*context
, unsigned int flags
, unsigned int pos
,
3608 unsigned int len
, struct glyph_iterator
*iter
)
3610 iter
->context
= context
;
3611 iter
->flags
= flags
;
3615 iter
->match_func
= NULL
;
3616 iter
->match_data
= NULL
;
3617 iter
->glyph_data
= NULL
;
3618 /* Context matching iterators will get these fixed up. */
3619 iter
->ignore_zwnj
= context
->table
== &context
->cache
->gpos
;
3620 iter
->ignore_zwj
= context
->auto_zwj
;
3623 struct ot_gdef_mark_glyph_sets
3630 static BOOL
opentype_match_glyph_func(UINT16 glyph
, UINT16 glyph_data
, const struct match_data
*data
)
3632 return glyph
== glyph_data
;
3635 static BOOL
opentype_match_class_func(UINT16 glyph
, UINT16 glyph_data
, const struct match_data
*data
)
3637 const struct match_context
*mc
= data
->mc
;
3638 UINT16 glyph_class
= opentype_layout_get_glyph_class(&mc
->context
->table
->table
, data
->subtable_offset
, glyph
);
3639 return glyph_class
== glyph_data
;
3642 static BOOL
opentype_match_coverage_func(UINT16 glyph
, UINT16 glyph_data
, const struct match_data
*data
)
3644 const struct match_context
*mc
= data
->mc
;
3645 return opentype_layout_is_glyph_covered(&mc
->context
->table
->table
, data
->subtable_offset
+ glyph_data
, glyph
)
3646 != GLYPH_NOT_COVERED
;
3649 static BOOL
opentype_layout_mark_set_covers(const struct scriptshaping_cache
*cache
, unsigned int set_index
,
3652 unsigned int format
, offset
= cache
->gdef
.markglyphsetdef
, coverage_offset
, set_count
;
3657 format
= table_read_be_word(&cache
->gdef
.table
, offset
);
3661 set_count
= table_read_be_word(&cache
->gdef
.table
, offset
+ 2);
3662 if (!set_count
|| set_index
>= set_count
)
3665 coverage_offset
= table_read_be_dword(&cache
->gdef
.table
, offset
+ 2 + set_index
* sizeof(coverage_offset
));
3666 return opentype_layout_is_glyph_covered(&cache
->gdef
.table
, offset
+ coverage_offset
, glyph
) != GLYPH_NOT_COVERED
;
3669 WARN("Unexpected MarkGlyphSets format %#x.\n", format
);
3674 static BOOL
lookup_is_glyph_match(const struct scriptshaping_context
*context
, unsigned int idx
, unsigned int match_props
)
3676 unsigned int glyph_props
= context
->glyph_infos
[idx
].props
;
3677 UINT16 glyph
= context
->u
.buffer
.glyphs
[idx
];
3679 if (glyph_props
& match_props
& LOOKUP_FLAG_IGNORE_MASK
)
3682 if (!(glyph_props
& GLYPH_PROP_MARK
))
3685 if (match_props
& LOOKUP_FLAG_USE_MARK_FILTERING_SET
)
3686 return opentype_layout_mark_set_covers(context
->cache
, match_props
>> 16, glyph
);
3688 if (match_props
& LOOKUP_FLAG_MARK_ATTACHMENT_TYPE
)
3689 return (match_props
& LOOKUP_FLAG_MARK_ATTACHMENT_TYPE
) == (glyph_props
& LOOKUP_FLAG_MARK_ATTACHMENT_TYPE
);
3694 static enum iterator_match
glyph_iterator_may_skip(const struct glyph_iterator
*iter
)
3696 unsigned int glyph_props
= iter
->context
->glyph_infos
[iter
->pos
].props
& (GLYPH_PROP_IGNORABLE
| GLYPH_PROP_HIDDEN
);
3698 if (!lookup_is_glyph_match(iter
->context
, iter
->pos
, iter
->flags
))
3701 if (glyph_props
== GLYPH_PROP_IGNORABLE
&& !iter
->context
->u
.buffer
.glyph_props
[iter
->pos
].components
&&
3702 (iter
->ignore_zwnj
|| !(iter
->context
->glyph_infos
[iter
->pos
].props
& GLYPH_PROP_ZWNJ
)) &&
3703 (iter
->ignore_zwj
|| !(iter
->context
->glyph_infos
[iter
->pos
].props
& GLYPH_PROP_ZWJ
)))
3711 static enum iterator_match
glyph_iterator_may_match(const struct glyph_iterator
*iter
)
3713 if (!(iter
->mask
& iter
->context
->glyph_infos
[iter
->pos
].mask
))
3716 /* Glyph data is used for input, backtrack, and lookahead arrays, swap it here instead of doing that
3717 in all matching functions. */
3718 if (iter
->match_func
)
3719 return !!iter
->match_func(iter
->context
->u
.buffer
.glyphs
[iter
->pos
], GET_BE_WORD(*iter
->glyph_data
), iter
->match_data
);
3724 static BOOL
glyph_iterator_next(struct glyph_iterator
*iter
)
3726 enum iterator_match skip
, match
;
3728 while (iter
->pos
+ iter
->len
< iter
->context
->glyph_count
)
3732 skip
= glyph_iterator_may_skip(iter
);
3733 if (skip
== ITER_YES
)
3736 match
= glyph_iterator_may_match(iter
);
3737 if (match
== ITER_YES
|| (match
== ITER_MAYBE
&& skip
== ITER_NO
))
3740 if (iter
->glyph_data
)
3745 if (skip
== ITER_NO
)
3752 static BOOL
glyph_iterator_prev(struct glyph_iterator
*iter
)
3754 enum iterator_match skip
, match
;
3756 while (iter
->pos
> iter
->len
- 1)
3760 skip
= glyph_iterator_may_skip(iter
);
3761 if (skip
== ITER_YES
)
3764 match
= glyph_iterator_may_match(iter
);
3765 if (match
== ITER_YES
|| (match
== ITER_MAYBE
&& skip
== ITER_NO
))
3768 if (iter
->glyph_data
)
3773 if (skip
== ITER_NO
)
3780 static BOOL
opentype_layout_apply_gpos_single_adjustment(struct scriptshaping_context
*context
,
3781 const struct lookup
*lookup
, unsigned int subtable_offset
)
3783 const struct dwrite_fonttable
*table
= &context
->table
->table
;
3784 UINT16 format
, value_format
, value_len
, coverage
, glyph
;
3786 unsigned int coverage_index
;
3788 format
= table_read_be_word(table
, subtable_offset
);
3790 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_singlepos_format1
, coverage
));
3791 value_format
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_singlepos_format1
, value_format
));
3792 value_len
= dwrite_popcount(value_format
);
3794 glyph
= context
->u
.pos
.glyphs
[context
->cur
];
3798 const struct ot_gpos_singlepos_format1
*format1
= table_read_ensure(table
, subtable_offset
,
3799 FIELD_OFFSET(struct ot_gpos_singlepos_format1
, value
[value_len
]));
3801 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
3802 if (coverage_index
== GLYPH_NOT_COVERED
)
3805 opentype_layout_apply_gpos_value(context
, subtable_offset
, value_format
, format1
->value
, context
->cur
);
3807 else if (format
== 2)
3809 WORD value_count
= table_read_be_word(table
, subtable_offset
+
3810 FIELD_OFFSET(struct ot_gpos_singlepos_format2
, value_count
));
3811 const struct ot_gpos_singlepos_format2
*format2
= table_read_ensure(table
, subtable_offset
,
3812 FIELD_OFFSET(struct ot_gpos_singlepos_format2
, values
) + value_count
* value_len
* sizeof(WORD
));
3814 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
3815 if (coverage_index
== GLYPH_NOT_COVERED
|| coverage_index
>= value_count
)
3818 opentype_layout_apply_gpos_value(context
, subtable_offset
, value_format
, &format2
->values
[coverage_index
* value_len
],
3823 WARN("Unknown single adjustment format %u.\n", format
);
3832 static int gpos_pair_adjustment_compare_format1(const void *g
, const void *r
)
3834 const struct ot_gpos_pairvalue
*pairvalue
= r
;
3835 UINT16 second_glyph
= GET_BE_WORD(pairvalue
->second_glyph
);
3836 return *(UINT16
*)g
- second_glyph
;
3839 static BOOL
opentype_layout_apply_gpos_pair_adjustment(struct scriptshaping_context
*context
,
3840 const struct lookup
*lookup
, unsigned int subtable_offset
)
3842 const struct dwrite_fonttable
*table
= &context
->table
->table
;
3843 unsigned int first_glyph
, second_glyph
;
3844 struct glyph_iterator iter_pair
;
3845 WORD format
, coverage
;
3847 WORD value_format1
, value_format2
, value_len1
, value_len2
;
3848 unsigned int coverage_index
;
3850 glyph_iterator_init(context
, lookup
->flags
, context
->cur
, 1, &iter_pair
);
3851 if (!glyph_iterator_next(&iter_pair
))
3854 if (context
->is_rtl
)
3856 first_glyph
= iter_pair
.pos
;
3857 second_glyph
= context
->cur
;
3861 first_glyph
= context
->cur
;
3862 second_glyph
= iter_pair
.pos
;
3865 format
= table_read_be_word(table
, subtable_offset
);
3867 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_pairpos_format1
, coverage
));
3871 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, context
->u
.pos
.glyphs
[first_glyph
]);
3872 if (coverage_index
== GLYPH_NOT_COVERED
)
3877 const struct ot_gpos_pairpos_format1
*format1
;
3878 WORD pairset_count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_pairpos_format1
,
3880 unsigned int pairvalue_len
, pairset_offset
;
3881 const struct ot_gpos_pairset
*pairset
;
3882 const WORD
*pairvalue
;
3883 WORD pairvalue_count
;
3885 if (!pairset_count
|| coverage_index
>= pairset_count
)
3888 format1
= table_read_ensure(table
, subtable_offset
, FIELD_OFFSET(struct ot_gpos_pairpos_format1
, pairsets
[pairset_count
]));
3892 /* Ordered paired values. */
3893 pairvalue_count
= table_read_be_word(table
, subtable_offset
+ GET_BE_WORD(format1
->pairsets
[coverage_index
]));
3894 if (!pairvalue_count
)
3897 /* Structure length is variable, but does not change across the subtable. */
3898 value_format1
= GET_BE_WORD(format1
->value_format1
) & 0xff;
3899 value_format2
= GET_BE_WORD(format1
->value_format2
) & 0xff;
3901 value_len1
= dwrite_popcount(value_format1
);
3902 value_len2
= dwrite_popcount(value_format2
);
3903 pairvalue_len
= FIELD_OFFSET(struct ot_gpos_pairvalue
, data
) + value_len1
* sizeof(WORD
) +
3904 value_len2
* sizeof(WORD
);
3906 pairset_offset
= subtable_offset
+ GET_BE_WORD(format1
->pairsets
[coverage_index
]);
3907 pairset
= table_read_ensure(table
, subtable_offset
+ pairset_offset
, pairvalue_len
* pairvalue_count
);
3911 pairvalue
= bsearch(&context
->u
.pos
.glyphs
[second_glyph
], pairset
->pairvalues
, pairvalue_count
,
3912 pairvalue_len
, gpos_pair_adjustment_compare_format1
);
3916 pairvalue
+= 1; /* Skip SecondGlyph. */
3917 opentype_layout_apply_gpos_value(context
, pairset_offset
, value_format1
, pairvalue
, first_glyph
);
3918 opentype_layout_apply_gpos_value(context
, pairset_offset
, value_format2
, pairvalue
+ value_len1
,
3921 context
->cur
= iter_pair
.pos
;
3925 else if (format
== 2)
3927 const struct ot_gpos_pairpos_format2
*format2
;
3928 WORD class1_count
, class2_count
;
3929 unsigned int class1
, class2
;
3930 const WCHAR
*values
;
3932 value_format1
= table_read_be_word(table
, subtable_offset
+
3933 FIELD_OFFSET(struct ot_gpos_pairpos_format2
, value_format1
)) & 0xff;
3934 value_format2
= table_read_be_word(table
, subtable_offset
+
3935 FIELD_OFFSET(struct ot_gpos_pairpos_format2
, value_format2
)) & 0xff;
3937 class1_count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_pairpos_format2
, class1_count
));
3938 class2_count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_pairpos_format2
, class2_count
));
3940 value_len1
= dwrite_popcount(value_format1
);
3941 value_len2
= dwrite_popcount(value_format2
);
3943 format2
= table_read_ensure(table
, subtable_offset
, FIELD_OFFSET(struct ot_gpos_pairpos_format2
,
3944 values
[class1_count
* class2_count
* (value_len1
+ value_len2
)]));
3948 class1
= opentype_layout_get_glyph_class(table
, subtable_offset
+ GET_BE_WORD(format2
->class_def1
),
3949 context
->u
.pos
.glyphs
[first_glyph
]);
3950 class2
= opentype_layout_get_glyph_class(table
, subtable_offset
+ GET_BE_WORD(format2
->class_def2
),
3951 context
->u
.pos
.glyphs
[second_glyph
]);
3953 if (!(class1
< class1_count
&& class2
< class2_count
))
3956 values
= &format2
->values
[(class1
* class2_count
+ class2
) * (value_len1
+ value_len2
)];
3957 opentype_layout_apply_gpos_value(context
, subtable_offset
, value_format1
, values
, first_glyph
);
3958 opentype_layout_apply_gpos_value(context
, subtable_offset
, value_format2
, values
+ value_len1
,
3961 context
->cur
= iter_pair
.pos
;
3967 WARN("Unknown pair adjustment format %u.\n", format
);
3974 static void opentype_layout_gpos_get_anchor(const struct scriptshaping_context
*context
, unsigned int anchor_offset
,
3975 unsigned int glyph_index
, float *x
, float *y
)
3977 const struct scriptshaping_cache
*cache
= context
->cache
;
3978 const struct dwrite_fonttable
*table
= &context
->table
->table
;
3980 WORD format
= table_read_be_word(table
, anchor_offset
);
3986 const struct ot_gpos_anchor_format1
*format1
= table_read_ensure(table
, anchor_offset
, sizeof(*format1
));
3990 *x
= opentype_scale_gpos_be_value(format1
->x_coord
, context
->emsize
, cache
->upem
);
3991 *y
= opentype_scale_gpos_be_value(format1
->y_coord
, context
->emsize
, cache
->upem
);
3994 else if (format
== 2)
3996 const struct ot_gpos_anchor_format2
*format2
= table_read_ensure(table
, anchor_offset
, sizeof(*format2
));
4000 if (context
->measuring_mode
!= DWRITE_MEASURING_MODE_NATURAL
)
4001 FIXME("Use outline anchor point for glyph %u.\n", context
->u
.pos
.glyphs
[glyph_index
]);
4003 *x
= opentype_scale_gpos_be_value(format2
->x_coord
, context
->emsize
, cache
->upem
);
4004 *y
= opentype_scale_gpos_be_value(format2
->y_coord
, context
->emsize
, cache
->upem
);
4007 else if (format
== 3)
4009 const struct ot_gpos_anchor_format3
*format3
= table_read_ensure(table
, anchor_offset
, sizeof(*format3
));
4013 *x
= opentype_scale_gpos_be_value(format3
->x_coord
, context
->emsize
, cache
->upem
);
4014 *y
= opentype_scale_gpos_be_value(format3
->y_coord
, context
->emsize
, cache
->upem
);
4016 if (context
->measuring_mode
!= DWRITE_MEASURING_MODE_NATURAL
)
4018 if (format3
->x_dev_offset
)
4019 *x
+= opentype_layout_gpos_get_dev_value(context
, anchor_offset
+ GET_BE_WORD(format3
->x_dev_offset
));
4020 if (format3
->y_dev_offset
)
4021 *y
+= opentype_layout_gpos_get_dev_value(context
, anchor_offset
+ GET_BE_WORD(format3
->y_dev_offset
));
4026 WARN("Unknown anchor format %u.\n", format
);
4029 static BOOL
opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_context
*context
,
4030 const struct lookup
*lookup
, unsigned int subtable_offset
)
4032 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4033 UINT16 format
, glyph
;
4035 format
= table_read_be_word(table
, subtable_offset
);
4036 glyph
= context
->u
.pos
.glyphs
[context
->cur
];
4040 WORD coverage_offset
= table_read_be_word(table
, subtable_offset
+
4041 FIELD_OFFSET(struct ot_gpos_cursive_format1
, coverage
));
4042 unsigned int glyph_index
, entry_count
, entry_anchor
, exit_anchor
;
4043 float entry_x
, entry_y
, exit_x
, exit_y
, delta
;
4044 struct glyph_iterator prev_iter
;
4046 if (!coverage_offset
)
4049 entry_count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_cursive_format1
, count
));
4051 glyph_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage_offset
, glyph
);
4052 if (glyph_index
== GLYPH_NOT_COVERED
|| glyph_index
>= entry_count
)
4055 entry_anchor
= table_read_be_word(table
, subtable_offset
+
4056 FIELD_OFFSET(struct ot_gpos_cursive_format1
, anchors
[glyph_index
* 2]));
4060 glyph_iterator_init(context
, lookup
->flags
, context
->cur
, 1, &prev_iter
);
4061 if (!glyph_iterator_prev(&prev_iter
))
4064 glyph_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage_offset
,
4065 context
->u
.pos
.glyphs
[prev_iter
.pos
]);
4066 if (glyph_index
== GLYPH_NOT_COVERED
|| glyph_index
>= entry_count
)
4069 exit_anchor
= table_read_be_word(table
, subtable_offset
+
4070 FIELD_OFFSET(struct ot_gpos_cursive_format1
, anchors
[glyph_index
* 2 + 1]));
4074 opentype_layout_gpos_get_anchor(context
, subtable_offset
+ exit_anchor
, prev_iter
.pos
, &exit_x
, &exit_y
);
4075 opentype_layout_gpos_get_anchor(context
, subtable_offset
+ entry_anchor
, context
->cur
, &entry_x
, &entry_y
);
4077 if (context
->is_rtl
)
4079 delta
= exit_x
+ context
->offsets
[prev_iter
.pos
].advanceOffset
;
4080 context
->advances
[prev_iter
.pos
] -= delta
;
4081 context
->advances
[context
->cur
] = entry_x
+ context
->offsets
[context
->cur
].advanceOffset
;
4082 context
->offsets
[prev_iter
.pos
].advanceOffset
-= delta
;
4086 delta
= entry_x
+ context
->offsets
[context
->cur
].advanceOffset
;
4087 context
->advances
[prev_iter
.pos
] = exit_x
+ context
->offsets
[prev_iter
.pos
].advanceOffset
;
4088 context
->advances
[context
->cur
] -= delta
;
4089 context
->offsets
[context
->cur
].advanceOffset
-= delta
;
4092 if (lookup
->flags
& LOOKUP_FLAG_RTL
)
4093 context
->offsets
[prev_iter
.pos
].ascenderOffset
= entry_y
- exit_y
;
4095 context
->offsets
[context
->cur
].ascenderOffset
= exit_y
- entry_y
;
4101 WARN("Unknown cursive attachment format %u.\n", format
);
4108 static BOOL
opentype_layout_apply_mark_array(struct scriptshaping_context
*context
, unsigned int subtable_offset
,
4109 unsigned int mark_array
, unsigned int mark_index
, unsigned int glyph_index
, unsigned int anchors_matrix
,
4110 unsigned int class_count
, unsigned int glyph_pos
)
4112 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4113 unsigned int mark_class
, mark_count
, glyph_count
;
4114 const struct ot_gpos_mark_record
*record
;
4115 float mark_x
, mark_y
, base_x
, base_y
;
4116 const UINT16
*anchors
;
4118 mark_count
= table_read_be_word(table
, subtable_offset
+ mark_array
);
4119 if (mark_index
>= mark_count
) return FALSE
;
4121 if (!(record
= table_read_ensure(table
, subtable_offset
+ mark_array
+
4122 FIELD_OFFSET(struct ot_gpos_mark_array
, records
[mark_index
]), sizeof(*record
))))
4127 mark_class
= GET_BE_WORD(record
->mark_class
);
4128 if (mark_class
>= class_count
) return FALSE
;
4130 glyph_count
= table_read_be_word(table
, subtable_offset
+ anchors_matrix
);
4131 if (glyph_index
>= glyph_count
) return FALSE
;
4133 /* Anchors data is stored as two dimensional array [glyph_count][class_count], starting with row count field. */
4134 anchors
= table_read_ensure(table
, subtable_offset
+ anchors_matrix
+ 2, glyph_count
* class_count
* sizeof(*anchors
));
4135 if (!anchors
) return FALSE
;
4137 opentype_layout_gpos_get_anchor(context
, subtable_offset
+ mark_array
+ GET_BE_WORD(record
->mark_anchor
),
4138 context
->cur
, &mark_x
, &mark_y
);
4139 opentype_layout_gpos_get_anchor(context
, subtable_offset
+ anchors_matrix
+
4140 GET_BE_WORD(anchors
[glyph_index
* class_count
+ mark_class
]), glyph_pos
, &base_x
, &base_y
);
4142 if (context
->is_rtl
)
4143 context
->offsets
[context
->cur
].advanceOffset
= mark_x
- base_x
;
4145 context
->offsets
[context
->cur
].advanceOffset
= -context
->advances
[glyph_pos
] + base_x
- mark_x
;
4147 context
->offsets
[context
->cur
].ascenderOffset
= base_y
- mark_y
;
4153 static BOOL
opentype_layout_apply_gpos_mark_to_base_attachment(struct scriptshaping_context
*context
,
4154 const struct lookup
*lookup
, unsigned int subtable_offset
)
4156 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4159 format
= table_read_be_word(table
, subtable_offset
);
4163 const struct ot_gpos_mark_to_base_format1
*format1
;
4164 unsigned int base_index
, mark_index
;
4165 struct glyph_iterator base_iter
;
4167 if (!(format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
)))) return FALSE
;
4169 mark_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->mark_coverage
),
4170 context
->u
.pos
.glyphs
[context
->cur
]);
4171 if (mark_index
== GLYPH_NOT_COVERED
) return FALSE
;
4173 /* Look back for first base glyph. */
4174 glyph_iterator_init(context
, LOOKUP_FLAG_IGNORE_MARKS
, context
->cur
, 1, &base_iter
);
4175 if (!glyph_iterator_prev(&base_iter
))
4178 base_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->base_coverage
),
4179 context
->u
.pos
.glyphs
[base_iter
.pos
]);
4180 if (base_index
== GLYPH_NOT_COVERED
) return FALSE
;
4182 return opentype_layout_apply_mark_array(context
, subtable_offset
, GET_BE_WORD(format1
->mark_array
), mark_index
,
4183 base_index
, GET_BE_WORD(format1
->base_array
), GET_BE_WORD(format1
->mark_class_count
), base_iter
.pos
);
4187 WARN("Unknown mark-to-base format %u.\n", format
);
4194 static const UINT16
* table_read_array_be_word(const struct dwrite_fonttable
*table
, unsigned int offset
,
4195 unsigned int index
, UINT16
*data
)
4197 unsigned int count
= table_read_be_word(table
, offset
);
4198 const UINT16
*array
;
4200 if (index
!= ~0u && index
>= count
) return NULL
;
4201 if (!(array
= table_read_ensure(table
, offset
+ 2, count
* sizeof(*array
)))) return FALSE
;
4202 *data
= index
== ~0u ? count
: GET_BE_WORD(array
[index
]);
4206 static BOOL
opentype_layout_apply_gpos_mark_to_lig_attachment(struct scriptshaping_context
*context
,
4207 const struct lookup
*lookup
, unsigned int subtable_offset
)
4209 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4212 format
= table_read_be_word(table
, subtable_offset
);
4216 unsigned int mark_index
, lig_index
, comp_index
, class_count
, comp_count
;
4217 const struct ot_gpos_mark_to_lig_format1
*format1
;
4218 struct glyph_iterator lig_iter
;
4219 unsigned int lig_array
;
4222 if (!(format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
)))) return FALSE
;
4224 mark_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->mark_coverage
),
4225 context
->u
.pos
.glyphs
[context
->cur
]);
4226 if (mark_index
== GLYPH_NOT_COVERED
) return FALSE
;
4228 glyph_iterator_init(context
, LOOKUP_FLAG_IGNORE_MARKS
, context
->cur
, 1, &lig_iter
);
4229 if (!glyph_iterator_prev(&lig_iter
))
4232 lig_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->lig_coverage
),
4233 context
->u
.pos
.glyphs
[lig_iter
.pos
]);
4234 if (lig_index
== GLYPH_NOT_COVERED
) return FALSE
;
4236 class_count
= GET_BE_WORD(format1
->mark_class_count
);
4238 lig_array
= GET_BE_WORD(format1
->lig_array
);
4240 if (!table_read_array_be_word(table
, subtable_offset
+ lig_array
, lig_index
, &lig_attach
)) return FALSE
;
4242 comp_count
= table_read_be_word(table
, subtable_offset
+ lig_array
+ lig_attach
);
4243 if (!comp_count
) return FALSE
;
4245 comp_index
= context
->u
.buffer
.glyph_props
[lig_iter
.pos
].components
-
4246 context
->u
.buffer
.glyph_props
[context
->cur
].lig_component
- 1;
4247 if (comp_index
>= comp_count
) return FALSE
;
4249 return opentype_layout_apply_mark_array(context
, subtable_offset
, GET_BE_WORD(format1
->mark_array
), mark_index
,
4250 comp_index
, lig_array
+ lig_attach
, class_count
, lig_iter
.pos
);
4253 WARN("Unknown mark-to-ligature format %u.\n", format
);
4258 static BOOL
opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshaping_context
*context
,
4259 const struct lookup
*lookup
, unsigned int subtable_offset
)
4261 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4264 format
= table_read_be_word(table
, subtable_offset
);
4268 const struct ot_gpos_mark_to_mark_format1
*format1
;
4269 unsigned int mark1_index
, mark2_index
;
4270 struct glyph_iterator mark_iter
;
4272 if (!(format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
)))) return FALSE
;
4274 mark1_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->mark1_coverage
),
4275 context
->u
.pos
.glyphs
[context
->cur
]);
4276 if (mark1_index
== GLYPH_NOT_COVERED
) return FALSE
;
4278 glyph_iterator_init(context
, lookup
->flags
& ~LOOKUP_FLAG_IGNORE_MASK
, context
->cur
, 1, &mark_iter
);
4279 if (!glyph_iterator_prev(&mark_iter
))
4282 if (!context
->u
.pos
.glyph_props
[mark_iter
.pos
].isDiacritic
)
4285 mark2_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->mark2_coverage
),
4286 context
->u
.pos
.glyphs
[mark_iter
.pos
]);
4287 if (mark2_index
== GLYPH_NOT_COVERED
) return FALSE
;
4289 return opentype_layout_apply_mark_array(context
, subtable_offset
, GET_BE_WORD(format1
->mark1_array
), mark1_index
,
4290 mark2_index
, GET_BE_WORD(format1
->mark2_array
), GET_BE_WORD(format1
->mark_class_count
), mark_iter
.pos
);
4294 WARN("Unknown mark-to-mark format %u.\n", format
);
4301 static BOOL
opentype_layout_apply_context(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4302 unsigned int subtable_offset
);
4303 static BOOL
opentype_layout_apply_chain_context(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4304 unsigned int subtable_offset
);
4306 static BOOL
opentype_layout_apply_gpos_lookup(struct scriptshaping_context
*context
, const struct lookup
*lookup
)
4308 unsigned int i
, lookup_type
;
4311 for (i
= 0; i
< lookup
->subtable_count
; ++i
)
4313 unsigned int subtable_offset
= opentype_layout_get_gsubgpos_subtable(context
, lookup
, i
, &lookup_type
);
4315 switch (lookup_type
)
4317 case GPOS_LOOKUP_SINGLE_ADJUSTMENT
:
4318 ret
= opentype_layout_apply_gpos_single_adjustment(context
, lookup
, subtable_offset
);
4320 case GPOS_LOOKUP_PAIR_ADJUSTMENT
:
4321 ret
= opentype_layout_apply_gpos_pair_adjustment(context
, lookup
, subtable_offset
);
4323 case GPOS_LOOKUP_CURSIVE_ATTACHMENT
:
4324 ret
= opentype_layout_apply_gpos_cursive_attachment(context
, lookup
, subtable_offset
);
4326 case GPOS_LOOKUP_MARK_TO_BASE_ATTACHMENT
:
4327 ret
= opentype_layout_apply_gpos_mark_to_base_attachment(context
, lookup
, subtable_offset
);
4329 case GPOS_LOOKUP_MARK_TO_LIGATURE_ATTACHMENT
:
4330 ret
= opentype_layout_apply_gpos_mark_to_lig_attachment(context
, lookup
, subtable_offset
);
4332 case GPOS_LOOKUP_MARK_TO_MARK_ATTACHMENT
:
4333 ret
= opentype_layout_apply_gpos_mark_to_mark_attachment(context
, lookup
, subtable_offset
);
4335 case GPOS_LOOKUP_CONTEXTUAL_POSITION
:
4336 ret
= opentype_layout_apply_context(context
, lookup
, subtable_offset
);
4338 case GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION
:
4339 ret
= opentype_layout_apply_chain_context(context
, lookup
, subtable_offset
);
4341 case GPOS_LOOKUP_EXTENSION_POSITION
:
4342 WARN("Recursive extension lookup.\n");
4345 WARN("Unknown lookup type %u.\n", lookup_type
);
4357 struct lookup
*lookups
;
4362 static int lookups_sorting_compare(const void *a
, const void *b
)
4364 const struct lookup
*left
= (const struct lookup
*)a
;
4365 const struct lookup
*right
= (const struct lookup
*)b
;
4366 return left
->index
< right
->index
? -1 : left
->index
> right
->index
? 1 : 0;
4369 static BOOL
opentype_layout_init_lookup(const struct ot_gsubgpos_table
*table
, unsigned short lookup_index
,
4370 const struct shaping_feature
*feature
, struct lookup
*lookup
)
4372 unsigned short subtable_count
, lookup_type
, flags
, mark_filtering_set
;
4373 const struct ot_lookup_table
*lookup_table
;
4374 unsigned int offset
;
4376 if (!(offset
= table_read_be_word(&table
->table
, table
->lookup_list
+
4377 FIELD_OFFSET(struct ot_lookup_list
, lookup
[lookup_index
]))))
4382 offset
+= table
->lookup_list
;
4384 if (!(lookup_table
= table_read_ensure(&table
->table
, offset
, sizeof(*lookup_table
))))
4387 if (!(subtable_count
= GET_BE_WORD(lookup_table
->subtable_count
)))
4390 lookup_type
= GET_BE_WORD(lookup_table
->lookup_type
);
4391 flags
= GET_BE_WORD(lookup_table
->flags
);
4393 if (flags
& LOOKUP_FLAG_USE_MARK_FILTERING_SET
)
4395 mark_filtering_set
= table_read_be_word(&table
->table
, offset
+
4396 FIELD_OFFSET(struct ot_lookup_table
, subtable
[subtable_count
]));
4397 flags
|= mark_filtering_set
<< 16;
4400 lookup
->index
= lookup_index
;
4401 lookup
->type
= lookup_type
;
4402 lookup
->flags
= flags
;
4403 lookup
->subtable_count
= subtable_count
;
4404 lookup
->offset
= offset
;
4407 lookup
->mask
= feature
->mask
;
4408 lookup
->auto_zwnj
= !(feature
->flags
& FEATURE_MANUAL_ZWNJ
);
4409 lookup
->auto_zwj
= !(feature
->flags
& FEATURE_MANUAL_ZWJ
);
4415 static void opentype_layout_add_lookups(const struct ot_feature_list
*feature_list
, UINT16 total_lookup_count
,
4416 const struct ot_gsubgpos_table
*table
, struct shaping_feature
*feature
, struct lookups
*lookups
)
4418 UINT16 feature_offset
, lookup_count
;
4421 /* Feature wasn't found */
4422 if (feature
->index
== 0xffff)
4425 feature_offset
= GET_BE_WORD(feature_list
->features
[feature
->index
].offset
);
4427 lookup_count
= table_read_be_word(&table
->table
, table
->feature_list
+ feature_offset
+
4428 FIELD_OFFSET(struct ot_feature
, lookup_count
));
4432 if (!dwrite_array_reserve((void **)&lookups
->lookups
, &lookups
->capacity
, lookups
->count
+ lookup_count
,
4433 sizeof(*lookups
->lookups
)))
4438 for (i
= 0; i
< lookup_count
; ++i
)
4440 UINT16 lookup_index
= table_read_be_word(&table
->table
, table
->feature_list
+ feature_offset
+
4441 FIELD_OFFSET(struct ot_feature
, lookuplist_index
[i
]));
4443 if (lookup_index
>= total_lookup_count
)
4446 if (opentype_layout_init_lookup(table
, lookup_index
, feature
, &lookups
->lookups
[lookups
->count
]))
4451 static void opentype_layout_collect_lookups(struct scriptshaping_context
*context
, unsigned int script_index
,
4452 unsigned int language_index
, struct shaping_features
*features
, const struct ot_gsubgpos_table
*table
,
4453 struct lookups
*lookups
)
4455 unsigned int last_num_lookups
= 0, stage
, script_feature_count
= 0;
4456 UINT16 total_feature_count
, total_lookup_count
;
4457 struct shaping_feature required_feature
= { 0 };
4458 const struct ot_feature_list
*feature_list
;
4459 const struct ot_langsys
*langsys
= NULL
;
4460 struct shaping_feature
*feature
;
4461 unsigned int i
, j
, next_bit
;
4462 unsigned int global_bit_shift
= 1;
4463 unsigned int global_bit_mask
= 2;
4464 UINT16 feature_index
;
4466 if (!table
->table
.data
)
4469 if (script_index
!= ~0u)
4471 unsigned int table_offset
, langsys_offset
;
4473 /* ScriptTable offset. */
4474 table_offset
= table_read_be_word(&table
->table
, table
->script_list
+ FIELD_OFFSET(struct ot_script_list
, scripts
) +
4475 script_index
* sizeof(struct ot_script_record
) + FIELD_OFFSET(struct ot_script_record
, script
));
4479 if (language_index
== ~0u)
4480 langsys_offset
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
);
4482 langsys_offset
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
+
4483 FIELD_OFFSET(struct ot_script
, langsys
) + language_index
* sizeof(struct ot_langsys_record
) +
4484 FIELD_OFFSET(struct ot_langsys_record
, langsys
));
4485 langsys_offset
+= table
->script_list
+ table_offset
;
4487 script_feature_count
= table_read_be_word(&table
->table
, langsys_offset
+ FIELD_OFFSET(struct ot_langsys
, feature_count
));
4488 if (script_feature_count
)
4489 langsys
= table_read_ensure(&table
->table
, langsys_offset
,
4490 FIELD_OFFSET(struct ot_langsys
, feature_index
[script_feature_count
]));
4492 script_feature_count
= 0;
4495 total_feature_count
= table_read_be_word(&table
->table
, table
->feature_list
);
4496 if (!total_feature_count
)
4499 total_lookup_count
= table_read_be_word(&table
->table
, table
->lookup_list
);
4500 if (!total_lookup_count
)
4503 feature_list
= table_read_ensure(&table
->table
, table
->feature_list
,
4504 FIELD_OFFSET(struct ot_feature_list
, features
[total_feature_count
]));
4508 /* Required feature. */
4509 required_feature
.index
= langsys
? GET_BE_WORD(langsys
->required_feature_index
) : 0xffff;
4510 if (required_feature
.index
< total_feature_count
)
4511 required_feature
.tag
= feature_list
->features
[required_feature
.index
].tag
;
4512 required_feature
.mask
= global_bit_mask
;
4514 context
->global_mask
= global_bit_mask
;
4515 next_bit
= global_bit_shift
+ 1;
4516 for (i
= 0; i
< features
->count
; ++i
)
4518 unsigned int bits_needed
;
4521 feature
= &features
->features
[i
];
4523 feature
->index
= 0xffff;
4525 if ((feature
->flags
& FEATURE_GLOBAL
) && feature
->max_value
== 1)
4529 BitScanReverse(&bits_needed
, min(feature
->max_value
, 256));
4533 if (!feature
->max_value
|| next_bit
+ bits_needed
> 8 * sizeof (feature
->mask
))
4536 if (required_feature
.tag
== feature
->tag
)
4537 required_feature
.stage
= feature
->stage
;
4539 for (j
= 0; j
< script_feature_count
; ++j
)
4541 feature_index
= GET_BE_WORD(langsys
->feature_index
[j
]);
4542 if (feature_index
>= total_feature_count
)
4544 if ((found
= feature_list
->features
[feature_index
].tag
== feature
->tag
))
4546 feature
->index
= feature_index
;
4551 if (!found
&& (features
->features
[i
].flags
& FEATURE_GLOBAL_SEARCH
))
4553 for (j
= 0; j
< total_feature_count
; ++j
)
4555 if ((found
= (feature_list
->features
[j
].tag
== feature
->tag
)))
4563 if (!found
&& !(features
->features
[i
].flags
& FEATURE_HAS_FALLBACK
))
4566 if (feature
->flags
& FEATURE_GLOBAL
&& feature
->max_value
== 1)
4568 feature
->shift
= global_bit_shift
;
4569 feature
->mask
= global_bit_mask
;
4573 feature
->shift
= next_bit
;
4574 feature
->mask
= (1 << (next_bit
+ bits_needed
)) - (1 << next_bit
);
4575 next_bit
+= bits_needed
;
4576 context
->global_mask
|= (feature
->default_value
<< feature
->shift
) & feature
->mask
;
4579 feature
->flags
|= FEATURE_NEEDS_FALLBACK
;
4582 for (stage
= 0; stage
<= features
->stage
; ++stage
)
4584 if (required_feature
.index
!= 0xffff && required_feature
.stage
== stage
)
4585 opentype_layout_add_lookups(feature_list
, total_lookup_count
, table
, &required_feature
, lookups
);
4587 for (i
= 0; i
< features
->count
; ++i
)
4589 if (features
->features
[i
].stage
== stage
)
4590 opentype_layout_add_lookups(feature_list
, total_lookup_count
, table
, &features
->features
[i
], lookups
);
4593 /* Sort and merge lookups for current stage. */
4594 if (last_num_lookups
< lookups
->count
)
4596 qsort(lookups
->lookups
+ last_num_lookups
, lookups
->count
- last_num_lookups
, sizeof(*lookups
->lookups
),
4597 lookups_sorting_compare
);
4599 j
= last_num_lookups
;
4600 for (i
= j
+ 1; i
< lookups
->count
; ++i
)
4602 if (lookups
->lookups
[i
].index
!= lookups
->lookups
[j
].index
)
4604 lookups
->lookups
[++j
] = lookups
->lookups
[i
];
4608 lookups
->lookups
[j
].mask
|= lookups
->lookups
[i
].mask
;
4609 lookups
->lookups
[j
].auto_zwnj
&= lookups
->lookups
[i
].auto_zwnj
;
4610 lookups
->lookups
[j
].auto_zwj
&= lookups
->lookups
[i
].auto_zwj
;
4613 lookups
->count
= j
+ 1;
4616 last_num_lookups
= lookups
->count
;
4617 features
->stages
[stage
].last_lookup
= last_num_lookups
;
4621 static int feature_search_compare(const void *a
, const void* b
)
4623 unsigned int tag
= *(unsigned int *)a
;
4624 const struct shaping_feature
*feature
= b
;
4626 return tag
< feature
->tag
? -1 : tag
> feature
->tag
? 1 : 0;
4629 static unsigned int shaping_features_get_mask(const struct shaping_features
*features
, unsigned int tag
, unsigned int *shift
)
4631 struct shaping_feature
*feature
;
4633 feature
= bsearch(&tag
, features
->features
, features
->count
, sizeof(*features
->features
), feature_search_compare
);
4635 if (!feature
|| feature
->index
== 0xffff)
4638 if (shift
) *shift
= feature
->shift
;
4639 return feature
->mask
;
4642 unsigned int shape_get_feature_1_mask(const struct shaping_features
*features
, unsigned int tag
)
4644 unsigned int shift
, mask
= shaping_features_get_mask(features
, tag
, &shift
);
4645 return (1 << shift
) & mask
;
4648 static void opentype_layout_get_glyph_range_for_text(struct scriptshaping_context
*context
, unsigned int start_char
,
4649 unsigned int end_char
, unsigned int *start_glyph
, unsigned int *end_glyph
)
4651 *start_glyph
= context
->u
.buffer
.clustermap
[start_char
];
4652 if (end_char
>= context
->length
- 1)
4653 *end_glyph
= context
->glyph_count
- 1;
4655 *end_glyph
= context
->u
.buffer
.clustermap
[end_char
+ 1] - 1;
4658 static void opentype_layout_set_glyph_masks(struct scriptshaping_context
*context
, const struct shaping_features
*features
)
4660 const DWRITE_TYPOGRAPHIC_FEATURES
**user_features
= context
->user_features
.features
;
4661 unsigned int f
, r
, g
, start_char
, mask
, shift
, value
;
4663 for (g
= 0; g
< context
->glyph_count
; ++g
)
4664 context
->glyph_infos
[g
].mask
= context
->global_mask
;
4666 if (context
->shaper
->setup_masks
)
4667 context
->shaper
->setup_masks(context
, features
);
4669 for (r
= 0, start_char
= 0; r
< context
->user_features
.range_count
; ++r
)
4671 unsigned int start_glyph
, end_glyph
;
4673 if (start_char
>= context
->length
)
4676 opentype_layout_get_glyph_range_for_text(context
, start_char
, start_char
+ context
->user_features
.range_lengths
[r
],
4677 &start_glyph
, &end_glyph
);
4678 start_char
+= context
->user_features
.range_lengths
[r
];
4680 if (start_glyph
> end_glyph
|| end_glyph
>= context
->glyph_count
)
4683 for (f
= 0; f
< user_features
[r
]->featureCount
; ++f
)
4685 mask
= shaping_features_get_mask(features
, user_features
[r
]->features
[f
].nameTag
, &shift
);
4689 value
= (user_features
[r
]->features
[f
].parameter
<< shift
) & mask
;
4691 for (g
= start_glyph
; g
<= end_glyph
; ++g
)
4692 context
->glyph_infos
[g
].mask
= (context
->glyph_infos
[g
].mask
& ~mask
) | value
;
4697 static void opentype_layout_apply_gpos_context_lookup(struct scriptshaping_context
*context
, unsigned int lookup_index
)
4699 struct lookup lookup
= { 0 };
4700 if (opentype_layout_init_lookup(context
->table
, lookup_index
, NULL
, &lookup
))
4701 opentype_layout_apply_gpos_lookup(context
, &lookup
);
4704 void opentype_layout_apply_gpos_features(struct scriptshaping_context
*context
, unsigned int script_index
,
4705 unsigned int language_index
, struct shaping_features
*features
)
4707 struct lookups lookups
= { 0 };
4711 context
->nesting_level_left
= SHAPE_MAX_NESTING_LEVEL
;
4712 context
->u
.buffer
.apply_context_lookup
= opentype_layout_apply_gpos_context_lookup
;
4713 opentype_layout_collect_lookups(context
, script_index
, language_index
, features
, &context
->cache
->gpos
, &lookups
);
4715 for (i
= 0; i
< context
->glyph_count
; ++i
)
4716 opentype_set_glyph_props(context
, i
);
4717 opentype_layout_set_glyph_masks(context
, features
);
4719 for (i
= 0; i
< lookups
.count
; ++i
)
4721 const struct lookup
*lookup
= &lookups
.lookups
[i
];
4724 context
->lookup_mask
= lookup
->mask
;
4725 context
->auto_zwnj
= lookup
->auto_zwnj
;
4726 context
->auto_zwj
= lookup
->auto_zwj
;
4728 while (context
->cur
< context
->glyph_count
)
4732 if ((context
->glyph_infos
[context
->cur
].mask
& lookup
->mask
) &&
4733 lookup_is_glyph_match(context
, context
->cur
, lookup
->flags
))
4735 ret
= opentype_layout_apply_gpos_lookup(context
, lookup
);
4743 heap_free(lookups
.lookups
);
4746 static void opentype_layout_replace_glyph(struct scriptshaping_context
*context
, UINT16 glyph
)
4748 UINT16 orig_glyph
= context
->u
.subst
.glyphs
[context
->cur
];
4749 if (glyph
!= orig_glyph
)
4751 context
->u
.subst
.glyphs
[context
->cur
] = glyph
;
4752 opentype_set_subst_glyph_props(context
, context
->cur
);
4756 static BOOL
opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4757 unsigned int subtable_offset
)
4759 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4760 UINT16 format
, coverage
, orig_glyph
, glyph
;
4761 unsigned int coverage_index
;
4763 orig_glyph
= glyph
= context
->u
.subst
.glyphs
[context
->cur
];
4765 format
= table_read_be_word(table
, subtable_offset
);
4767 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format1
, coverage
));
4771 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
4772 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
4774 glyph
= orig_glyph
+ table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format1
, delta
));
4776 else if (format
== 2)
4778 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
4779 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
4781 if (!table_read_array_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format2
, count
),
4782 coverage_index
, &glyph
))
4789 WARN("Unknown single substitution format %u.\n", format
);
4793 opentype_layout_replace_glyph(context
, glyph
);
4799 static BOOL
opentype_layout_gsub_ensure_buffer(struct scriptshaping_context
*context
, unsigned int count
)
4801 DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
;
4802 struct shaping_glyph_info
*glyph_infos
;
4803 unsigned int new_capacity
;
4807 if (context
->u
.subst
.capacity
>= count
)
4810 new_capacity
= context
->u
.subst
.capacity
* 2;
4812 if ((glyphs
= heap_realloc(context
->u
.subst
.glyphs
, new_capacity
* sizeof(*glyphs
))))
4813 context
->u
.subst
.glyphs
= glyphs
;
4814 if ((glyph_props
= heap_realloc(context
->u
.subst
.glyph_props
, new_capacity
* sizeof(*glyph_props
))))
4815 context
->u
.subst
.glyph_props
= glyph_props
;
4816 if ((glyph_infos
= heap_realloc(context
->glyph_infos
, new_capacity
* sizeof(*glyph_infos
))))
4817 context
->glyph_infos
= glyph_infos
;
4819 if ((ret
= (glyphs
&& glyph_props
&& glyph_infos
)))
4820 context
->u
.subst
.capacity
= new_capacity
;
4825 static BOOL
opentype_layout_apply_gsub_mult_substitution(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4826 unsigned int subtable_offset
)
4828 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4829 UINT16 format
, coverage
, glyph
, glyph_count
;
4830 unsigned int i
, idx
, coverage_index
;
4831 const UINT16
*glyphs
;
4834 glyph
= context
->u
.subst
.glyphs
[idx
];
4836 format
= table_read_be_word(table
, subtable_offset
);
4838 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_multsubst_format1
, coverage
));
4844 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
4845 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
4847 if (!table_read_array_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_multsubst_format1
, seq_count
),
4848 coverage_index
, &seq_offset
))
4853 if (!(glyphs
= table_read_array_be_word(table
, subtable_offset
+ seq_offset
, ~0u, &glyph_count
))) return FALSE
;
4855 if (glyph_count
== 1)
4857 /* Equivalent of single substitution. */
4858 opentype_layout_replace_glyph(context
, GET_BE_WORD(glyphs
[0]));
4861 else if (glyph_count
== 0)
4867 unsigned int shift_len
, src_idx
, dest_idx
, mask
;
4869 /* Current glyph is also replaced. */
4872 if (!(opentype_layout_gsub_ensure_buffer(context
, context
->glyph_count
+ glyph_count
)))
4875 shift_len
= context
->cur
+ 1 < context
->glyph_count
? context
->glyph_count
- context
->cur
- 1 : 0;
4879 src_idx
= context
->cur
+ 1;
4880 dest_idx
= src_idx
+ glyph_count
;
4882 memmove(&context
->u
.subst
.glyphs
[dest_idx
], &context
->u
.subst
.glyphs
[src_idx
],
4883 shift_len
* sizeof(*context
->u
.subst
.glyphs
));
4884 memmove(&context
->u
.subst
.glyph_props
[dest_idx
], &context
->u
.subst
.glyph_props
[src_idx
],
4885 shift_len
* sizeof(*context
->u
.subst
.glyph_props
));
4886 memmove(&context
->glyph_infos
[dest_idx
], &context
->glyph_infos
[src_idx
],
4887 shift_len
* sizeof(*context
->glyph_infos
));
4890 mask
= context
->glyph_infos
[context
->cur
].mask
;
4891 for (i
= 0, idx
= context
->cur
; i
<= glyph_count
; ++i
)
4893 glyph
= GET_BE_WORD(glyphs
[i
]);
4894 context
->u
.subst
.glyphs
[idx
+ i
] = glyph
;
4897 context
->u
.subst
.glyph_props
[idx
+ i
].isClusterStart
= 0;
4898 context
->u
.buffer
.glyph_props
[idx
+ i
].components
= 0;
4899 context
->glyph_infos
[idx
+ i
].start_text_idx
= 0;
4901 opentype_set_subst_glyph_props(context
, idx
+ i
);
4902 /* Inherit feature mask from original matched glyph. */
4903 context
->glyph_infos
[idx
+ i
].mask
= mask
;
4906 context
->cur
+= glyph_count
+ 1;
4907 context
->glyph_count
+= glyph_count
;
4912 WARN("Unknown multiple substitution format %u.\n", format
);
4919 static BOOL
opentype_layout_apply_gsub_alt_substitution(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4920 unsigned int subtable_offset
)
4922 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4923 unsigned int idx
, coverage_index
;
4924 UINT16 format
, coverage
, glyph
;
4927 glyph
= context
->u
.subst
.glyphs
[idx
];
4929 format
= table_read_be_word(table
, subtable_offset
);
4933 const struct ot_gsub_altsubst_format1
*format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
));
4934 unsigned int shift
, alt_index
;
4937 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_altsubst_format1
, coverage
));
4939 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
4940 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
4942 if (!table_read_array_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_altsubst_format1
, count
),
4943 coverage_index
, &set_offset
))
4946 /* Argument is 1-based. */
4947 BitScanForward(&shift
, context
->lookup_mask
);
4948 alt_index
= (context
->lookup_mask
& context
->glyph_infos
[idx
].mask
) >> shift
;
4949 if (!alt_index
) return FALSE
;
4951 if (!table_read_array_be_word(table
, subtable_offset
+ set_offset
, alt_index
- 1, &glyph
)) return FALSE
;
4955 WARN("Unexpected alternate substitution format %d.\n", format
);
4959 opentype_layout_replace_glyph(context
, glyph
);
4965 static BOOL
opentype_layout_context_match_input(const struct match_context
*mc
, unsigned int count
, const UINT16
*input
,
4966 unsigned int *end_offset
, unsigned int *match_positions
)
4968 struct match_data match_data
= { .mc
= mc
, .subtable_offset
= mc
->input_offset
};
4969 struct scriptshaping_context
*context
= mc
->context
;
4970 struct glyph_iterator iter
;
4973 if (count
> GLYPH_CONTEXT_MAX_LENGTH
)
4976 match_positions
[0] = context
->cur
;
4978 glyph_iterator_init(context
, mc
->lookup
->flags
, context
->cur
, count
- 1, &iter
);
4979 iter
.mask
= context
->lookup_mask
;
4980 iter
.match_func
= mc
->match_func
;
4981 iter
.match_data
= &match_data
;
4982 iter
.glyph_data
= input
;
4984 for (i
= 1; i
< count
; ++i
)
4986 if (!glyph_iterator_next(&iter
))
4989 match_positions
[i
] = iter
.pos
;
4992 *end_offset
= iter
.pos
- context
->cur
+ 1;
4997 static void opentype_layout_unsafe_to_break(struct scriptshaping_context
*context
, unsigned int idx
)
4999 if (context
->u
.buffer
.glyph_props
[idx
].isClusterStart
)
5000 context
->u
.buffer
.text_props
[context
->glyph_infos
[idx
].start_text_idx
].canBreakShapingAfter
= 0;
5003 static void opentype_layout_delete_glyph(struct scriptshaping_context
*context
, unsigned int idx
)
5005 unsigned int shift_len
;
5007 shift_len
= context
->glyph_count
- context
->cur
- 1;
5011 memmove(&context
->u
.buffer
.glyphs
[idx
], &context
->u
.buffer
.glyphs
[idx
+ 1],
5012 shift_len
* sizeof(*context
->u
.buffer
.glyphs
));
5013 memmove(&context
->u
.buffer
.glyph_props
[idx
], &context
->u
.buffer
.glyph_props
[idx
+ 1],
5014 shift_len
* sizeof(*context
->u
.buffer
.glyph_props
));
5015 memmove(&context
->glyph_infos
[idx
], &context
->glyph_infos
[idx
+ 1], shift_len
* sizeof(*context
->glyph_infos
));
5018 context
->glyph_count
--;
5021 static BOOL
opentype_layout_apply_ligature(struct scriptshaping_context
*context
, unsigned int offset
,
5022 const struct lookup
*lookup
)
5024 struct match_context mc
= { .context
= context
, .lookup
= lookup
, .match_func
= opentype_match_glyph_func
};
5025 const struct dwrite_fonttable
*gsub
= &context
->table
->table
;
5026 unsigned int match_positions
[GLYPH_CONTEXT_MAX_LENGTH
];
5027 unsigned int i
, j
, comp_count
, match_length
= 0;
5028 const struct ot_gsub_lig
*lig
;
5031 comp_count
= table_read_be_word(gsub
, offset
+ FIELD_OFFSET(struct ot_gsub_lig
, comp_count
));
5036 lig
= table_read_ensure(gsub
, offset
, FIELD_OFFSET(struct ot_gsub_lig
, components
[comp_count
-1]));
5040 lig_glyph
= GET_BE_WORD(lig
->lig_glyph
);
5042 if (comp_count
== 1)
5044 opentype_layout_replace_glyph(context
, lig_glyph
);
5049 if (!opentype_layout_context_match_input(&mc
, comp_count
, lig
->components
, &match_length
, match_positions
))
5052 opentype_layout_replace_glyph(context
, lig_glyph
);
5053 context
->u
.buffer
.glyph_props
[context
->cur
].components
= comp_count
;
5055 /* Positioning against a ligature implies keeping track of ligature component
5056 glyph should be attached to. Update per-glyph property for interleaving glyphs,
5057 0 means attaching to last component, n - attaching to n-th glyph before last. */
5058 for (i
= 1; i
< comp_count
; ++i
)
5060 j
= match_positions
[i
- 1] + 1;
5061 while (j
< match_positions
[i
])
5063 context
->u
.buffer
.glyph_props
[j
++].lig_component
= comp_count
- i
;
5065 opentype_layout_unsafe_to_break(context
, i
);
5066 context
->u
.buffer
.glyph_props
[i
].isClusterStart
= 0;
5067 context
->glyph_infos
[i
].start_text_idx
= 0;
5070 /* Delete ligated glyphs, backwards to preserve index. */
5071 for (i
= 1; i
< comp_count
; ++i
)
5073 opentype_layout_delete_glyph(context
, match_positions
[comp_count
- i
]);
5076 /* Skip whole matched sequence, accounting for deleted glyphs. */
5077 context
->cur
+= match_length
- (comp_count
- 1);
5082 static BOOL
opentype_layout_apply_gsub_lig_substitution(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
5083 unsigned int subtable_offset
)
5085 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5086 UINT16 format
, coverage
, glyph
, lig_set_offset
;
5087 unsigned int coverage_index
;
5089 glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5091 format
= table_read_be_word(table
, subtable_offset
);
5095 const struct ot_gsub_ligsubst_format1
*format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
));
5097 const UINT16
*offsets
;
5100 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_ligsubst_format1
, coverage
));
5102 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5103 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
5105 if (!table_read_array_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_ligsubst_format1
, lig_set_count
),
5106 coverage_index
, &lig_set_offset
))
5109 if (!(offsets
= table_read_array_be_word(table
, subtable_offset
+ lig_set_offset
, ~0u, &lig_count
)))
5112 /* First applicable ligature is used. */
5113 for (i
= 0; i
< lig_count
; ++i
)
5115 if (opentype_layout_apply_ligature(context
, subtable_offset
+ lig_set_offset
+ GET_BE_WORD(offsets
[i
]), lookup
))
5120 WARN("Unexpected ligature substitution format %d.\n", format
);
5125 static BOOL
opentype_layout_context_match_backtrack(const struct match_context
*mc
, unsigned int count
,
5126 const UINT16
*backtrack
, unsigned int *match_start
)
5128 struct match_data match_data
= { .mc
= mc
, .subtable_offset
= mc
->backtrack_offset
};
5129 struct scriptshaping_context
*context
= mc
->context
;
5130 struct glyph_iterator iter
;
5133 glyph_iterator_init(context
, mc
->lookup
->flags
, context
->cur
, count
, &iter
);
5134 iter
.match_func
= mc
->match_func
;
5135 iter
.match_data
= &match_data
;
5136 iter
.glyph_data
= backtrack
;
5137 iter
.ignore_zwnj
|= context
->auto_zwnj
;
5138 iter
.ignore_zwj
= 1;
5140 for (i
= 0; i
< count
; ++i
)
5142 if (!glyph_iterator_prev(&iter
))
5146 *match_start
= iter
.pos
;
5151 static BOOL
opentype_layout_context_match_lookahead(const struct match_context
*mc
, unsigned int count
,
5152 const UINT16
*lookahead
, unsigned int offset
, unsigned int *end_index
)
5154 struct match_data match_data
= { .mc
= mc
, .subtable_offset
= mc
->lookahead_offset
};
5155 struct scriptshaping_context
*context
= mc
->context
;
5156 struct glyph_iterator iter
;
5159 glyph_iterator_init(context
, mc
->lookup
->flags
, context
->cur
+ offset
- 1, count
, &iter
);
5160 iter
.match_func
= mc
->match_func
;
5161 iter
.match_data
= &match_data
;
5162 iter
.glyph_data
= lookahead
;
5163 iter
.ignore_zwnj
|= context
->auto_zwnj
;
5164 iter
.ignore_zwj
= 1;
5166 for (i
= 0; i
< count
; ++i
)
5168 if (!glyph_iterator_next(&iter
))
5172 *end_index
= iter
.pos
;
5177 static BOOL
opentype_layout_context_apply_lookup(struct scriptshaping_context
*context
, unsigned int count
,
5178 unsigned int *match_positions
, unsigned int lookup_count
, const UINT16
*lookup_records
, unsigned int match_length
)
5183 if (!context
->nesting_level_left
)
5186 end
= context
->cur
+ match_length
;
5188 for (i
= 0; i
< lookup_count
; ++i
)
5190 unsigned int idx
= GET_BE_WORD(lookup_records
[i
]);
5191 unsigned int orig_len
, lookup_index
, next
;
5196 context
->cur
= match_positions
[idx
];
5198 orig_len
= context
->glyph_count
;
5200 lookup_index
= GET_BE_WORD(lookup_records
[i
+1]);
5202 --context
->nesting_level_left
;
5203 context
->u
.buffer
.apply_context_lookup(context
, lookup_index
);
5204 ++context
->nesting_level_left
;
5206 delta
= context
->glyph_count
- orig_len
;
5211 if (end
<= (int)match_positions
[idx
])
5213 end
= match_positions
[idx
];
5221 if (delta
+ count
> GLYPH_CONTEXT_MAX_LENGTH
)
5226 delta
= max(delta
, (int)next
- (int)count
);
5230 memmove(match_positions
+ next
+ delta
, match_positions
+ next
,
5231 (count
- next
) * sizeof (*match_positions
));
5235 for (j
= idx
+ 1; j
< next
; j
++)
5236 match_positions
[j
] = match_positions
[j
- 1] + 1;
5238 for (; next
< count
; next
++)
5239 match_positions
[next
] += delta
;
5247 static BOOL
opentype_layout_apply_chain_context_match(unsigned int backtrack_count
, const UINT16
*backtrack
,
5248 unsigned int input_count
, const UINT16
*input
, unsigned int lookahead_count
, const UINT16
*lookahead
,
5249 unsigned int lookup_count
, const UINT16
*lookup_records
, const struct match_context
*mc
)
5251 unsigned int start_index
= 0, match_length
= 0, end_index
= 0;
5252 unsigned int match_positions
[GLYPH_CONTEXT_MAX_LENGTH
];
5254 return opentype_layout_context_match_input(mc
, input_count
, input
, &match_length
, match_positions
) &&
5255 opentype_layout_context_match_backtrack(mc
, backtrack_count
, backtrack
, &start_index
) &&
5256 opentype_layout_context_match_lookahead(mc
, lookahead_count
, lookahead
, input_count
, &end_index
) &&
5257 opentype_layout_context_apply_lookup(mc
->context
, input_count
, match_positions
, lookup_count
, lookup_records
, match_length
);
5260 static BOOL
opentype_layout_apply_chain_rule_set(const struct match_context
*mc
, unsigned int offset
)
5262 unsigned int backtrack_count
, input_count
, lookahead_count
, lookup_count
;
5263 const struct dwrite_fonttable
*table
= &mc
->context
->table
->table
;
5264 const UINT16
*backtrack
, *lookahead
, *input
, *lookup_records
;
5265 const struct ot_gsubgpos_ruleset
*ruleset
;
5266 unsigned int i
, count
;
5268 count
= table_read_be_word(table
, offset
);
5269 ruleset
= table_read_ensure(table
, offset
, count
* sizeof(ruleset
->offsets
));
5271 for (i
= 0; i
< count
; ++i
)
5273 unsigned int rule_offset
= offset
+ GET_BE_WORD(ruleset
->offsets
[i
]);
5275 backtrack_count
= table_read_be_word(table
, rule_offset
);
5277 backtrack
= table_read_ensure(table
, rule_offset
, backtrack_count
* sizeof(*backtrack
));
5278 rule_offset
+= backtrack_count
* sizeof(*backtrack
);
5280 if (!(input_count
= table_read_be_word(table
, rule_offset
)))
5284 input
= table_read_ensure(table
, rule_offset
, (input_count
- 1) * sizeof(*input
));
5285 rule_offset
+= (input_count
- 1) * sizeof(*input
);
5287 lookahead_count
= table_read_be_word(table
, rule_offset
);
5289 lookahead
= table_read_ensure(table
, rule_offset
, lookahead_count
* sizeof(*lookahead
));
5290 rule_offset
+= lookahead_count
* sizeof(*lookahead
);
5292 lookup_count
= table_read_be_word(table
, rule_offset
);
5294 lookup_records
= table_read_ensure(table
, rule_offset
, lookup_count
* 2 * sizeof(*lookup_records
));
5296 /* First applicable rule is used. */
5297 if (opentype_layout_apply_chain_context_match(backtrack_count
, backtrack
, input_count
, input
, lookahead_count
,
5298 lookahead
, lookup_count
, lookup_records
, mc
))
5307 static BOOL
opentype_layout_apply_context_match(unsigned int input_count
, const UINT16
*input
, unsigned int lookup_count
,
5308 const UINT16
*lookup_records
, const struct match_context
*mc
)
5310 unsigned int match_positions
[GLYPH_CONTEXT_MAX_LENGTH
];
5311 unsigned int match_length
= 0;
5313 return opentype_layout_context_match_input(mc
, input_count
, input
, &match_length
, match_positions
) &&
5314 opentype_layout_context_apply_lookup(mc
->context
, input_count
, match_positions
, lookup_count
,
5315 lookup_records
, match_length
);
5318 static BOOL
opentype_layout_apply_rule_set(const struct match_context
*mc
, unsigned int offset
)
5320 unsigned int input_count
, lookup_count
;
5321 const struct dwrite_fonttable
*table
= &mc
->context
->table
->table
;
5322 const UINT16
*input
, *lookup_records
;
5323 const struct ot_gsubgpos_ruleset
*ruleset
;
5324 unsigned int i
, count
;
5326 count
= table_read_be_word(table
, offset
);
5327 ruleset
= table_read_ensure(table
, offset
, count
* sizeof(ruleset
->offsets
));
5329 for (i
= 0; i
< count
; ++i
)
5331 unsigned int rule_offset
= offset
+ GET_BE_WORD(ruleset
->offsets
[i
]);
5333 if (!(input_count
= table_read_be_word(table
, rule_offset
)))
5337 if (!(lookup_count
= table_read_be_word(table
, rule_offset
)))
5341 if (!(input
= table_read_ensure(table
, rule_offset
, (input_count
- 1) * sizeof(*input
))))
5343 rule_offset
+= (input_count
- 1) * sizeof(*input
);
5345 if (!(lookup_records
= table_read_ensure(table
, rule_offset
, lookup_count
* 2 * sizeof(*lookup_records
))))
5348 /* First applicable rule is used. */
5349 if (opentype_layout_apply_context_match(input_count
, input
, lookup_count
, lookup_records
, mc
))
5356 static BOOL
opentype_layout_apply_context(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
5357 unsigned int subtable_offset
)
5359 struct match_context mc
= { .context
= context
, .lookup
= lookup
};
5360 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5361 unsigned int coverage_index
= GLYPH_NOT_COVERED
, count
, offset
;
5362 UINT16 glyph
, format
, coverage
;
5365 glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5367 format
= table_read_be_word(table
, subtable_offset
);
5371 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
, coverage
));
5373 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5374 if (coverage_index
== GLYPH_NOT_COVERED
)
5377 count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
, ruleset_count
));
5378 if (coverage_index
>= count
)
5381 offset
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
,
5382 rulesets
[coverage_index
]));
5383 offset
+= subtable_offset
;
5385 mc
.match_func
= opentype_match_glyph_func
;
5387 ret
= opentype_layout_apply_rule_set(&mc
, offset
);
5389 else if (format
== 2)
5391 unsigned int input_classdef
, rule_set_idx
;
5393 offset
= subtable_offset
+ 2 /* format */;
5395 coverage
= table_read_be_word(table
, offset
);
5398 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5399 if (coverage_index
== GLYPH_NOT_COVERED
)
5402 input_classdef
= table_read_be_word(table
, offset
) + subtable_offset
;
5405 count
= table_read_be_word(table
, offset
);
5408 rule_set_idx
= opentype_layout_get_glyph_class(table
, input_classdef
, glyph
);
5409 if (rule_set_idx
>= count
)
5412 offset
= table_read_be_word(table
, offset
+ rule_set_idx
* 2);
5413 offset
+= subtable_offset
;
5415 mc
.input_offset
= input_classdef
;
5416 mc
.match_func
= opentype_match_class_func
;
5418 ret
= opentype_layout_apply_rule_set(&mc
, offset
);
5420 else if (format
== 3)
5422 unsigned int input_count
, lookup_count
;
5423 const UINT16
*input
, *lookup_records
;
5425 offset
= subtable_offset
+ 2 /* format */;
5427 input_count
= table_read_be_word(table
, offset
);
5433 lookup_count
= table_read_be_word(table
, offset
);
5436 if (!(input
= table_read_ensure(table
, offset
, sizeof(*input
) * input_count
)))
5438 offset
+= sizeof(*input
) * input_count
;
5440 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(input
[0]), glyph
);
5441 if (coverage_index
== GLYPH_NOT_COVERED
)
5444 lookup_records
= table_read_ensure(table
, offset
, lookup_count
* 2 * sizeof(*lookup_records
));
5446 mc
.input_offset
= subtable_offset
;
5447 mc
.match_func
= opentype_match_coverage_func
;
5449 ret
= opentype_layout_apply_context_match(input_count
, input
+ 1, lookup_count
, lookup_records
, &mc
);
5452 WARN("Unknown contextual substitution format %u.\n", format
);
5457 static BOOL
opentype_layout_apply_chain_context(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
5458 unsigned int subtable_offset
)
5460 struct match_context mc
= { .context
= context
, .lookup
= lookup
};
5461 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5462 unsigned int coverage_index
= GLYPH_NOT_COVERED
, count
, offset
;
5463 UINT16 glyph
, format
, coverage
;
5466 glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5468 format
= table_read_be_word(table
, subtable_offset
);
5472 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
, coverage
));
5474 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5475 if (coverage_index
== GLYPH_NOT_COVERED
)
5478 count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
, ruleset_count
));
5479 if (coverage_index
>= count
)
5482 offset
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
,
5483 rulesets
[coverage_index
]));
5484 offset
+= subtable_offset
;
5486 mc
.match_func
= opentype_match_glyph_func
;
5488 ret
= opentype_layout_apply_chain_rule_set(&mc
, offset
);
5490 else if (format
== 2)
5492 unsigned int backtrack_classdef
, input_classdef
, lookahead_classdef
, rule_set_idx
;
5494 offset
= subtable_offset
+ 2 /* format */;
5496 coverage
= table_read_be_word(table
, offset
);
5499 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5500 if (coverage_index
== GLYPH_NOT_COVERED
)
5503 backtrack_classdef
= table_read_be_word(table
, offset
) + subtable_offset
;
5506 input_classdef
= table_read_be_word(table
, offset
) + subtable_offset
;
5509 lookahead_classdef
= table_read_be_word(table
, offset
) + subtable_offset
;
5512 count
= table_read_be_word(table
, offset
);
5515 rule_set_idx
= opentype_layout_get_glyph_class(table
, input_classdef
, glyph
);
5516 if (rule_set_idx
>= count
)
5519 offset
= table_read_be_word(table
, offset
+ rule_set_idx
* 2);
5520 offset
+= subtable_offset
;
5522 mc
.backtrack_offset
= backtrack_classdef
;
5523 mc
.input_offset
= input_classdef
;
5524 mc
.lookahead_offset
= lookahead_classdef
;
5525 mc
.match_func
= opentype_match_class_func
;
5527 ret
= opentype_layout_apply_chain_rule_set(&mc
, offset
);
5529 else if (format
== 3)
5531 unsigned int backtrack_count
, input_count
, lookahead_count
, lookup_count
;
5532 const UINT16
*backtrack
, *lookahead
, *input
, *lookup_records
;
5534 offset
= subtable_offset
+ 2 /* format */;
5536 backtrack_count
= table_read_be_word(table
, offset
);
5538 backtrack
= table_read_ensure(table
, offset
, backtrack_count
* sizeof(*backtrack
));
5539 offset
+= backtrack_count
* sizeof(*backtrack
);
5541 input_count
= table_read_be_word(table
, offset
);
5543 input
= table_read_ensure(table
, offset
, input_count
* sizeof(*input
));
5544 offset
+= input_count
* sizeof(*input
);
5546 lookahead_count
= table_read_be_word(table
, offset
);
5548 lookahead
= table_read_ensure(table
, offset
, lookahead_count
* sizeof(*lookahead
));
5549 offset
+= lookahead_count
* sizeof(*lookahead
);
5551 lookup_count
= table_read_be_word(table
, offset
);
5553 lookup_records
= table_read_ensure(table
, offset
, lookup_count
* 2 * sizeof(*lookup_records
));
5556 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(input
[0]), glyph
);
5558 if (coverage_index
== GLYPH_NOT_COVERED
)
5561 mc
.backtrack_offset
= subtable_offset
;
5562 mc
.input_offset
= subtable_offset
;
5563 mc
.lookahead_offset
= subtable_offset
;
5564 mc
.match_func
= opentype_match_coverage_func
;
5566 ret
= opentype_layout_apply_chain_context_match(backtrack_count
, backtrack
, input_count
, input
+ 1, lookahead_count
,
5567 lookahead
, lookup_count
, lookup_records
, &mc
);
5570 WARN("Unknown chaining contextual substitution format %u.\n", format
);
5575 static BOOL
opentype_layout_apply_gsub_reverse_chain_context_substitution(struct scriptshaping_context
*context
,
5576 const struct lookup
*lookup
, unsigned int subtable_offset
)
5578 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5579 unsigned int offset
= subtable_offset
;
5580 UINT16 glyph
, format
;
5582 if (context
->nesting_level_left
!= SHAPE_MAX_NESTING_LEVEL
)
5585 glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5587 format
= table_read_be_word(table
, offset
);
5592 struct match_context mc
= { .context
= context
, .lookup
= lookup
};
5593 unsigned int start_index
= 0, end_index
= 0, backtrack_count
, lookahead_count
;
5594 unsigned int coverage
, coverage_index
;
5595 const UINT16
*backtrack
, *lookahead
;
5597 coverage
= table_read_be_word(table
, offset
);
5600 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5601 if (coverage_index
== GLYPH_NOT_COVERED
)
5604 backtrack_count
= table_read_be_word(table
, offset
);
5607 backtrack
= table_read_ensure(table
, offset
, sizeof(*backtrack
) * backtrack_count
);
5608 offset
+= sizeof(*backtrack
) * backtrack_count
;
5610 lookahead_count
= table_read_be_word(table
, offset
);
5613 lookahead
= table_read_ensure(table
, offset
, sizeof(*lookahead
) * lookahead_count
);
5614 offset
+= sizeof(*lookahead
) * lookahead_count
;
5616 mc
.match_func
= opentype_match_coverage_func
;
5617 mc
.backtrack_offset
= subtable_offset
;
5618 mc
.lookahead_offset
= subtable_offset
;
5620 if (opentype_layout_context_match_backtrack(&mc
, backtrack_count
, backtrack
, &start_index
) &&
5621 opentype_layout_context_match_lookahead(&mc
, lookahead_count
, lookahead
, 1, &end_index
))
5623 unsigned int glyph_count
= table_read_be_word(table
, offset
);
5624 if (coverage_index
>= glyph_count
)
5628 glyph
= table_read_be_word(table
, offset
+ coverage_index
* sizeof(glyph
));
5629 opentype_layout_replace_glyph(context
, glyph
);
5635 WARN("Unknown reverse chaining contextual substitution format %u.\n", format
);
5640 static BOOL
opentype_layout_apply_gsub_lookup(struct scriptshaping_context
*context
, const struct lookup
*lookup
)
5642 unsigned int i
, lookup_type
;
5645 for (i
= 0; i
< lookup
->subtable_count
; ++i
)
5647 unsigned int subtable_offset
= opentype_layout_get_gsubgpos_subtable(context
, lookup
, i
, &lookup_type
);
5649 switch (lookup_type
)
5651 case GSUB_LOOKUP_SINGLE_SUBST
:
5652 ret
= opentype_layout_apply_gsub_single_substitution(context
, lookup
, subtable_offset
);
5654 case GSUB_LOOKUP_MULTIPLE_SUBST
:
5655 ret
= opentype_layout_apply_gsub_mult_substitution(context
, lookup
, subtable_offset
);
5657 case GSUB_LOOKUP_ALTERNATE_SUBST
:
5658 ret
= opentype_layout_apply_gsub_alt_substitution(context
, lookup
, subtable_offset
);
5660 case GSUB_LOOKUP_LIGATURE_SUBST
:
5661 ret
= opentype_layout_apply_gsub_lig_substitution(context
, lookup
, subtable_offset
);
5663 case GSUB_LOOKUP_CONTEXTUAL_SUBST
:
5664 ret
= opentype_layout_apply_context(context
, lookup
, subtable_offset
);
5666 case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST
:
5667 ret
= opentype_layout_apply_chain_context(context
, lookup
, subtable_offset
);
5669 case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST
:
5670 ret
= opentype_layout_apply_gsub_reverse_chain_context_substitution(context
, lookup
, subtable_offset
);
5672 case GSUB_LOOKUP_EXTENSION_SUBST
:
5673 WARN("Invalid lookup type for extension substitution %#x.\n", lookup_type
);
5676 WARN("Unknown lookup type %u.\n", lookup_type
);
5686 static unsigned int unicode_get_mirrored_char(unsigned int codepoint
)
5688 extern const WCHAR wine_mirror_map
[] DECLSPEC_HIDDEN
;
5690 /* TODO: check if mirroring for higher planes makes sense at all */
5691 if (codepoint
> 0xffff) return codepoint
;
5692 mirror
= get_table_entry(wine_mirror_map
, codepoint
);
5693 return mirror
? mirror
: codepoint
;
5697 * 034F # Mn COMBINING GRAPHEME JOINER
5698 * 061C # Cf ARABIC LETTER MARK
5699 * 180B..180D # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
5700 * 180E # Cf MONGOLIAN VOWEL SEPARATOR
5701 * 200B..200F # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
5702 * FEFF # Cf ZERO WIDTH NO-BREAK SPACE
5704 static unsigned int opentype_is_zero_width(unsigned int codepoint
)
5706 return codepoint
== 0x34f || codepoint
== 0x61c || codepoint
== 0xfeff ||
5707 (codepoint
>= 0x180b && codepoint
<= 0x180e) || (codepoint
>= 0x200b && codepoint
<= 0x200f);
5711 * 00AD # Cf SOFT HYPHEN
5712 * 034F # Mn COMBINING GRAPHEME JOINER
5713 * 061C # Cf ARABIC LETTER MARK
5714 * 115F..1160 # Lo [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER
5715 * 17B4..17B5 # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
5716 * 180B..180D # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
5717 * 180E # Cf MONGOLIAN VOWEL SEPARATOR
5718 * 200B..200F # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
5719 * 202A..202E # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
5720 * 2060..2064 # Cf [5] WORD JOINER..INVISIBLE PLUS
5721 * 2065 # Cn <reserved-2065>
5722 * 2066..206F # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
5723 * 3164 # Lo HANGUL FILLER
5724 * FE00..FE0F # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
5725 * FEFF # Cf ZERO WIDTH NO-BREAK SPACE
5726 * FFA0 # Lo HALFWIDTH HANGUL FILLER
5727 * FFF0..FFF8 # Cn [9] <reserved-FFF0>..<reserved-FFF8>
5728 * 1BCA0..1BCA3 # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
5729 * 1D173..1D17A # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
5730 * E0000 # Cn <reserved-E0000>
5731 * E0001 # Cf LANGUAGE TAG
5732 * E0002..E001F # Cn [30] <reserved-E0002>..<reserved-E001F>
5733 * E0020..E007F # Cf [96] TAG SPACE..CANCEL TAG
5734 * E0080..E00FF # Cn [128] <reserved-E0080>..<reserved-E00FF>
5735 * E0100..E01EF # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
5736 * E01F0..E0FFF # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
5738 static unsigned int opentype_is_default_ignorable(unsigned int codepoint
)
5740 if (codepoint
< 0x80) return 0;
5741 return codepoint
== 0xad ||
5742 codepoint
== 0x34f ||
5743 codepoint
== 0x61c ||
5744 (codepoint
>= 0x17b4 && codepoint
<= 0x17b5) ||
5745 (codepoint
>= 0x180b && codepoint
<= 0x180e) ||
5746 (codepoint
>= 0x200b && codepoint
<= 0x200f) ||
5747 (codepoint
>= 0x202a && codepoint
<= 0x202e) ||
5748 (codepoint
>= 0x2060 && codepoint
<= 0x206f) ||
5749 (codepoint
>= 0xfe00 && codepoint
<= 0xfe0f) ||
5750 codepoint
== 0xfeff ||
5751 (codepoint
>= 0xfff0 && codepoint
<= 0xfff8) ||
5752 (codepoint
>= 0x1d173 && codepoint
<= 0x1d17a) ||
5753 (codepoint
>= 0xe0000 && codepoint
<= 0xe0fff);
5756 static unsigned int opentype_is_diacritic(unsigned int codepoint
)
5758 WCHAR ch
= codepoint
;
5760 /* Ignore higher planes for now. */
5761 if (codepoint
> 0xffff) return 0;
5762 GetStringTypeW(CT_CTYPE3
, &ch
, 1, &type
);
5763 return !!(type
& C3_DIACRITIC
);
5766 static void opentype_get_nominal_glyphs(struct scriptshaping_context
*context
, const struct shaping_features
*features
)
5768 unsigned int rtlm_mask
= shaping_features_get_mask(features
, DWRITE_MAKE_OPENTYPE_TAG('r','t','l','m'), NULL
);
5769 const struct shaping_font_ops
*font
= context
->cache
->font
;
5770 unsigned int i
, g
, c
, codepoint
, cluster_start_idx
= 0;
5771 UINT16
*clustermap
= context
->u
.subst
.clustermap
;
5772 const WCHAR
*text
= context
->text
;
5775 memset(context
->u
.subst
.glyph_props
, 0, context
->u
.subst
.max_glyph_count
* sizeof(*context
->u
.subst
.glyph_props
));
5776 memset(context
->u
.buffer
.text_props
, 0, context
->length
* sizeof(*context
->u
.buffer
.text_props
));
5778 for (i
= 0; i
< context
->length
; ++i
)
5780 g
= context
->glyph_count
;
5782 if ((bmp
= !(IS_HIGH_SURROGATE(text
[i
]) && (i
< context
->length
- 1) && IS_LOW_SURROGATE(text
[i
+ 1]))))
5784 codepoint
= text
[i
];
5788 codepoint
= 0x10000 + ((text
[i
] - 0xd800) << 10) + (text
[i
+ 1] - 0xdc00);
5791 if (context
->is_rtl
)
5793 c
= unicode_get_mirrored_char(codepoint
);
5794 if (c
!= codepoint
&& font
->has_glyph(context
->cache
->context
, c
))
5797 context
->glyph_infos
[i
].mask
|= rtlm_mask
;
5800 /* TODO: should this check for glyph availability? */
5801 if (*context
->u
.subst
.digits
&& codepoint
>= '0' && codepoint
<= '9')
5802 codepoint
= context
->u
.subst
.digits
[codepoint
- '0'];
5804 context
->u
.buffer
.glyphs
[g
] = font
->get_glyph(context
->cache
->context
, codepoint
);
5805 context
->u
.buffer
.glyph_props
[g
].justification
= SCRIPT_JUSTIFY_CHARACTER
;
5806 opentype_set_subst_glyph_props(context
, g
);
5807 if (opentype_is_default_ignorable(codepoint
))
5809 context
->glyph_infos
[g
].props
|= GLYPH_PROP_IGNORABLE
;
5810 if (codepoint
== 0x200d)
5811 context
->glyph_infos
[g
].props
|= GLYPH_PROP_ZWJ
;
5812 else if (codepoint
== 0x200c)
5813 context
->glyph_infos
[g
].props
|= GLYPH_PROP_ZWNJ
;
5814 /* Mongolian FVSs, TAGs, COMBINING GRAPHEME JOINER */
5815 else if ((codepoint
>= 0x180b && codepoint
<= 0x180d) ||
5816 (codepoint
>= 0xe0020 && codepoint
<= 0xe007f) ||
5819 context
->glyph_infos
[g
].props
|= GLYPH_PROP_HIDDEN
;
5823 /* Group diacritics with preceding base. Glyph class is ignored here. */
5824 if (!g
|| !opentype_is_diacritic(codepoint
))
5826 context
->u
.buffer
.glyph_props
[g
].isClusterStart
= 1;
5827 context
->glyph_infos
[g
].start_text_idx
= i
;
5828 cluster_start_idx
= g
;
5830 if (opentype_is_zero_width(codepoint
))
5831 context
->u
.buffer
.glyph_props
[g
].isZeroWidthSpace
= 1;
5833 context
->u
.buffer
.glyph_props
[g
].components
= 1;
5834 context
->glyph_count
++;
5836 /* Set initial cluster map here, it's used for setting user features masks. */
5837 clustermap
[i
] = cluster_start_idx
;
5839 context
->u
.buffer
.text_props
[i
].canBreakShapingAfter
= 1;
5842 clustermap
[i
+ 1] = cluster_start_idx
;
5843 context
->u
.buffer
.text_props
[i
+ 1].canBreakShapingAfter
= 1;
5849 static BOOL
opentype_is_gsub_lookup_reversed(const struct scriptshaping_context
*context
, const struct lookup
*lookup
)
5851 unsigned int lookup_type
;
5853 opentype_layout_get_gsubgpos_subtable(context
, lookup
, 0, &lookup_type
);
5854 return lookup_type
== GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST
;
5857 static void opentype_layout_apply_gsub_context_lookup(struct scriptshaping_context
*context
, unsigned int lookup_index
)
5859 struct lookup lookup
= { 0 };
5860 if (opentype_layout_init_lookup(context
->table
, lookup_index
, NULL
, &lookup
))
5861 opentype_layout_apply_gsub_lookup(context
, &lookup
);
5864 void opentype_layout_apply_gsub_features(struct scriptshaping_context
*context
, unsigned int script_index
,
5865 unsigned int language_index
, struct shaping_features
*features
)
5867 struct lookups lookups
= { 0 };
5868 unsigned int i
= 0, j
, start_idx
;
5871 context
->nesting_level_left
= SHAPE_MAX_NESTING_LEVEL
;
5872 context
->u
.buffer
.apply_context_lookup
= opentype_layout_apply_gsub_context_lookup
;
5873 opentype_layout_collect_lookups(context
, script_index
, language_index
, features
, context
->table
, &lookups
);
5875 opentype_get_nominal_glyphs(context
, features
);
5876 opentype_layout_set_glyph_masks(context
, features
);
5878 for (j
= 0; j
<= features
->stage
; ++j
)
5880 for (; i
< features
->stages
[j
].last_lookup
; ++i
)
5882 const struct lookup
*lookup
= &lookups
.lookups
[i
];
5884 context
->lookup_mask
= lookup
->mask
;
5885 context
->auto_zwnj
= lookup
->auto_zwnj
;
5886 context
->auto_zwj
= lookup
->auto_zwj
;
5888 if (!opentype_is_gsub_lookup_reversed(context
, lookup
))
5891 while (context
->cur
< context
->glyph_count
)
5895 if ((context
->glyph_infos
[context
->cur
].mask
& lookup
->mask
) &&
5896 lookup_is_glyph_match(context
, context
->cur
, lookup
->flags
))
5898 ret
= opentype_layout_apply_gsub_lookup(context
, lookup
);
5907 context
->cur
= context
->glyph_count
- 1;
5911 if ((context
->glyph_infos
[context
->cur
].mask
& lookup
->mask
) &&
5912 lookup_is_glyph_match(context
, context
->cur
, lookup
->flags
))
5914 opentype_layout_apply_gsub_lookup(context
, lookup
);
5917 if (context
->cur
== 0) break;
5923 if (features
->stages
[j
].func
)
5924 features
->stages
[j
].func(context
);
5927 /* For every glyph range of [<last>.isClusterStart, <next>.isClusterStart) set corresponding
5928 text span to start_idx. */
5930 for (i
= 1; i
< context
->glyph_count
; ++i
)
5932 if (context
->u
.buffer
.glyph_props
[i
].isClusterStart
)
5934 unsigned int start_text
, end_text
;
5936 start_text
= context
->glyph_infos
[start_idx
].start_text_idx
;
5937 end_text
= context
->glyph_infos
[i
].start_text_idx
;
5939 for (j
= start_text
; j
< end_text
; ++j
)
5940 context
->u
.buffer
.clustermap
[j
] = start_idx
;
5946 /* Fill the tail. */
5947 for (j
= context
->glyph_infos
[start_idx
].start_text_idx
; j
< context
->length
; ++j
)
5948 context
->u
.buffer
.clustermap
[j
] = start_idx
;
5950 heap_free(lookups
.lookups
);
5953 static BOOL
opentype_layout_contextual_lookup_is_glyph_covered(struct scriptshaping_context
*context
, UINT16 glyph
,
5954 unsigned int subtable_offset
, unsigned int coverage
, unsigned int format
)
5956 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5957 const UINT16
*offsets
;
5960 if (format
== 1 || format
== 2)
5962 if (opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
) != GLYPH_NOT_COVERED
)
5965 else if (format
== 3)
5967 count
= table_read_be_word(table
, subtable_offset
+ 2);
5968 if (!count
|| !(offsets
= table_read_ensure(table
, subtable_offset
+ 6, count
* sizeof(*offsets
))))
5971 if (opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(offsets
[0]), glyph
) != GLYPH_NOT_COVERED
)
5978 static BOOL
opentype_layout_chain_contextual_lookup_is_glyph_covered(struct scriptshaping_context
*context
, UINT16 glyph
,
5979 unsigned int subtable_offset
, unsigned int coverage
, unsigned int format
)
5981 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5982 unsigned int count
, backtrack_count
;
5983 const UINT16
*offsets
;
5985 if (format
== 1 || format
== 2)
5987 if (opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
) != GLYPH_NOT_COVERED
)
5990 else if (format
== 3)
5992 backtrack_count
= table_read_be_word(table
, subtable_offset
+ 2);
5994 count
= table_read_be_word(table
, subtable_offset
+ 4 + backtrack_count
* sizeof(*offsets
));
5996 if (!count
|| !(offsets
= table_read_ensure(table
, subtable_offset
+ 6 + backtrack_count
* sizeof(*offsets
),
5997 count
* sizeof(*offsets
))))
6000 if (opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(offsets
[0]), glyph
) != GLYPH_NOT_COVERED
)
6007 static BOOL
opentype_layout_gsub_lookup_is_glyph_covered(struct scriptshaping_context
*context
, UINT16 glyph
,
6008 const struct lookup
*lookup
)
6010 const struct dwrite_fonttable
*gsub
= &context
->table
->table
;
6011 static const unsigned short gsub_formats
[] =
6014 1, /* SingleSubst */
6015 1, /* MultipleSubst */
6016 1, /* AlternateSubst */
6017 1, /* LigatureSubst */
6018 3, /* ContextSubst */
6019 3, /* ChainContextSubst */
6020 0, /* Extension, unused */
6021 1, /* ReverseChainSubst */
6023 unsigned int i
, coverage
, lookup_type
, format
;
6025 for (i
= 0; i
< lookup
->subtable_count
; ++i
)
6027 unsigned int subtable_offset
= opentype_layout_get_gsubgpos_subtable(context
, lookup
, i
, &lookup_type
);
6029 format
= table_read_be_word(gsub
, subtable_offset
);
6031 if (!format
|| format
> ARRAY_SIZE(gsub_formats
) || format
> gsub_formats
[lookup_type
])
6034 coverage
= table_read_be_word(gsub
, subtable_offset
+ 2);
6036 switch (lookup_type
)
6038 case GSUB_LOOKUP_SINGLE_SUBST
:
6039 case GSUB_LOOKUP_MULTIPLE_SUBST
:
6040 case GSUB_LOOKUP_ALTERNATE_SUBST
:
6041 case GSUB_LOOKUP_LIGATURE_SUBST
:
6042 case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST
:
6044 if (opentype_layout_is_glyph_covered(gsub
, subtable_offset
+ coverage
, glyph
) != GLYPH_NOT_COVERED
)
6049 case GSUB_LOOKUP_CONTEXTUAL_SUBST
:
6051 if (opentype_layout_contextual_lookup_is_glyph_covered(context
, glyph
, subtable_offset
, coverage
, format
))
6056 case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST
:
6058 if (opentype_layout_chain_contextual_lookup_is_glyph_covered(context
, glyph
, subtable_offset
, coverage
, format
))
6064 WARN("Unknown lookup type %u.\n", lookup_type
);
6071 static BOOL
opentype_layout_gpos_lookup_is_glyph_covered(struct scriptshaping_context
*context
, UINT16 glyph
,
6072 const struct lookup
*lookup
)
6074 const struct dwrite_fonttable
*gpos
= &context
->table
->table
;
6075 static const unsigned short gpos_formats
[] =
6081 1, /* MarkBasePos */
6083 1, /* MarkMarkPos */
6085 3, /* ChainContextPos */
6086 0, /* Extension, unused */
6088 unsigned int i
, coverage
, lookup_type
, format
;
6090 for (i
= 0; i
< lookup
->subtable_count
; ++i
)
6092 unsigned int subtable_offset
= opentype_layout_get_gsubgpos_subtable(context
, lookup
, i
, &lookup_type
);
6094 format
= table_read_be_word(gpos
, subtable_offset
);
6096 if (!format
|| format
> ARRAY_SIZE(gpos_formats
) || format
> gpos_formats
[lookup_type
])
6099 coverage
= table_read_be_word(gpos
, subtable_offset
+ 2);
6101 switch (lookup_type
)
6103 case GPOS_LOOKUP_SINGLE_ADJUSTMENT
:
6104 case GPOS_LOOKUP_PAIR_ADJUSTMENT
:
6105 case GPOS_LOOKUP_CURSIVE_ATTACHMENT
:
6106 case GPOS_LOOKUP_MARK_TO_BASE_ATTACHMENT
:
6107 case GPOS_LOOKUP_MARK_TO_LIGATURE_ATTACHMENT
:
6108 case GPOS_LOOKUP_MARK_TO_MARK_ATTACHMENT
:
6110 if (opentype_layout_is_glyph_covered(gpos
, subtable_offset
+ coverage
, glyph
) != GLYPH_NOT_COVERED
)
6115 case GPOS_LOOKUP_CONTEXTUAL_POSITION
:
6117 if (opentype_layout_contextual_lookup_is_glyph_covered(context
, glyph
, subtable_offset
, coverage
, format
))
6122 case GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION
:
6124 if (opentype_layout_chain_contextual_lookup_is_glyph_covered(context
, glyph
, subtable_offset
, coverage
, format
))
6130 WARN("Unknown lookup type %u.\n", lookup_type
);
6137 typedef BOOL (*p_lookup_is_glyph_covered_func
)(struct scriptshaping_context
*context
, UINT16 glyph
, const struct lookup
*lookup
);
6139 BOOL
opentype_layout_check_feature(struct scriptshaping_context
*context
, unsigned int script_index
,
6140 unsigned int language_index
, struct shaping_feature
*feature
, unsigned int glyph_count
,
6141 const UINT16
*glyphs
, UINT8
*feature_applies
)
6143 p_lookup_is_glyph_covered_func func_is_covered
;
6144 struct shaping_features features
= { 0 };
6145 struct lookups lookups
= { 0 };
6146 BOOL ret
= FALSE
, is_covered
;
6147 unsigned int i
, j
, applies
;
6149 features
.features
= feature
;
6152 for (i
= 0; i
< context
->glyph_count
; ++i
)
6153 opentype_set_glyph_props(context
, i
);
6155 opentype_layout_collect_lookups(context
, script_index
, language_index
, &features
, context
->table
, &lookups
);
6157 func_is_covered
= context
->table
== &context
->cache
->gsub
? opentype_layout_gsub_lookup_is_glyph_covered
:
6158 opentype_layout_gpos_lookup_is_glyph_covered
;
6160 for (i
= 0; i
< lookups
.count
; ++i
)
6162 struct lookup
*lookup
= &lookups
.lookups
[i
];
6165 for (j
= 0; j
< context
->glyph_count
; ++j
)
6167 if (lookup_is_glyph_match(context
, j
, lookup
->flags
))
6169 if ((is_covered
= func_is_covered(context
, glyphs
[i
], lookup
)))
6171 feature_applies
[j
] |= is_covered
;
6175 if ((ret
= (applies
== context
->glyph_count
)))
6179 heap_free(lookups
.lookups
);
6184 BOOL
opentype_has_vertical_variants(struct dwrite_fontface
*fontface
)
6186 unsigned int i
, j
, count
= 0, lookup_type
, subtable_offset
;
6187 struct shaping_features features
= { 0 };
6188 struct shaping_feature vert_feature
= { 0 };
6189 struct scriptshaping_context context
= { 0 };
6190 struct lookups lookups
= { 0 };
6193 context
.cache
= fontface_get_shaping_cache(fontface
);
6194 context
.table
= &context
.cache
->gsub
;
6196 vert_feature
.tag
= DWRITE_MAKE_OPENTYPE_TAG('v','e','r','t');
6197 vert_feature
.flags
= FEATURE_GLOBAL
| FEATURE_GLOBAL_SEARCH
;
6198 vert_feature
.max_value
= 1;
6199 vert_feature
.default_value
= 1;
6201 features
.features
= &vert_feature
;
6202 features
.count
= features
.capacity
= 1;
6204 opentype_layout_collect_lookups(&context
, ~0u, ~0u, &features
, context
.table
, &lookups
);
6206 for (i
= 0; i
< lookups
.count
&& !count
; ++i
)
6208 const struct dwrite_fonttable
*table
= &context
.table
->table
;
6209 const struct lookup
*lookup
= &lookups
.lookups
[i
];
6211 for (j
= 0; j
< lookup
->subtable_count
&& !count
; ++j
)
6213 subtable_offset
= opentype_layout_get_gsubgpos_subtable(&context
, lookup
, j
, &lookup_type
);
6215 if (lookup_type
!= GSUB_LOOKUP_SINGLE_SUBST
)
6218 format
= table_read_be_word(table
, subtable_offset
);
6224 else if (format
== 2)
6226 count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format2
, count
));
6229 WARN("Unrecognized single substitution format %u.\n", format
);
6233 heap_free(lookups
.lookups
);
6238 HRESULT
opentype_get_vertical_glyph_variants(struct dwrite_fontface
*fontface
, unsigned int glyph_count
,
6239 const UINT16
*nominal_glyphs
, UINT16
*glyphs
)
6241 struct shaping_features features
= { 0 };
6242 struct shaping_feature vert_feature
= { 0 };
6243 struct scriptshaping_context context
= { 0 };
6244 struct lookups lookups
= { 0 };
6247 memcpy(glyphs
, nominal_glyphs
, glyph_count
* sizeof(*glyphs
));
6249 if (!(fontface
->flags
& FONTFACE_HAS_VERTICAL_VARIANTS
))
6252 context
.cache
= fontface_get_shaping_cache(fontface
);
6253 context
.u
.subst
.glyphs
= glyphs
;
6254 context
.u
.subst
.glyph_props
= heap_calloc(glyph_count
, sizeof(*context
.u
.subst
.glyph_props
));
6255 context
.u
.subst
.max_glyph_count
= glyph_count
;
6256 context
.u
.subst
.capacity
= glyph_count
;
6257 context
.glyph_infos
= heap_alloc_zero(sizeof(*context
.glyph_infos
) * glyph_count
);
6258 context
.table
= &context
.cache
->gsub
;
6260 vert_feature
.tag
= DWRITE_MAKE_OPENTYPE_TAG('v','e','r','t');
6261 vert_feature
.flags
= FEATURE_GLOBAL
| FEATURE_GLOBAL_SEARCH
;
6262 vert_feature
.max_value
= 1;
6263 vert_feature
.default_value
= 1;
6265 features
.features
= &vert_feature
;
6266 features
.count
= features
.capacity
= 1;
6268 opentype_layout_collect_lookups(&context
, ~0u, ~0u, &features
, context
.table
, &lookups
);
6269 opentype_layout_set_glyph_masks(&context
, &features
);
6271 for (i
= 0; i
< lookups
.count
; ++i
)
6273 const struct lookup
*lookup
= &lookups
.lookups
[i
];
6276 while (context
.cur
< context
.glyph_count
)
6280 if (lookup_is_glyph_match(&context
, context
.cur
, lookup
->flags
))
6281 ret
= opentype_layout_apply_gsub_lookup(&context
, lookup
);
6288 heap_free(context
.u
.subst
.glyph_props
);
6289 heap_free(context
.glyph_infos
);
6290 heap_free(lookups
.lookups
);