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
336 TT_NameRecord nameRecord
[1];
366 struct vdmx_vtable entries
[1];
369 struct ot_feature_record
375 struct ot_feature_list
378 struct ot_feature_record features
[1];
383 WORD lookup_order
; /* Reserved */
384 WORD required_feature_index
;
386 WORD feature_index
[1];
389 struct ot_langsys_record
397 WORD default_langsys
;
399 struct ot_langsys_record langsys
[1];
402 struct ot_script_record
408 struct ot_script_list
411 struct ot_script_record scripts
[1];
416 GDEF_CLASS_UNCLASSIFIED
= 0,
418 GDEF_CLASS_LIGATURE
= 2,
420 GDEF_CLASS_COMPONENT
= 4,
421 GDEF_CLASS_MAX
= GDEF_CLASS_COMPONENT
,
429 UINT16 ligcaret_list
;
430 UINT16 markattach_classdef
;
431 UINT16 markglyphsetdef
;
434 struct ot_gdef_classdef_format1
442 struct ot_gdef_class_range
449 struct ot_gdef_classdef_format2
453 struct ot_gdef_class_range ranges
[1];
456 struct gpos_gsub_header
464 enum gsub_gpos_lookup_flags
466 LOOKUP_FLAG_RTL
= 0x1, /* Only used for GPOS cursive attachments. */
468 LOOKUP_FLAG_IGNORE_BASE
= 0x2,
469 LOOKUP_FLAG_IGNORE_LIGATURES
= 0x4,
470 LOOKUP_FLAG_IGNORE_MARKS
= 0x8,
471 LOOKUP_FLAG_IGNORE_MASK
= 0xe,
473 LOOKUP_FLAG_USE_MARK_FILTERING_SET
= 0x10,
474 LOOKUP_FLAG_MARK_ATTACHMENT_TYPE
= 0xff00,
477 enum glyph_prop_flags
479 GLYPH_PROP_BASE
= LOOKUP_FLAG_IGNORE_BASE
,
480 GLYPH_PROP_LIGATURE
= LOOKUP_FLAG_IGNORE_LIGATURES
,
481 GLYPH_PROP_MARK
= LOOKUP_FLAG_IGNORE_MARKS
,
484 enum gpos_lookup_type
486 GPOS_LOOKUP_SINGLE_ADJUSTMENT
= 1,
487 GPOS_LOOKUP_PAIR_ADJUSTMENT
= 2,
488 GPOS_LOOKUP_CURSIVE_ATTACHMENT
= 3,
489 GPOS_LOOKUP_MARK_TO_BASE_ATTACHMENT
= 4,
490 GPOS_LOOKUP_MARK_TO_LIGATURE_ATTACHMENT
= 5,
491 GPOS_LOOKUP_MARK_TO_MARK_ATTACHMENT
= 6,
492 GPOS_LOOKUP_CONTEXTUAL_POSITION
= 7,
493 GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION
= 8,
494 GPOS_LOOKUP_EXTENSION_POSITION
= 9,
497 enum gsub_lookup_type
499 GSUB_LOOKUP_SINGLE_SUBST
= 1,
500 GSUB_LOOKUP_MULTIPLE_SUBST
= 2,
501 GSUB_LOOKUP_ALTERNATE_SUBST
= 3,
502 GSUB_LOOKUP_LIGATURE_SUBST
= 4,
503 GSUB_LOOKUP_CONTEXTUAL_SUBST
= 5,
504 GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST
= 6,
505 GSUB_LOOKUP_EXTENSION_SUBST
= 7,
506 GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST
= 8,
509 enum gpos_value_format
511 GPOS_VALUE_X_PLACEMENT
= 0x1,
512 GPOS_VALUE_Y_PLACEMENT
= 0x2,
513 GPOS_VALUE_X_ADVANCE
= 0x4,
514 GPOS_VALUE_Y_ADVANCE
= 0x8,
515 GPOS_VALUE_X_PLACEMENT_DEVICE
= 0x10,
516 GPOS_VALUE_Y_PLACEMENT_DEVICE
= 0x20,
517 GPOS_VALUE_X_ADVANCE_DEVICE
= 0x40,
518 GPOS_VALUE_Y_ADVANCE_DEVICE
= 0x80,
521 enum OPENTYPE_PLATFORM_ID
523 OPENTYPE_PLATFORM_UNICODE
= 0,
524 OPENTYPE_PLATFORM_MAC
,
525 OPENTYPE_PLATFORM_ISO
,
526 OPENTYPE_PLATFORM_WIN
,
527 OPENTYPE_PLATFORM_CUSTOM
530 struct ot_gsubgpos_extension_format1
534 DWORD extension_offset
;
537 struct ot_gsub_singlesubst_format1
544 struct ot_gsub_singlesubst_format2
549 UINT16 substitutes
[1];
552 struct ot_gsub_multsubst_format1
560 struct ot_gsub_altsubst_format1
568 struct ot_gsub_ligsubst_format1
572 UINT16 lig_set_count
;
576 struct ot_gsub_ligset
586 UINT16 components
[1];
589 struct ot_gsubgpos_context_format1
593 UINT16 ruleset_count
;
597 struct ot_gsubgpos_ruleset
607 WORD lookuplist_index
[1];
610 struct ot_lookup_list
616 struct ot_lookup_table
624 #define GLYPH_NOT_COVERED (~0u)
626 struct ot_coverage_format1
633 struct ot_coverage_range
637 WORD startcoverage_index
;
640 struct ot_coverage_format2
644 struct ot_coverage_range ranges
[1];
647 struct ot_gpos_device_table
655 struct ot_gpos_singlepos_format1
663 struct ot_gpos_singlepos_format2
672 struct ot_gpos_pairvalue
678 struct ot_gpos_pairset
680 WORD pairvalue_count
;
681 struct ot_gpos_pairvalue pairvalues
[1];
684 struct ot_gpos_pairpos_format1
694 struct ot_gpos_pairpos_format2
707 struct ot_gpos_anchor_format1
714 struct ot_gpos_anchor_format2
722 struct ot_gpos_anchor_format3
731 struct ot_gpos_cursive_format1
739 struct ot_gpos_mark_record
745 struct ot_gpos_mark_array
748 struct ot_gpos_mark_record records
[1];
751 struct ot_gpos_base_array
757 struct ot_gpos_mark_to_base_format1
762 WORD mark_class_count
;
767 struct ot_gpos_mark_to_lig_format1
772 WORD mark_class_count
;
777 struct ot_gpos_mark_to_mark_format1
782 WORD mark_class_count
;
791 } GSUB_SingleSubstFormat1
;
798 } GSUB_SingleSubstFormat2
;
802 WORD ExtensionLookupType
;
803 DWORD ExtensionOffset
;
804 } GSUB_ExtensionPosFormat1
;
808 enum TT_NAME_WINDOWS_ENCODING_ID
810 TT_NAME_WINDOWS_ENCODING_SYMBOL
= 0,
811 TT_NAME_WINDOWS_ENCODING_UNICODE_BMP
,
812 TT_NAME_WINDOWS_ENCODING_SJIS
,
813 TT_NAME_WINDOWS_ENCODING_PRC
,
814 TT_NAME_WINDOWS_ENCODING_BIG5
,
815 TT_NAME_WINDOWS_ENCODING_WANSUNG
,
816 TT_NAME_WINDOWS_ENCODING_JOHAB
,
817 TT_NAME_WINDOWS_ENCODING_RESERVED1
,
818 TT_NAME_WINDOWS_ENCODING_RESERVED2
,
819 TT_NAME_WINDOWS_ENCODING_RESERVED3
,
820 TT_NAME_WINDOWS_ENCODING_UNICODE_FULL
823 enum TT_NAME_MAC_ENCODING_ID
825 TT_NAME_MAC_ENCODING_ROMAN
= 0,
826 TT_NAME_MAC_ENCODING_JAPANESE
,
827 TT_NAME_MAC_ENCODING_TRAD_CHINESE
,
828 TT_NAME_MAC_ENCODING_KOREAN
,
829 TT_NAME_MAC_ENCODING_ARABIC
,
830 TT_NAME_MAC_ENCODING_HEBREW
,
831 TT_NAME_MAC_ENCODING_GREEK
,
832 TT_NAME_MAC_ENCODING_RUSSIAN
,
833 TT_NAME_MAC_ENCODING_RSYMBOL
,
834 TT_NAME_MAC_ENCODING_DEVANAGARI
,
835 TT_NAME_MAC_ENCODING_GURMUKHI
,
836 TT_NAME_MAC_ENCODING_GUJARATI
,
837 TT_NAME_MAC_ENCODING_ORIYA
,
838 TT_NAME_MAC_ENCODING_BENGALI
,
839 TT_NAME_MAC_ENCODING_TAMIL
,
840 TT_NAME_MAC_ENCODING_TELUGU
,
841 TT_NAME_MAC_ENCODING_KANNADA
,
842 TT_NAME_MAC_ENCODING_MALAYALAM
,
843 TT_NAME_MAC_ENCODING_SINHALESE
,
844 TT_NAME_MAC_ENCODING_BURMESE
,
845 TT_NAME_MAC_ENCODING_KHMER
,
846 TT_NAME_MAC_ENCODING_THAI
,
847 TT_NAME_MAC_ENCODING_LAOTIAN
,
848 TT_NAME_MAC_ENCODING_GEORGIAN
,
849 TT_NAME_MAC_ENCODING_ARMENIAN
,
850 TT_NAME_MAC_ENCODING_SIMPL_CHINESE
,
851 TT_NAME_MAC_ENCODING_TIBETAN
,
852 TT_NAME_MAC_ENCODING_MONGOLIAN
,
853 TT_NAME_MAC_ENCODING_GEEZ
,
854 TT_NAME_MAC_ENCODING_SLAVIC
,
855 TT_NAME_MAC_ENCODING_VIETNAMESE
,
856 TT_NAME_MAC_ENCODING_SINDHI
,
857 TT_NAME_MAC_ENCODING_UNINTERPRETED
860 enum TT_NAME_MAC_LANGUAGE_ID
862 TT_NAME_MAC_LANGID_ENGLISH
= 0,
863 TT_NAME_MAC_LANGID_FRENCH
,
864 TT_NAME_MAC_LANGID_GERMAN
,
865 TT_NAME_MAC_LANGID_ITALIAN
,
866 TT_NAME_MAC_LANGID_DUTCH
,
867 TT_NAME_MAC_LANGID_SWEDISH
,
868 TT_NAME_MAC_LANGID_SPANISH
,
869 TT_NAME_MAC_LANGID_DANISH
,
870 TT_NAME_MAC_LANGID_PORTUGUESE
,
871 TT_NAME_MAC_LANGID_NORWEGIAN
,
872 TT_NAME_MAC_LANGID_HEBREW
,
873 TT_NAME_MAC_LANGID_JAPANESE
,
874 TT_NAME_MAC_LANGID_ARABIC
,
875 TT_NAME_MAC_LANGID_FINNISH
,
876 TT_NAME_MAC_LANGID_GREEK
,
877 TT_NAME_MAC_LANGID_ICELANDIC
,
878 TT_NAME_MAC_LANGID_MALTESE
,
879 TT_NAME_MAC_LANGID_TURKISH
,
880 TT_NAME_MAC_LANGID_CROATIAN
,
881 TT_NAME_MAC_LANGID_TRAD_CHINESE
,
882 TT_NAME_MAC_LANGID_URDU
,
883 TT_NAME_MAC_LANGID_HINDI
,
884 TT_NAME_MAC_LANGID_THAI
,
885 TT_NAME_MAC_LANGID_KOREAN
,
886 TT_NAME_MAC_LANGID_LITHUANIAN
,
887 TT_NAME_MAC_LANGID_POLISH
,
888 TT_NAME_MAC_LANGID_HUNGARIAN
,
889 TT_NAME_MAC_LANGID_ESTONIAN
,
890 TT_NAME_MAC_LANGID_LATVIAN
,
891 TT_NAME_MAC_LANGID_SAMI
,
892 TT_NAME_MAC_LANGID_FAROESE
,
893 TT_NAME_MAC_LANGID_FARSI
,
894 TT_NAME_MAC_LANGID_RUSSIAN
,
895 TT_NAME_MAC_LANGID_SIMPL_CHINESE
,
896 TT_NAME_MAC_LANGID_FLEMISH
,
897 TT_NAME_MAC_LANGID_GAELIC
,
898 TT_NAME_MAC_LANGID_ALBANIAN
,
899 TT_NAME_MAC_LANGID_ROMANIAN
,
900 TT_NAME_MAC_LANGID_CZECH
,
901 TT_NAME_MAC_LANGID_SLOVAK
,
902 TT_NAME_MAC_LANGID_SLOVENIAN
,
903 TT_NAME_MAC_LANGID_YIDDISH
,
904 TT_NAME_MAC_LANGID_SERBIAN
,
905 TT_NAME_MAC_LANGID_MACEDONIAN
,
906 TT_NAME_MAC_LANGID_BULGARIAN
,
907 TT_NAME_MAC_LANGID_UKRAINIAN
,
908 TT_NAME_MAC_LANGID_BYELORUSSIAN
,
909 TT_NAME_MAC_LANGID_UZBEK
,
910 TT_NAME_MAC_LANGID_KAZAKH
,
911 TT_NAME_MAC_LANGID_AZERB_CYR
,
912 TT_NAME_MAC_LANGID_AZERB_ARABIC
,
913 TT_NAME_MAC_LANGID_ARMENIAN
,
914 TT_NAME_MAC_LANGID_GEORGIAN
,
915 TT_NAME_MAC_LANGID_MOLDAVIAN
,
916 TT_NAME_MAC_LANGID_KIRGHIZ
,
917 TT_NAME_MAC_LANGID_TAJIKI
,
918 TT_NAME_MAC_LANGID_TURKMEN
,
919 TT_NAME_MAC_LANGID_MONGOLIAN
,
920 TT_NAME_MAC_LANGID_MONGOLIAN_CYR
,
921 TT_NAME_MAC_LANGID_PASHTO
,
922 TT_NAME_MAC_LANGID_KURDISH
,
923 TT_NAME_MAC_LANGID_KASHMIRI
,
924 TT_NAME_MAC_LANGID_SINDHI
,
925 TT_NAME_MAC_LANGID_TIBETAN
,
926 TT_NAME_MAC_LANGID_NEPALI
,
927 TT_NAME_MAC_LANGID_SANSKRIT
,
928 TT_NAME_MAC_LANGID_MARATHI
,
929 TT_NAME_MAC_LANGID_BENGALI
,
930 TT_NAME_MAC_LANGID_ASSAMESE
,
931 TT_NAME_MAC_LANGID_GUJARATI
,
932 TT_NAME_MAC_LANGID_PUNJABI
,
933 TT_NAME_MAC_LANGID_ORIYA
,
934 TT_NAME_MAC_LANGID_MALAYALAM
,
935 TT_NAME_MAC_LANGID_KANNADA
,
936 TT_NAME_MAC_LANGID_TAMIL
,
937 TT_NAME_MAC_LANGID_TELUGU
,
938 TT_NAME_MAC_LANGID_SINHALESE
,
939 TT_NAME_MAC_LANGID_BURMESE
,
940 TT_NAME_MAC_LANGID_KHMER
,
941 TT_NAME_MAC_LANGID_LAO
,
942 TT_NAME_MAC_LANGID_VIETNAMESE
,
943 TT_NAME_MAC_LANGID_INDONESIAN
,
944 TT_NAME_MAC_LANGID_TAGALOG
,
945 TT_NAME_MAC_LANGID_MALAY_ROMAN
,
946 TT_NAME_MAC_LANGID_MALAY_ARABIC
,
947 TT_NAME_MAC_LANGID_AMHARIC
,
948 TT_NAME_MAC_LANGID_TIGRINYA
,
949 TT_NAME_MAC_LANGID_GALLA
,
950 TT_NAME_MAC_LANGID_SOMALI
,
951 TT_NAME_MAC_LANGID_SWAHILI
,
952 TT_NAME_MAC_LANGID_KINYARWANDA
,
953 TT_NAME_MAC_LANGID_RUNDI
,
954 TT_NAME_MAC_LANGID_NYANJA
,
955 TT_NAME_MAC_LANGID_MALAGASY
,
956 TT_NAME_MAC_LANGID_ESPERANTO
,
957 TT_NAME_MAC_LANGID_WELSH
= 128,
958 TT_NAME_MAC_LANGID_BASQUE
,
959 TT_NAME_MAC_LANGID_CATALAN
,
960 TT_NAME_MAC_LANGID_LATIN
,
961 TT_NAME_MAC_LANGID_QUECHUA
,
962 TT_NAME_MAC_LANGID_GUARANI
,
963 TT_NAME_MAC_LANGID_AYMARA
,
964 TT_NAME_MAC_LANGID_TATAR
,
965 TT_NAME_MAC_LANGID_UIGHUR
,
966 TT_NAME_MAC_LANGID_DZONGKHA
,
967 TT_NAME_MAC_LANGID_JAVANESE
,
968 TT_NAME_MAC_LANGID_SUNDANESE
,
969 TT_NAME_MAC_LANGID_GALICIAN
,
970 TT_NAME_MAC_LANGID_AFRIKAANS
,
971 TT_NAME_MAC_LANGID_BRETON
,
972 TT_NAME_MAC_LANGID_INUKTITUT
,
973 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC
,
974 TT_NAME_MAC_LANGID_MANX_GAELIC
,
975 TT_NAME_MAC_LANGID_IRISH_GAELIC
,
976 TT_NAME_MAC_LANGID_TONGAN
,
977 TT_NAME_MAC_LANGID_GREEK_POLYTONIC
,
978 TT_NAME_MAC_LANGID_GREENLANDIC
,
979 TT_NAME_MAC_LANGID_AZER_ROMAN
982 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
983 static const char name_mac_langid_to_locale
[][10] = {
1137 enum OPENTYPE_STRING_ID
1139 OPENTYPE_STRING_COPYRIGHT_NOTICE
= 0,
1140 OPENTYPE_STRING_FAMILY_NAME
,
1141 OPENTYPE_STRING_SUBFAMILY_NAME
,
1142 OPENTYPE_STRING_UNIQUE_IDENTIFIER
,
1143 OPENTYPE_STRING_FULL_FONTNAME
,
1144 OPENTYPE_STRING_VERSION_STRING
,
1145 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
1146 OPENTYPE_STRING_TRADEMARK
,
1147 OPENTYPE_STRING_MANUFACTURER
,
1148 OPENTYPE_STRING_DESIGNER
,
1149 OPENTYPE_STRING_DESCRIPTION
,
1150 OPENTYPE_STRING_VENDOR_URL
,
1151 OPENTYPE_STRING_DESIGNER_URL
,
1152 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
1153 OPENTYPE_STRING_LICENSE_INFO_URL
,
1154 OPENTYPE_STRING_RESERVED_ID15
,
1155 OPENTYPE_STRING_TYPOGRAPHIC_FAMILY_NAME
,
1156 OPENTYPE_STRING_TYPOGRAPHIC_SUBFAMILY_NAME
,
1157 OPENTYPE_STRING_COMPATIBLE_FULLNAME
,
1158 OPENTYPE_STRING_SAMPLE_TEXT
,
1159 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
1160 OPENTYPE_STRING_WWS_FAMILY_NAME
,
1161 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
1164 static const UINT16 dwriteid_to_opentypeid
[DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME
+ 1] =
1166 (UINT16
)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
1167 OPENTYPE_STRING_COPYRIGHT_NOTICE
,
1168 OPENTYPE_STRING_VERSION_STRING
,
1169 OPENTYPE_STRING_TRADEMARK
,
1170 OPENTYPE_STRING_MANUFACTURER
,
1171 OPENTYPE_STRING_DESIGNER
,
1172 OPENTYPE_STRING_DESIGNER_URL
,
1173 OPENTYPE_STRING_DESCRIPTION
,
1174 OPENTYPE_STRING_VENDOR_URL
,
1175 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
1176 OPENTYPE_STRING_LICENSE_INFO_URL
,
1177 OPENTYPE_STRING_FAMILY_NAME
,
1178 OPENTYPE_STRING_SUBFAMILY_NAME
,
1179 OPENTYPE_STRING_TYPOGRAPHIC_FAMILY_NAME
,
1180 OPENTYPE_STRING_TYPOGRAPHIC_SUBFAMILY_NAME
,
1181 OPENTYPE_STRING_SAMPLE_TEXT
,
1182 OPENTYPE_STRING_FULL_FONTNAME
,
1183 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
1184 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
1185 OPENTYPE_STRING_WWS_FAMILY_NAME
,
1189 struct cpal_header_0
1192 USHORT num_palette_entries
;
1193 USHORT num_palettes
;
1194 USHORT num_color_records
;
1195 ULONG offset_first_color_record
;
1196 USHORT color_record_indices
[1];
1199 struct cpal_color_record
1211 USHORT num_baseglyph_records
;
1212 ULONG offset_baseglyph_records
;
1213 ULONG offset_layer_records
;
1214 USHORT num_layer_records
;
1217 struct colr_baseglyph_record
1220 USHORT first_layer_index
;
1224 struct colr_layer_record
1227 USHORT palette_index
;
1230 struct meta_data_map
1242 DWORD data_maps_count
;
1243 struct meta_data_map maps
[1];
1246 static const void *table_read_ensure(const struct dwrite_fonttable
*table
, unsigned int offset
, unsigned int size
)
1248 if (size
> table
->size
|| offset
> table
->size
- size
)
1251 return table
->data
+ offset
;
1254 static WORD
table_read_be_word(const struct dwrite_fonttable
*table
, unsigned int offset
)
1256 const WORD
*ptr
= table_read_ensure(table
, offset
, sizeof(*ptr
));
1257 return ptr
? GET_BE_WORD(*ptr
) : 0;
1260 static DWORD
table_read_be_dword(const struct dwrite_fonttable
*table
, unsigned int offset
)
1262 const DWORD
*ptr
= table_read_ensure(table
, offset
, sizeof(*ptr
));
1263 return ptr
? GET_BE_DWORD(*ptr
) : 0;
1266 static DWORD
table_read_dword(const struct dwrite_fonttable
*table
, unsigned int offset
)
1268 const DWORD
*ptr
= table_read_ensure(table
, offset
, sizeof(*ptr
));
1269 return ptr
? *ptr
: 0;
1272 BOOL
is_face_type_supported(DWRITE_FONT_FACE_TYPE type
)
1274 return (type
== DWRITE_FONT_FACE_TYPE_CFF
) ||
1275 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE
) ||
1276 (type
== DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
) ||
1277 (type
== DWRITE_FONT_FACE_TYPE_RAW_CFF
);
1280 typedef HRESULT (*dwrite_fontfile_analyzer
)(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1281 DWRITE_FONT_FACE_TYPE
*face_type
);
1283 static HRESULT
opentype_ttc_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1284 DWRITE_FONT_FACE_TYPE
*face_type
)
1286 static const DWORD ttctag
= MS_TTCF_TAG
;
1287 const TTC_Header_V1
*header
;
1291 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(header
), &context
);
1295 if (!memcmp(header
->TTCTag
, &ttctag
, sizeof(ttctag
))) {
1296 *font_count
= GET_BE_DWORD(header
->numFonts
);
1297 *file_type
= DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION
;
1298 *face_type
= DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
;
1301 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1303 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1306 static HRESULT
opentype_ttf_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1307 DWRITE_FONT_FACE_TYPE
*face_type
)
1309 const DWORD
*header
;
1313 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
1317 if (GET_BE_DWORD(*header
) == 0x10000) {
1319 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE
;
1320 *face_type
= DWRITE_FONT_FACE_TYPE_TRUETYPE
;
1323 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1325 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1328 static HRESULT
opentype_otf_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1329 DWRITE_FONT_FACE_TYPE
*face_type
)
1331 const DWORD
*header
;
1335 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
1339 if (GET_BE_DWORD(*header
) == MS_OTTO_TAG
) {
1341 *file_type
= DWRITE_FONT_FILE_TYPE_CFF
;
1342 *face_type
= DWRITE_FONT_FACE_TYPE_CFF
;
1345 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1347 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1350 static HRESULT
opentype_type1_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1351 DWRITE_FONT_FACE_TYPE
*face_type
)
1353 #include "pshpack1.h"
1354 /* Specified in Adobe TechNote #5178 */
1362 #include "poppack.h"
1363 struct type1_header
{
1367 const struct type1_header
*header
;
1371 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
1375 /* tag is followed by plain text section */
1376 if (header
->tag
== 0x8001 &&
1377 (!memcmp(header
->data
, "%!PS-AdobeFont", 14) ||
1378 !memcmp(header
->data
, "%!FontType", 10))) {
1380 *file_type
= DWRITE_FONT_FILE_TYPE_TYPE1_PFB
;
1381 *face_type
= DWRITE_FONT_FACE_TYPE_TYPE1
;
1384 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1386 /* let's see if it's a .pfm metrics file */
1387 if (*file_type
== DWRITE_FONT_FILE_TYPE_UNKNOWN
) {
1388 const struct pfm_header
*pfm_header
;
1391 BOOL header_checked
;
1393 hr
= IDWriteFontFileStream_GetFileSize(stream
, &filesize
);
1397 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&pfm_header
, 0, sizeof(*pfm_header
), &context
);
1401 offset
= pfm_header
->dfDevice
;
1402 header_checked
= pfm_header
->dfVersion
== 0x100 && pfm_header
->dfSize
== filesize
;
1403 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1405 /* as a last test check static string in PostScript information section */
1406 if (header_checked
) {
1407 static const char postscript
[] = "PostScript";
1410 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&devtype_name
, offset
, sizeof(postscript
), &context
);
1414 if (!memcmp(devtype_name
, postscript
, sizeof(postscript
))) {
1416 *file_type
= DWRITE_FONT_FILE_TYPE_TYPE1_PFM
;
1417 *face_type
= DWRITE_FONT_FACE_TYPE_TYPE1
;
1420 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1424 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1427 HRESULT
opentype_analyze_font(IDWriteFontFileStream
*stream
, BOOL
*supported
, DWRITE_FONT_FILE_TYPE
*file_type
,
1428 DWRITE_FONT_FACE_TYPE
*face_type
, UINT32
*face_count
)
1430 static dwrite_fontfile_analyzer fontfile_analyzers
[] = {
1431 opentype_ttf_analyzer
,
1432 opentype_otf_analyzer
,
1433 opentype_ttc_analyzer
,
1434 opentype_type1_analyzer
,
1437 dwrite_fontfile_analyzer
*analyzer
= fontfile_analyzers
;
1438 DWRITE_FONT_FACE_TYPE face
;
1444 *file_type
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
1445 *face_type
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
1449 hr
= (*analyzer
)(stream
, face_count
, file_type
, face_type
);
1459 *supported
= is_face_type_supported(*face_type
);
1463 HRESULT
opentype_try_get_font_table(const struct file_stream_desc
*stream_desc
, UINT32 tag
, const void **table_data
,
1464 void **table_context
, UINT32
*table_size
, BOOL
*found
)
1466 void *table_directory_context
, *sfnt_context
;
1467 TT_TableRecord
*table_record
= NULL
;
1468 TTC_SFNT_V1
*font_header
= NULL
;
1469 UINT32 table_offset
= 0;
1473 if (found
) *found
= FALSE
;
1474 if (table_size
) *table_size
= 0;
1477 *table_context
= NULL
;
1479 if (stream_desc
->face_type
== DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
) {
1480 const TTC_Header_V1
*ttc_header
;
1482 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&ttc_header
, 0, sizeof(*ttc_header
), &ttc_context
);
1483 if (SUCCEEDED(hr
)) {
1484 if (stream_desc
->face_index
>= GET_BE_DWORD(ttc_header
->numFonts
))
1487 table_offset
= GET_BE_DWORD(ttc_header
->OffsetTable
[stream_desc
->face_index
]);
1488 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&font_header
, table_offset
, sizeof(*font_header
), &sfnt_context
);
1490 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, ttc_context
);
1494 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&font_header
, 0, sizeof(*font_header
), &sfnt_context
);
1499 table_count
= GET_BE_WORD(font_header
->numTables
);
1500 table_offset
+= sizeof(*font_header
);
1502 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, sfnt_context
);
1504 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void **)&table_record
, table_offset
,
1505 table_count
* sizeof(*table_record
), &table_directory_context
);
1509 for (i
= 0; i
< table_count
; i
++) {
1510 if (table_record
->tag
== tag
) {
1511 UINT32 offset
= GET_BE_DWORD(table_record
->offset
);
1512 UINT32 length
= GET_BE_DWORD(table_record
->length
);
1517 *table_size
= length
;
1518 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, table_data
, offset
,
1519 length
, table_context
);
1525 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, table_directory_context
);
1531 static HRESULT
opentype_get_font_table(const struct file_stream_desc
*stream_desc
, UINT32 tag
,
1532 struct dwrite_fonttable
*table
)
1534 return opentype_try_get_font_table(stream_desc
, tag
, (const void **)&table
->data
, &table
->context
, &table
->size
, &table
->exists
);
1541 static UINT16
opentype_cmap_format0_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1543 const UINT8
*glyphs
= cmap
->data
;
1544 return (ch
< 0xff) ? glyphs
[ch
] : 0;
1547 static unsigned int opentype_cmap_format0_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1548 DWRITE_UNICODE_RANGE
*ranges
)
1559 struct cmap_format4_compare_context
1561 const struct dwrite_cmap
*cmap
;
1565 static int cmap_format4_compare_range(const void *a
, const void *b
)
1567 const struct cmap_format4_compare_context
*key
= a
;
1568 const UINT16
*end
= b
;
1571 if (key
->ch
> GET_BE_WORD(*end
))
1574 idx
= end
- key
->cmap
->u
.format4
.ends
;
1575 if (key
->ch
< GET_BE_WORD(key
->cmap
->u
.format4
.starts
[idx
]))
1581 static UINT16
opentype_cmap_format4_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1583 struct cmap_format4_compare_context key
= { .cmap
= cmap
, .ch
= ch
};
1584 unsigned int glyph
, idx
, range_offset
;
1585 const UINT16
*end_found
;
1587 /* Look up range. */
1588 end_found
= bsearch(&key
, cmap
->u
.format4
.ends
, cmap
->u
.format4
.seg_count
, sizeof(*cmap
->u
.format4
.ends
),
1589 cmap_format4_compare_range
);
1593 idx
= end_found
- cmap
->u
.format4
.ends
;
1595 range_offset
= GET_BE_WORD(cmap
->u
.format4
.id_range_offset
[idx
]);
1599 glyph
= ch
+ GET_BE_WORD(cmap
->u
.format4
.id_delta
[idx
]);
1603 unsigned int index
= range_offset
/ 2 + (ch
- GET_BE_WORD(cmap
->u
.format4
.starts
[idx
])) + idx
- cmap
->u
.format4
.seg_count
;
1604 if (index
>= cmap
->u
.format4
.glyph_id_array_len
)
1606 glyph
= GET_BE_WORD(cmap
->u
.format4
.glyph_id_array
[index
]);
1609 glyph
+= GET_BE_WORD(cmap
->u
.format4
.id_delta
[idx
]);
1612 return glyph
& 0xffff;
1615 static unsigned int opentype_cmap_format4_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1616 DWRITE_UNICODE_RANGE
*ranges
)
1620 count
= min(count
, cmap
->u
.format4
.seg_count
);
1622 for (i
= 0; i
< count
; ++i
)
1624 ranges
[i
].first
= GET_BE_WORD(cmap
->u
.format4
.starts
[i
]);
1625 ranges
[i
].last
= GET_BE_WORD(cmap
->u
.format4
.ends
[i
]);
1628 return cmap
->u
.format4
.seg_count
;
1631 static UINT16
opentype_cmap_format6_10_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1633 const UINT16
*glyphs
= cmap
->data
;
1634 if (ch
< cmap
->u
.format6_10
.first
|| ch
> cmap
->u
.format6_10
.last
) return 0;
1635 return glyphs
[ch
- cmap
->u
.format6_10
.first
];
1638 static unsigned int opentype_cmap_format6_10_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1639 DWRITE_UNICODE_RANGE
*ranges
)
1643 ranges
->first
= cmap
->u
.format6_10
.first
;
1644 ranges
->last
= cmap
->u
.format6_10
.last
;
1650 static int cmap_format12_13_compare_group(const void *a
, const void *b
)
1652 const unsigned int *ch
= a
;
1653 const UINT32
*group
= b
;
1655 if (*ch
> GET_BE_DWORD(group
[1]))
1658 if (*ch
< GET_BE_DWORD(group
[0]))
1664 static UINT16
opentype_cmap_format12_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1666 const UINT32
*groups
= cmap
->data
;
1667 const UINT32
*group_found
;
1669 if (!(group_found
= bsearch(&ch
, groups
, cmap
->u
.format12_13
.group_count
, 3 * sizeof(*groups
),
1670 cmap_format12_13_compare_group
)))
1673 return GET_BE_DWORD(group_found
[0]) <= GET_BE_DWORD(group_found
[1]) ?
1674 GET_BE_DWORD(group_found
[2]) + (ch
- GET_BE_DWORD(group_found
[0])) : 0;
1677 static unsigned int opentype_cmap_format12_13_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1678 DWRITE_UNICODE_RANGE
*ranges
)
1680 unsigned int i
, group_count
= cmap
->u
.format12_13
.group_count
;
1681 const UINT32
*groups
= cmap
->data
;
1683 count
= min(count
, group_count
);
1685 for (i
= 0; i
< count
; ++i
)
1687 ranges
[i
].first
= GET_BE_DWORD(groups
[3 * i
]);
1688 ranges
[i
].last
= GET_BE_DWORD(groups
[3 * i
+ 1]);
1694 static UINT16
opentype_cmap_format13_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1696 const UINT32
*groups
= cmap
->data
;
1697 const UINT32
*group_found
;
1699 if (!(group_found
= bsearch(&ch
, groups
, cmap
->u
.format12_13
.group_count
, 3 * sizeof(*groups
),
1700 cmap_format12_13_compare_group
)))
1703 return GET_BE_DWORD(group_found
[2]);
1706 static UINT16
opentype_cmap_dummy_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1711 static unsigned int opentype_cmap_dummy_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1712 DWRITE_UNICODE_RANGE
*ranges
)
1717 UINT16
opentype_cmap_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1721 if (!cmap
->get_glyph
) return 0;
1722 glyph
= cmap
->get_glyph(cmap
, ch
);
1723 if (!glyph
&& cmap
->symbol
&& ch
<= 0xff)
1724 glyph
= cmap
->get_glyph(cmap
, ch
+ 0xf000);
1728 static int cmap_header_compare(const void *a
, const void *b
)
1730 const UINT16
*key
= a
;
1731 const UINT16
*record
= b
;
1734 if (key
[0] < GET_BE_WORD(record
[0])) return -1;
1735 if (key
[0] > GET_BE_WORD(record
[0])) return 1;
1737 if (key
[1] < GET_BE_WORD(record
[1])) return -1;
1738 if (key
[1] > GET_BE_WORD(record
[1])) return 1;
1743 void dwrite_cmap_init(struct dwrite_cmap
*cmap
, IDWriteFontFile
*file
, unsigned int face_index
,
1744 DWRITE_FONT_FACE_TYPE face_type
)
1746 static const UINT16 encodings
[][2] =
1748 { 3, 0 }, /* MS Symbol encoding is preferred. */
1758 const struct cmap_encoding_record
*records
, *found_record
= NULL
;
1759 unsigned int length
, offset
, format
, count
, f
, i
, num_records
;
1760 struct file_stream_desc stream_desc
;
1761 struct dwrite_fonttable table
;
1762 const UINT16
*pair
= NULL
;
1765 if (cmap
->data
) return;
1767 /* For fontface stream is already available and preset. */
1768 if (!cmap
->stream
&& FAILED(hr
= get_filestream_from_file(file
, &cmap
->stream
)))
1770 WARN("Failed to get file stream, hr %#x.\n", hr
);
1774 stream_desc
.stream
= cmap
->stream
;
1775 stream_desc
.face_type
= face_type
;
1776 stream_desc
.face_index
= face_index
;
1778 opentype_get_font_table(&stream_desc
, MS_CMAP_TAG
, &table
);
1781 cmap
->table_context
= table
.context
;
1783 num_records
= table_read_be_word(&table
, 2);
1784 records
= table_read_ensure(&table
, 4, sizeof(*records
) * num_records
);
1786 for (i
= 0; i
< ARRAY_SIZE(encodings
); ++i
)
1788 pair
= encodings
[i
];
1789 if ((found_record
= bsearch(pair
, records
, num_records
, sizeof(*records
), cmap_header_compare
)))
1795 WARN("No suitable cmap table were found.\n");
1799 /* Symbol encoding. */
1800 cmap
->symbol
= pair
[0] == 3 && pair
[1] == 0;
1801 offset
= GET_BE_DWORD(found_record
->offset
);
1803 format
= table_read_be_word(&table
, offset
);
1808 cmap
->data
= table_read_ensure(&table
, offset
+ 6, 256);
1809 cmap
->get_glyph
= opentype_cmap_format0_get_glyph
;
1810 cmap
->get_ranges
= opentype_cmap_format0_get_ranges
;
1813 length
= table_read_be_word(&table
, offset
+ 2);
1814 cmap
->u
.format4
.seg_count
= count
= table_read_be_word(&table
, offset
+ 6) / 2;
1815 cmap
->u
.format4
.ends
= table_read_ensure(&table
, offset
+ 14, count
* 2);
1816 cmap
->u
.format4
.starts
= cmap
->u
.format4
.ends
+ count
+ 1;
1817 cmap
->u
.format4
.id_delta
= cmap
->u
.format4
.starts
+ count
;
1818 cmap
->u
.format4
.id_range_offset
= cmap
->u
.format4
.id_delta
+ count
;
1819 cmap
->u
.format4
.glyph_id_array
= cmap
->data
= cmap
->u
.format4
.id_range_offset
+ count
;
1820 cmap
->u
.format4
.glyph_id_array_len
= (length
- 16 - 8 * count
) / 2;
1821 cmap
->get_glyph
= opentype_cmap_format4_get_glyph
;
1822 cmap
->get_ranges
= opentype_cmap_format4_get_ranges
;
1826 /* Format 10 uses 4 byte fields. */
1827 f
= format
== 6 ? 1 : 2;
1828 cmap
->u
.format6_10
.first
= table_read_be_word(&table
, offset
+ f
* 6);
1829 count
= table_read_be_word(&table
, offset
+ f
* 8);
1830 cmap
->u
.format6_10
.last
= cmap
->u
.format6_10
.first
+ count
;
1831 cmap
->data
= table_read_ensure(&table
, offset
+ f
* 10, count
* 2);
1832 cmap
->get_glyph
= opentype_cmap_format6_10_get_glyph
;
1833 cmap
->get_ranges
= opentype_cmap_format6_10_get_ranges
;
1837 cmap
->u
.format12_13
.group_count
= count
= table_read_be_dword(&table
, offset
+ 12);
1838 cmap
->data
= table_read_ensure(&table
, offset
+ 16, count
* 3 * 4);
1839 cmap
->get_glyph
= format
== 12 ? opentype_cmap_format12_get_glyph
: opentype_cmap_format13_get_glyph
;
1840 cmap
->get_ranges
= opentype_cmap_format12_13_get_ranges
;
1843 WARN("Unhandled subtable format %u.\n", format
);
1850 /* Dummy implementation, returns 0 unconditionally. */
1852 cmap
->get_glyph
= opentype_cmap_dummy_get_glyph
;
1853 cmap
->get_ranges
= opentype_cmap_dummy_get_ranges
;
1857 void dwrite_cmap_release(struct dwrite_cmap
*cmap
)
1861 IDWriteFontFileStream_ReleaseFileFragment(cmap
->stream
, cmap
->table_context
);
1862 IDWriteFontFileStream_Release(cmap
->stream
);
1865 cmap
->stream
= NULL
;
1868 HRESULT
opentype_cmap_get_unicode_ranges(const struct dwrite_cmap
*cmap
, unsigned int max_count
, DWRITE_UNICODE_RANGE
*ranges
,
1869 unsigned int *count
)
1874 *count
= cmap
->get_ranges(cmap
, max_count
, ranges
);
1876 return *count
> max_count
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
1879 void opentype_get_font_typo_metrics(struct file_stream_desc
*stream_desc
, unsigned int *ascent
, unsigned int *descent
)
1881 struct dwrite_fonttable os2
;
1883 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
1885 *ascent
= *descent
= 0;
1887 if (os2
.size
>= FIELD_OFFSET(struct tt_os2
, sTypoLineGap
))
1889 SHORT value
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoDescender
));
1890 *ascent
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoAscender
));
1891 *descent
= value
< 0 ? -value
: 0;
1895 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
1898 void opentype_get_font_metrics(struct file_stream_desc
*stream_desc
, DWRITE_FONT_METRICS1
*metrics
, DWRITE_CARET_METRICS
*caret
)
1900 struct dwrite_fonttable os2
, head
, post
, hhea
;
1902 memset(metrics
, 0, sizeof(*metrics
));
1904 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
1905 opentype_get_font_table(stream_desc
, MS_HEAD_TAG
, &head
);
1906 opentype_get_font_table(stream_desc
, MS_POST_TAG
, &post
);
1907 opentype_get_font_table(stream_desc
, MS_HHEA_TAG
, &hhea
);
1911 metrics
->designUnitsPerEm
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, unitsPerEm
));
1912 metrics
->glyphBoxLeft
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, xMin
));
1913 metrics
->glyphBoxTop
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, yMax
));
1914 metrics
->glyphBoxRight
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, xMax
));
1915 metrics
->glyphBoxBottom
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, yMin
));
1922 caret
->slopeRise
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, caretSlopeRise
));
1923 caret
->slopeRun
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, caretSlopeRun
));
1924 caret
->offset
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, caretOffset
));
1927 memset(caret
, 0, sizeof(*caret
));
1932 USHORT version
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, version
));
1934 metrics
->ascent
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, usWinAscent
));
1935 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
1936 interpreted as large unsigned value. */
1937 metrics
->descent
= abs((SHORT
)table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, usWinDescent
)));
1939 /* Line gap is estimated using two sets of ascender/descender values and 'hhea' line gap. */
1942 SHORT descender
= (SHORT
)table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, descender
));
1945 linegap
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, ascender
)) + abs(descender
) +
1946 table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, linegap
)) - metrics
->ascent
- metrics
->descent
;
1947 metrics
->lineGap
= linegap
> 0 ? linegap
: 0;
1950 metrics
->strikethroughPosition
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, yStrikeoutPosition
));
1951 metrics
->strikethroughThickness
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, yStrikeoutSize
));
1952 metrics
->subscriptPositionX
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySubscriptXOffset
));
1953 /* Y offset is stored as positive offset below baseline */
1954 metrics
->subscriptPositionY
= -table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySubscriptYOffset
));
1955 metrics
->subscriptSizeX
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySubscriptXSize
));
1956 metrics
->subscriptSizeY
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySubscriptYSize
));
1957 metrics
->superscriptPositionX
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySuperscriptXOffset
));
1958 metrics
->superscriptPositionY
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySuperscriptYOffset
));
1959 metrics
->superscriptSizeX
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySuperscriptXSize
));
1960 metrics
->superscriptSizeY
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySuperscriptYSize
));
1962 /* version 2 fields */
1965 metrics
->capHeight
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sCapHeight
));
1966 metrics
->xHeight
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sxHeight
));
1969 if (table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, fsSelection
)) & OS2_FSSELECTION_USE_TYPO_METRICS
)
1971 SHORT descent
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoDescender
));
1972 metrics
->ascent
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoAscender
));
1973 metrics
->descent
= descent
< 0 ? -descent
: 0;
1974 metrics
->lineGap
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoLineGap
));
1975 metrics
->hasTypographicMetrics
= TRUE
;
1980 metrics
->strikethroughPosition
= metrics
->designUnitsPerEm
/ 3;
1983 metrics
->ascent
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, ascender
));
1984 metrics
->descent
= abs((SHORT
)table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, descender
)));
1990 metrics
->underlinePosition
= table_read_be_word(&post
, FIELD_OFFSET(struct tt_post
, underlinePosition
));
1991 metrics
->underlineThickness
= table_read_be_word(&post
, FIELD_OFFSET(struct tt_post
, underlineThickness
));
1994 if (metrics
->underlineThickness
== 0)
1995 metrics
->underlineThickness
= metrics
->designUnitsPerEm
/ 14;
1996 if (metrics
->strikethroughThickness
== 0)
1997 metrics
->strikethroughThickness
= metrics
->underlineThickness
;
1999 /* estimate missing metrics */
2000 if (metrics
->xHeight
== 0)
2001 metrics
->xHeight
= metrics
->designUnitsPerEm
/ 2;
2002 if (metrics
->capHeight
== 0)
2003 metrics
->capHeight
= metrics
->designUnitsPerEm
* 7 / 10;
2006 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
2008 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, head
.context
);
2010 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, post
.context
);
2012 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, hhea
.context
);
2015 void opentype_get_font_properties(struct file_stream_desc
*stream_desc
, struct dwrite_font_props
*props
)
2017 struct dwrite_fonttable os2
, head
, colr
, cpal
;
2018 BOOL is_symbol
, is_monospaced
;
2020 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
2021 opentype_get_font_table(stream_desc
, MS_HEAD_TAG
, &head
);
2023 /* default stretch, weight and style to normal */
2024 props
->stretch
= DWRITE_FONT_STRETCH_NORMAL
;
2025 props
->weight
= DWRITE_FONT_WEIGHT_NORMAL
;
2026 props
->style
= DWRITE_FONT_STYLE_NORMAL
;
2027 memset(&props
->panose
, 0, sizeof(props
->panose
));
2028 memset(&props
->fontsig
, 0, sizeof(props
->fontsig
));
2029 memset(&props
->lf
, 0, sizeof(props
->lf
));
2032 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
2035 USHORT version
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, version
));
2036 USHORT fsSelection
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, fsSelection
));
2037 USHORT usWeightClass
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, usWeightClass
));
2038 USHORT usWidthClass
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, usWidthClass
));
2041 if (usWidthClass
> DWRITE_FONT_STRETCH_UNDEFINED
&& usWidthClass
<= DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
2042 props
->stretch
= usWidthClass
;
2044 if (usWeightClass
>= 1 && usWeightClass
<= 9)
2045 usWeightClass
*= 100;
2047 if (usWeightClass
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
2048 props
->weight
= DWRITE_FONT_WEIGHT_ULTRA_BLACK
;
2049 else if (usWeightClass
> 0)
2050 props
->weight
= usWeightClass
;
2052 if (version
>= 4 && (fsSelection
& OS2_FSSELECTION_OBLIQUE
))
2053 props
->style
= DWRITE_FONT_STYLE_OBLIQUE
;
2054 else if (fsSelection
& OS2_FSSELECTION_ITALIC
)
2055 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
2056 props
->lf
.lfItalic
= !!(fsSelection
& OS2_FSSELECTION_ITALIC
);
2058 if ((panose
= table_read_ensure(&os2
, FIELD_OFFSET(struct tt_os2
, panose
), sizeof(props
->panose
))))
2059 memcpy(&props
->panose
, panose
, sizeof(props
->panose
));
2062 props
->fontsig
.fsUsb
[0] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulUnicodeRange1
));
2063 props
->fontsig
.fsUsb
[1] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulUnicodeRange2
));
2064 props
->fontsig
.fsUsb
[2] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulUnicodeRange3
));
2065 props
->fontsig
.fsUsb
[3] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulUnicodeRange4
));
2069 props
->fontsig
.fsCsb
[0] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulCodePageRange1
));
2070 props
->fontsig
.fsCsb
[1] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulCodePageRange2
));
2075 USHORT macStyle
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, macStyle
));
2077 if (macStyle
& TT_HEAD_MACSTYLE_CONDENSED
)
2078 props
->stretch
= DWRITE_FONT_STRETCH_CONDENSED
;
2079 else if (macStyle
& TT_HEAD_MACSTYLE_EXTENDED
)
2080 props
->stretch
= DWRITE_FONT_STRETCH_EXPANDED
;
2082 if (macStyle
& TT_HEAD_MACSTYLE_BOLD
)
2083 props
->weight
= DWRITE_FONT_WEIGHT_BOLD
;
2085 if (macStyle
& TT_HEAD_MACSTYLE_ITALIC
) {
2086 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
2087 props
->lf
.lfItalic
= 1;
2091 props
->lf
.lfWeight
= props
->weight
;
2093 /* FONT_IS_SYMBOL */
2094 if (!(is_symbol
= props
->panose
.familyKind
== DWRITE_PANOSE_FAMILY_SYMBOL
))
2096 struct dwrite_fonttable cmap
;
2097 int i
, offset
, num_tables
;
2099 opentype_get_font_table(stream_desc
, MS_CMAP_TAG
, &cmap
);
2103 num_tables
= table_read_be_word(&cmap
, FIELD_OFFSET(struct cmap_header
, num_tables
));
2104 offset
= FIELD_OFFSET(struct cmap_header
, tables
);
2106 for (i
= 0; !is_symbol
&& i
< num_tables
; ++i
)
2108 WORD platform
, encoding
;
2110 platform
= table_read_be_word(&cmap
, offset
+ i
* sizeof(struct cmap_encoding_record
) +
2111 FIELD_OFFSET(struct cmap_encoding_record
, platformID
));
2112 encoding
= table_read_be_word(&cmap
, offset
+ i
* sizeof(struct cmap_encoding_record
) +
2113 FIELD_OFFSET(struct cmap_encoding_record
, encodingID
));
2115 is_symbol
= platform
== OPENTYPE_CMAP_TABLE_PLATFORM_WIN
&&
2116 encoding
== OPENTYPE_CMAP_TABLE_ENCODING_SYMBOL
;
2119 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, cmap
.context
);
2123 props
->flags
|= FONT_IS_SYMBOL
;
2125 /* FONT_IS_MONOSPACED */
2126 if (!(is_monospaced
= props
->panose
.text
.proportion
== DWRITE_PANOSE_PROPORTION_MONOSPACED
))
2128 struct dwrite_fonttable post
;
2130 opentype_get_font_table(stream_desc
, MS_POST_TAG
, &post
);
2134 is_monospaced
= !!table_read_dword(&post
, FIELD_OFFSET(struct tt_post
, fixed_pitch
));
2136 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, post
.context
);
2140 props
->flags
|= FONT_IS_MONOSPACED
;
2142 /* FONT_IS_COLORED */
2143 opentype_get_font_table(stream_desc
, MS_COLR_TAG
, &colr
);
2146 opentype_get_font_table(stream_desc
, MS_CPAL_TAG
, &cpal
);
2149 props
->flags
|= FONT_IS_COLORED
;
2150 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, cpal
.context
);
2153 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, colr
.context
);
2156 TRACE("stretch=%d, weight=%d, style %d\n", props
->stretch
, props
->weight
, props
->style
);
2159 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
2161 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, head
.context
);
2164 static UINT
get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform
, USHORT encoding
)
2169 case OPENTYPE_PLATFORM_UNICODE
:
2171 case OPENTYPE_PLATFORM_MAC
:
2174 case TT_NAME_MAC_ENCODING_ROMAN
:
2177 case TT_NAME_MAC_ENCODING_JAPANESE
:
2180 case TT_NAME_MAC_ENCODING_TRAD_CHINESE
:
2183 case TT_NAME_MAC_ENCODING_KOREAN
:
2186 case TT_NAME_MAC_ENCODING_ARABIC
:
2189 case TT_NAME_MAC_ENCODING_HEBREW
:
2192 case TT_NAME_MAC_ENCODING_GREEK
:
2195 case TT_NAME_MAC_ENCODING_RUSSIAN
:
2198 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE
:
2201 case TT_NAME_MAC_ENCODING_THAI
:
2205 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
2209 case OPENTYPE_PLATFORM_WIN
:
2212 case TT_NAME_WINDOWS_ENCODING_SYMBOL
:
2213 case TT_NAME_WINDOWS_ENCODING_UNICODE_BMP
:
2214 case TT_NAME_WINDOWS_ENCODING_UNICODE_FULL
:
2216 case TT_NAME_WINDOWS_ENCODING_SJIS
:
2219 case TT_NAME_WINDOWS_ENCODING_PRC
:
2222 case TT_NAME_WINDOWS_ENCODING_BIG5
:
2225 case TT_NAME_WINDOWS_ENCODING_WANSUNG
:
2228 case TT_NAME_WINDOWS_ENCODING_JOHAB
:
2232 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
2237 FIXME("unknown platform %d\n", platform
);
2243 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform
, USHORT lang_id
, WCHAR
*locale
, USHORT locale_len
)
2245 static const WCHAR enusW
[] = {'e','n','-','U','S',0};
2248 case OPENTYPE_PLATFORM_MAC
:
2250 const char *locale_name
= NULL
;
2252 if (lang_id
> TT_NAME_MAC_LANGID_AZER_ROMAN
)
2253 WARN("invalid mac lang id %d\n", lang_id
);
2254 else if (!name_mac_langid_to_locale
[lang_id
][0])
2255 FIXME("failed to map mac lang id %d to locale name\n", lang_id
);
2257 locale_name
= name_mac_langid_to_locale
[lang_id
];
2260 MultiByteToWideChar(CP_ACP
, 0, name_mac_langid_to_locale
[lang_id
], -1, locale
, locale_len
);
2262 strcpyW(locale
, enusW
);
2265 case OPENTYPE_PLATFORM_WIN
:
2266 if (!LCIDToLocaleName(MAKELCID(lang_id
, SORT_DEFAULT
), locale
, locale_len
, 0)) {
2267 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id
, SORT_DEFAULT
));
2268 strcpyW(locale
, enusW
);
2271 case OPENTYPE_PLATFORM_UNICODE
:
2272 strcpyW(locale
, enusW
);
2275 FIXME("unknown platform %d\n", platform
);
2279 static BOOL
opentype_decode_namerecord(const TT_NAME_V0
*header
, BYTE
*storage_area
, USHORT recid
, IDWriteLocalizedStrings
*strings
)
2281 const TT_NameRecord
*record
= &header
->nameRecord
[recid
];
2282 USHORT lang_id
, length
, offset
, encoding
, platform
;
2285 platform
= GET_BE_WORD(record
->platformID
);
2286 lang_id
= GET_BE_WORD(record
->languageID
);
2287 length
= GET_BE_WORD(record
->length
);
2288 offset
= GET_BE_WORD(record
->offset
);
2289 encoding
= GET_BE_WORD(record
->encodingID
);
2291 if (lang_id
< 0x8000) {
2292 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
2296 codepage
= get_name_record_codepage(platform
, encoding
);
2297 get_name_record_locale(platform
, lang_id
, locale
, ARRAY_SIZE(locale
));
2300 DWORD len
= MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, NULL
, 0);
2301 name_string
= heap_alloc(sizeof(WCHAR
) * (len
+1));
2302 MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, name_string
, len
);
2303 name_string
[len
] = 0;
2308 length
/= sizeof(WCHAR
);
2309 name_string
= heap_strdupnW((LPWSTR
)(storage_area
+ offset
), length
);
2310 for (i
= 0; i
< length
; i
++)
2311 name_string
[i
] = GET_BE_WORD(name_string
[i
]);
2314 TRACE("string %s for locale %s found\n", debugstr_w(name_string
), debugstr_w(locale
));
2315 add_localizedstring(strings
, locale
, name_string
);
2316 heap_free(name_string
);
2320 FIXME("handle NAME format 1\n");
2325 static HRESULT
opentype_get_font_strings_from_id(const void *table_data
, enum OPENTYPE_STRING_ID id
, IDWriteLocalizedStrings
**strings
)
2327 int i
, count
, candidate_mac
, candidate_unicode
;
2328 const TT_NAME_V0
*header
;
2329 BYTE
*storage_area
= 0;
2337 hr
= create_localizedstrings(strings
);
2338 if (FAILED(hr
)) return hr
;
2340 header
= table_data
;
2341 format
= GET_BE_WORD(header
->format
);
2348 FIXME("unsupported NAME format %d\n", format
);
2351 storage_area
= (LPBYTE
)table_data
+ GET_BE_WORD(header
->stringOffset
);
2352 count
= GET_BE_WORD(header
->count
);
2355 candidate_unicode
= candidate_mac
= -1;
2356 for (i
= 0; i
< count
; i
++) {
2357 const TT_NameRecord
*record
= &header
->nameRecord
[i
];
2360 if (GET_BE_WORD(record
->nameID
) != id
)
2363 platform
= GET_BE_WORD(record
->platformID
);
2366 /* Skip Unicode or Mac entries for now, fonts tend to duplicate those
2367 strings as WIN platform entries. If font does not have WIN entry for
2368 this id, we will use Mac or Unicode platform entry while assuming
2370 case OPENTYPE_PLATFORM_UNICODE
:
2371 if (candidate_unicode
== -1)
2372 candidate_unicode
= i
;
2374 case OPENTYPE_PLATFORM_MAC
:
2375 if (candidate_mac
== -1)
2378 case OPENTYPE_PLATFORM_WIN
:
2379 if (opentype_decode_namerecord(header
, storage_area
, i
, *strings
))
2383 FIXME("platform %i not supported\n", platform
);
2390 if (candidate_mac
!= -1)
2391 exists
= opentype_decode_namerecord(header
, storage_area
, candidate_mac
, *strings
);
2392 if (!exists
&& candidate_unicode
!= -1)
2393 exists
= opentype_decode_namerecord(header
, storage_area
, candidate_unicode
, *strings
);
2397 IDWriteLocalizedStrings_Release(*strings
);
2403 sort_localizedstrings(*strings
);
2405 return exists
? S_OK
: E_FAIL
;
2408 static WCHAR
*meta_get_lng_name(WCHAR
*str
, WCHAR
**ctx
)
2410 static const WCHAR delimW
[] = {',',' ',0};
2413 if (!str
) str
= *ctx
;
2414 while (*str
&& strchrW(delimW
, *str
)) str
++;
2415 if (!*str
) return NULL
;
2417 while (*str
&& !strchrW(delimW
, *str
)) str
++;
2418 if (*str
) *str
++ = 0;
2424 static HRESULT
opentype_get_font_strings_from_meta(const struct file_stream_desc
*stream_desc
,
2425 DWRITE_INFORMATIONAL_STRING_ID id
, IDWriteLocalizedStrings
**ret
)
2427 static const WCHAR emptyW
[] = { 0 };
2428 const struct meta_data_map
*maps
;
2429 IDWriteLocalizedStrings
*strings
;
2430 struct dwrite_fonttable meta
;
2431 DWORD version
, i
, count
, tag
;
2438 case DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG
:
2441 case DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
:
2445 WARN("Unexpected id %d.\n", id
);
2449 if (FAILED(hr
= create_localizedstrings(&strings
)))
2452 opentype_get_font_table(stream_desc
, MS_META_TAG
, &meta
);
2456 version
= table_read_be_dword(&meta
, 0);
2459 WARN("Unexpected meta table version %d.\n", version
);
2463 count
= table_read_be_dword(&meta
, FIELD_OFFSET(struct meta_header
, data_maps_count
));
2464 if (!(maps
= table_read_ensure(&meta
, FIELD_OFFSET(struct meta_header
, maps
),
2465 count
* sizeof(struct meta_data_map
))))
2468 for (i
= 0; i
< count
; ++i
)
2472 if (maps
[i
].tag
== tag
&& maps
[i
].length
)
2474 DWORD length
= GET_BE_DWORD(maps
[i
].length
), j
;
2476 if ((data
= table_read_ensure(&meta
, GET_BE_DWORD(maps
[i
].offset
), length
)))
2478 WCHAR
*ptrW
= heap_alloc((length
+ 1) * sizeof(WCHAR
)), *ctx
, *token
;
2486 /* Data is stored in comma separated list, ASCII range only. */
2487 for (j
= 0; j
< length
; ++j
)
2491 token
= meta_get_lng_name(ptrW
, &ctx
);
2495 add_localizedstring(strings
, emptyW
, token
);
2496 token
= meta_get_lng_name(NULL
, &ctx
);
2504 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, meta
.context
);
2507 if (IDWriteLocalizedStrings_GetCount(strings
))
2510 IDWriteLocalizedStrings_Release(strings
);
2515 HRESULT
opentype_get_font_info_strings(const struct file_stream_desc
*stream_desc
, DWRITE_INFORMATIONAL_STRING_ID id
,
2516 IDWriteLocalizedStrings
**strings
)
2518 struct dwrite_fonttable name
;
2522 case DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG
:
2523 case DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
:
2524 opentype_get_font_strings_from_meta(stream_desc
, id
, strings
);
2527 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name
);
2528 opentype_get_font_strings_from_id(name
.data
, dwriteid_to_opentypeid
[id
], strings
);
2530 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name
.context
);
2536 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
2537 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
2538 HRESULT
opentype_get_font_familyname(struct file_stream_desc
*stream_desc
, IDWriteLocalizedStrings
**names
)
2540 struct dwrite_fonttable os2
, name
;
2541 const void *name_table
;
2545 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
2546 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name
);
2548 name_table
= (const void *)name
.data
;
2552 /* If Preferred Family doesn't conform to WWS model try WWS name. */
2553 fsselection
= os2
.data
? table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, fsSelection
)) : 0;
2554 if (os2
.data
&& !(fsselection
& OS2_FSSELECTION_WWS
))
2555 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_WWS_FAMILY_NAME
, names
);
2560 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_TYPOGRAPHIC_FAMILY_NAME
, names
);
2562 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_FAMILY_NAME
, names
);
2565 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
2567 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name
.context
);
2572 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
2573 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
2574 HRESULT
opentype_get_font_facename(struct file_stream_desc
*stream_desc
, WCHAR
*lfname
, IDWriteLocalizedStrings
**names
)
2576 struct dwrite_fonttable os2
, name
;
2577 IDWriteLocalizedStrings
*lfnames
;
2578 const void *name_table
;
2582 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
2583 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name
);
2585 name_table
= name
.data
;
2589 /* if Preferred Family doesn't conform to WWS model try WWS name */
2590 fsselection
= os2
.data
? table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, fsSelection
)) : 0;
2591 if (os2
.data
&& !(fsselection
& OS2_FSSELECTION_WWS
))
2592 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_WWS_SUBFAMILY_NAME
, names
);
2597 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_TYPOGRAPHIC_SUBFAMILY_NAME
, names
);
2599 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_SUBFAMILY_NAME
, names
);
2601 /* User locale is preferred, with fallback to en-us. */
2603 if (SUCCEEDED(opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_FAMILY_NAME
, &lfnames
))) {
2604 static const WCHAR enusW
[] = {'e','n','-','u','s',0};
2605 WCHAR localeW
[LOCALE_NAME_MAX_LENGTH
];
2610 if (GetSystemDefaultLocaleName(localeW
, ARRAY_SIZE(localeW
)))
2611 IDWriteLocalizedStrings_FindLocaleName(lfnames
, localeW
, &index
, &exists
);
2614 IDWriteLocalizedStrings_FindLocaleName(lfnames
, enusW
, &index
, &exists
);
2620 IDWriteLocalizedStrings_GetStringLength(lfnames
, index
, &length
);
2621 nameW
= heap_alloc((length
+ 1) * sizeof(WCHAR
));
2624 IDWriteLocalizedStrings_GetString(lfnames
, index
, nameW
, length
+ 1);
2625 lstrcpynW(lfname
, nameW
, LF_FACESIZE
);
2630 IDWriteLocalizedStrings_Release(lfnames
);
2634 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
2636 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name
.context
);
2641 static const struct ot_langsys
*opentype_get_langsys(const struct ot_gsubgpos_table
*table
, unsigned int script_index
,
2642 unsigned int language_index
, unsigned int *feature_count
)
2644 unsigned int table_offset
, langsys_offset
;
2645 const struct ot_langsys
*langsys
= NULL
;
2649 if (!table
->table
.data
|| script_index
== ~0u)
2652 /* ScriptTable offset. */
2653 table_offset
= table_read_be_word(&table
->table
, table
->script_list
+ FIELD_OFFSET(struct ot_script_list
, scripts
) +
2654 script_index
* sizeof(struct ot_script_record
) + FIELD_OFFSET(struct ot_script_record
, script
));
2658 if (language_index
== ~0u)
2659 langsys_offset
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
);
2661 langsys_offset
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
+
2662 FIELD_OFFSET(struct ot_script
, langsys
) + language_index
* sizeof(struct ot_langsys_record
) +
2663 FIELD_OFFSET(struct ot_langsys_record
, langsys
));
2664 langsys_offset
+= table
->script_list
+ table_offset
;
2666 *feature_count
= table_read_be_word(&table
->table
, langsys_offset
+ FIELD_OFFSET(struct ot_langsys
, feature_count
));
2668 langsys
= table_read_ensure(&table
->table
, langsys_offset
, FIELD_OFFSET(struct ot_langsys
, feature_index
[*feature_count
]));
2675 void opentype_get_typographic_features(struct ot_gsubgpos_table
*table
, unsigned int script_index
,
2676 unsigned int language_index
, struct tag_array
*t
)
2678 unsigned int i
, total_feature_count
, script_feature_count
;
2679 const struct ot_feature_list
*feature_list
;
2680 const struct ot_langsys
*langsys
= NULL
;
2682 langsys
= opentype_get_langsys(table
, script_index
, language_index
, &script_feature_count
);
2684 total_feature_count
= table_read_be_word(&table
->table
, table
->feature_list
);
2685 if (!total_feature_count
)
2688 feature_list
= table_read_ensure(&table
->table
, table
->feature_list
,
2689 FIELD_OFFSET(struct ot_feature_list
, features
[total_feature_count
]));
2693 for (i
= 0; i
< script_feature_count
; ++i
)
2695 unsigned int feature_index
= GET_BE_WORD(langsys
->feature_index
[i
]);
2696 if (feature_index
>= total_feature_count
)
2699 if (!dwrite_array_reserve((void **)&t
->tags
, &t
->capacity
, t
->count
+ 1, sizeof(*t
->tags
)))
2702 t
->tags
[t
->count
++] = feature_list
->features
[feature_index
].tag
;
2706 static unsigned int find_vdmx_group(const struct vdmx_header
*hdr
)
2709 const struct vdmx_ratio
*ratios
= (struct vdmx_ratio
*)(hdr
+ 1);
2710 BYTE dev_x_ratio
= 1, dev_y_ratio
= 1;
2711 unsigned int group_offset
= 0;
2713 num_ratios
= GET_BE_WORD(hdr
->num_ratios
);
2715 for (i
= 0; i
< num_ratios
; i
++) {
2717 if (!ratios
[i
].bCharSet
) continue;
2719 if ((ratios
[i
].xRatio
== 0 && ratios
[i
].yStartRatio
== 0 &&
2720 ratios
[i
].yEndRatio
== 0) ||
2721 (ratios
[i
].xRatio
== dev_x_ratio
&& ratios
[i
].yStartRatio
<= dev_y_ratio
&&
2722 ratios
[i
].yEndRatio
>= dev_y_ratio
))
2724 group_offset
= GET_BE_WORD(*((WORD
*)(ratios
+ num_ratios
) + i
));
2729 return group_offset
;
2732 BOOL
opentype_get_vdmx_size(const struct dwrite_fonttable
*vdmx
, INT emsize
, UINT16
*ascent
, UINT16
*descent
)
2734 unsigned int num_ratios
, num_recs
, group_offset
, i
;
2735 const struct vdmx_header
*header
;
2736 const struct vdmx_group
*group
;
2741 num_ratios
= table_read_be_word(vdmx
, FIELD_OFFSET(struct vdmx_header
, num_ratios
));
2742 num_recs
= table_read_be_word(vdmx
, FIELD_OFFSET(struct vdmx_header
, num_recs
));
2744 header
= table_read_ensure(vdmx
, 0, sizeof(*header
) + num_ratios
* sizeof(struct vdmx_ratio
) +
2745 num_recs
* sizeof(*group
));
2750 group_offset
= find_vdmx_group(header
);
2754 num_recs
= table_read_be_word(vdmx
, group_offset
);
2755 group
= table_read_ensure(vdmx
, group_offset
, FIELD_OFFSET(struct vdmx_group
, entries
[num_recs
]));
2760 if (emsize
< group
->startsz
|| emsize
>= group
->endsz
)
2763 for (i
= 0; i
< num_recs
; ++i
)
2765 WORD ppem
= GET_BE_WORD(group
->entries
[i
].yPelHeight
);
2766 if (ppem
> emsize
) {
2767 FIXME("interpolate %d\n", emsize
);
2771 if (ppem
== emsize
) {
2772 *ascent
= (SHORT
)GET_BE_WORD(group
->entries
[i
].yMax
);
2773 *descent
= -(SHORT
)GET_BE_WORD(group
->entries
[i
].yMin
);
2781 unsigned int opentype_get_gasp_flags(const struct dwrite_fonttable
*gasp
, float emsize
)
2783 unsigned int version
, num_ranges
, i
;
2784 const struct gasp_header
*table
;
2790 num_ranges
= table_read_be_word(gasp
, FIELD_OFFSET(struct gasp_header
, num_ranges
));
2792 table
= table_read_ensure(gasp
, 0, FIELD_OFFSET(struct gasp_header
, ranges
[num_ranges
]));
2796 version
= GET_BE_WORD(table
->version
);
2799 ERR("Unsupported gasp table format version %u.\n", version
);
2803 for (i
= 0; i
< num_ranges
; ++i
)
2805 flags
= GET_BE_WORD(table
->ranges
[i
].flags
);
2806 if (emsize
<= GET_BE_WORD(table
->ranges
[i
].max_ppem
)) break;
2813 unsigned int opentype_get_cpal_palettecount(const struct dwrite_fonttable
*cpal
)
2815 return table_read_be_word(cpal
, FIELD_OFFSET(struct cpal_header_0
, num_palettes
));
2818 unsigned int opentype_get_cpal_paletteentrycount(const struct dwrite_fonttable
*cpal
)
2820 return table_read_be_word(cpal
, FIELD_OFFSET(struct cpal_header_0
, num_palette_entries
));
2823 HRESULT
opentype_get_cpal_entries(const struct dwrite_fonttable
*cpal
, unsigned int palette
,
2824 unsigned int first_entry_index
, unsigned int entry_count
, DWRITE_COLOR_F
*entries
)
2826 unsigned int num_palettes
, num_palette_entries
, i
;
2827 const struct cpal_color_record
*records
;
2828 const struct cpal_header_0
*header
;
2830 header
= table_read_ensure(cpal
, 0, sizeof(*header
));
2832 if (!cpal
->exists
|| !header
)
2833 return DWRITE_E_NOCOLOR
;
2835 num_palettes
= GET_BE_WORD(header
->num_palettes
);
2836 if (palette
>= num_palettes
)
2837 return DWRITE_E_NOCOLOR
;
2839 header
= table_read_ensure(cpal
, 0, FIELD_OFFSET(struct cpal_header_0
, color_record_indices
[palette
]));
2841 return DWRITE_E_NOCOLOR
;
2843 num_palette_entries
= GET_BE_WORD(header
->num_palette_entries
);
2844 if (first_entry_index
+ entry_count
> num_palette_entries
)
2845 return E_INVALIDARG
;
2847 records
= table_read_ensure(cpal
, GET_BE_DWORD(header
->offset_first_color_record
),
2848 sizeof(*records
) * GET_BE_WORD(header
->num_color_records
));
2850 return DWRITE_E_NOCOLOR
;
2852 first_entry_index
+= GET_BE_WORD(header
->color_record_indices
[palette
]);
2854 for (i
= 0; i
< entry_count
; i
++) {
2855 entries
[i
].u1
.r
= records
[first_entry_index
+ i
].red
/ 255.0f
;
2856 entries
[i
].u2
.g
= records
[first_entry_index
+ i
].green
/ 255.0f
;
2857 entries
[i
].u3
.b
= records
[first_entry_index
+ i
].blue
/ 255.0f
;
2858 entries
[i
].u4
.a
= records
[first_entry_index
+ i
].alpha
/ 255.0f
;
2864 static int colr_compare_gid(const void *g
, const void *r
)
2866 const struct colr_baseglyph_record
*record
= r
;
2867 UINT16 glyph
= *(UINT16
*)g
, GID
= GET_BE_WORD(record
->glyph
);
2872 else if (glyph
< GID
)
2878 HRESULT
opentype_get_colr_glyph(const struct dwrite_fonttable
*colr
, UINT16 glyph
, struct dwrite_colorglyph
*ret
)
2880 unsigned int num_baseglyph_records
, offset_baseglyph_records
;
2881 const struct colr_baseglyph_record
*record
;
2882 const struct colr_layer_record
*layer
;
2883 const struct colr_header
*header
;
2885 memset(ret
, 0, sizeof(*ret
));
2887 ret
->palette_index
= 0xffff;
2889 header
= table_read_ensure(colr
, 0, sizeof(*header
));
2893 num_baseglyph_records
= GET_BE_WORD(header
->num_baseglyph_records
);
2894 offset_baseglyph_records
= GET_BE_DWORD(header
->offset_baseglyph_records
);
2895 if (!table_read_ensure(colr
, offset_baseglyph_records
, num_baseglyph_records
* sizeof(*record
)))
2900 record
= bsearch(&glyph
, colr
->data
+ offset_baseglyph_records
, num_baseglyph_records
,
2901 sizeof(*record
), colr_compare_gid
);
2905 ret
->first_layer
= GET_BE_WORD(record
->first_layer_index
);
2906 ret
->num_layers
= GET_BE_WORD(record
->num_layers
);
2908 if ((layer
= table_read_ensure(colr
, GET_BE_DWORD(header
->offset_layer_records
),
2909 (ret
->first_layer
+ ret
->layer
) * sizeof(*layer
))))
2911 layer
+= ret
->first_layer
+ ret
->layer
;
2912 ret
->glyph
= GET_BE_WORD(layer
->glyph
);
2913 ret
->palette_index
= GET_BE_WORD(layer
->palette_index
);
2919 void opentype_colr_next_glyph(const struct dwrite_fonttable
*colr
, struct dwrite_colorglyph
*glyph
)
2921 const struct colr_layer_record
*layer
;
2922 const struct colr_header
*header
;
2924 /* iterated all the way through */
2925 if (glyph
->layer
== glyph
->num_layers
)
2928 if (!(header
= table_read_ensure(colr
, 0, sizeof(*header
))))
2933 if ((layer
= table_read_ensure(colr
, GET_BE_DWORD(header
->offset_layer_records
),
2934 (glyph
->first_layer
+ glyph
->layer
) * sizeof(*layer
))))
2936 layer
+= glyph
->first_layer
+ glyph
->layer
;
2937 glyph
->glyph
= GET_BE_WORD(layer
->glyph
);
2938 glyph
->palette_index
= GET_BE_WORD(layer
->palette_index
);
2942 static BOOL
opentype_has_font_table(IDWriteFontFace5
*fontface
, UINT32 tag
)
2944 BOOL exists
= FALSE
;
2950 hr
= IDWriteFontFace5_TryGetFontTable(fontface
, tag
, &data
, &size
, &context
, &exists
);
2955 IDWriteFontFace5_ReleaseFontTable(fontface
, context
);
2960 static unsigned int opentype_get_sbix_formats(IDWriteFontFace5
*fontface
)
2962 unsigned int num_strikes
, num_glyphs
, i
, j
, ret
= 0;
2963 const struct sbix_header
*sbix_header
;
2964 struct dwrite_fonttable table
;
2966 memset(&table
, 0, sizeof(table
));
2967 table
.exists
= TRUE
;
2969 if (!get_fontface_table(fontface
, MS_MAXP_TAG
, &table
))
2972 num_glyphs
= table_read_be_word(&table
, FIELD_OFFSET(struct maxp
, num_glyphs
));
2974 IDWriteFontFace5_ReleaseFontTable(fontface
, table
.context
);
2976 memset(&table
, 0, sizeof(table
));
2977 table
.exists
= TRUE
;
2979 if (!get_fontface_table(fontface
, MS_SBIX_TAG
, &table
))
2982 num_strikes
= table_read_be_dword(&table
, FIELD_OFFSET(struct sbix_header
, num_strikes
));
2983 sbix_header
= table_read_ensure(&table
, 0, FIELD_OFFSET(struct sbix_header
, strike_offset
[num_strikes
]));
2987 for (i
= 0; i
< num_strikes
; ++i
)
2989 unsigned int strike_offset
= GET_BE_DWORD(sbix_header
->strike_offset
[i
]);
2990 const struct sbix_strike
*strike
= table_read_ensure(&table
, strike_offset
,
2991 FIELD_OFFSET(struct sbix_strike
, glyphdata_offsets
[num_glyphs
+ 1]));
2996 for (j
= 0; j
< num_glyphs
; j
++)
2998 unsigned int offset
= GET_BE_DWORD(strike
->glyphdata_offsets
[j
]);
2999 unsigned int next_offset
= GET_BE_DWORD(strike
->glyphdata_offsets
[j
+ 1]);
3000 const struct sbix_glyph_data
*glyph_data
;
3002 if (offset
== next_offset
)
3005 glyph_data
= table_read_ensure(&table
, strike_offset
+ offset
, sizeof(*glyph_data
));
3009 switch (glyph_data
->graphic_type
)
3012 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_PNG
;
3015 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_JPEG
;
3018 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_TIFF
;
3021 FIXME("unexpected bitmap format %s\n", debugstr_tag(GET_BE_DWORD(glyph_data
->graphic_type
)));
3027 IDWriteFontFace5_ReleaseFontTable(fontface
, table
.context
);
3032 static unsigned int opentype_get_cblc_formats(IDWriteFontFace5
*fontface
)
3034 const unsigned int format_mask
= DWRITE_GLYPH_IMAGE_FORMATS_PNG
|
3035 DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8
;
3036 const struct cblc_bitmapsize_table
*sizes
;
3037 struct dwrite_fonttable cblc
= { 0 };
3038 unsigned int num_sizes
, i
, ret
= 0;
3039 const struct cblc_header
*header
;
3042 if (!get_fontface_table(fontface
, MS_CBLC_TAG
, &cblc
))
3045 num_sizes
= table_read_be_dword(&cblc
, FIELD_OFFSET(struct cblc_header
, num_sizes
));
3046 sizes
= table_read_ensure(&cblc
, sizeof(*header
), num_sizes
* sizeof(*sizes
));
3050 for (i
= 0; i
< num_sizes
; ++i
)
3052 BYTE bpp
= sizes
[i
].bit_depth
;
3054 if ((ret
& format_mask
) == format_mask
)
3057 if (bpp
== 1 || bpp
== 2 || bpp
== 4 || bpp
== 8)
3058 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_PNG
;
3060 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8
;
3064 IDWriteFontFace5_ReleaseFontTable(fontface
, cblc
.context
);
3069 UINT32
opentype_get_glyph_image_formats(IDWriteFontFace5
*fontface
)
3071 UINT32 ret
= DWRITE_GLYPH_IMAGE_FORMATS_NONE
;
3073 if (opentype_has_font_table(fontface
, MS_GLYF_TAG
))
3074 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE
;
3076 if (opentype_has_font_table(fontface
, MS_CFF__TAG
) ||
3077 opentype_has_font_table(fontface
, MS_CFF2_TAG
))
3078 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_CFF
;
3080 if (opentype_has_font_table(fontface
, MS_COLR_TAG
))
3081 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_COLR
;
3083 if (opentype_has_font_table(fontface
, MS_SVG__TAG
))
3084 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_SVG
;
3086 if (opentype_has_font_table(fontface
, MS_SBIX_TAG
))
3087 ret
|= opentype_get_sbix_formats(fontface
);
3089 if (opentype_has_font_table(fontface
, MS_CBLC_TAG
))
3090 ret
|= opentype_get_cblc_formats(fontface
);
3095 DWRITE_CONTAINER_TYPE
opentype_analyze_container_type(void const *data
, UINT32 data_size
)
3099 if (data_size
< sizeof(DWORD
))
3100 return DWRITE_CONTAINER_TYPE_UNKNOWN
;
3102 /* Both WOFF and WOFF2 start with 4 bytes signature. */
3103 signature
= *(DWORD
*)data
;
3108 return DWRITE_CONTAINER_TYPE_WOFF
;
3110 return DWRITE_CONTAINER_TYPE_WOFF2
;
3112 return DWRITE_CONTAINER_TYPE_UNKNOWN
;
3116 void opentype_layout_scriptshaping_cache_init(struct scriptshaping_cache
*cache
)
3118 cache
->font
->grab_font_table(cache
->context
, MS_GSUB_TAG
, &cache
->gsub
.table
.data
, &cache
->gsub
.table
.size
,
3119 &cache
->gsub
.table
.context
);
3121 if (cache
->gsub
.table
.data
)
3123 cache
->gsub
.script_list
= table_read_be_word(&cache
->gsub
.table
, FIELD_OFFSET(struct gpos_gsub_header
, script_list
));
3124 cache
->gsub
.feature_list
= table_read_be_word(&cache
->gsub
.table
, FIELD_OFFSET(struct gpos_gsub_header
, feature_list
));
3125 cache
->gsub
.lookup_list
= table_read_be_word(&cache
->gsub
.table
, FIELD_OFFSET(struct gpos_gsub_header
, lookup_list
));
3128 cache
->font
->grab_font_table(cache
->context
, MS_GPOS_TAG
, &cache
->gpos
.table
.data
, &cache
->gpos
.table
.size
,
3129 &cache
->gpos
.table
.context
);
3131 if (cache
->gpos
.table
.data
)
3133 cache
->gpos
.script_list
= table_read_be_word(&cache
->gpos
.table
,
3134 FIELD_OFFSET(struct gpos_gsub_header
, script_list
));
3135 cache
->gpos
.feature_list
= table_read_be_word(&cache
->gpos
.table
,
3136 FIELD_OFFSET(struct gpos_gsub_header
, feature_list
));
3137 cache
->gpos
.lookup_list
= table_read_be_word(&cache
->gpos
.table
,
3138 FIELD_OFFSET(struct gpos_gsub_header
, lookup_list
));
3141 cache
->font
->grab_font_table(cache
->context
, MS_GDEF_TAG
, &cache
->gdef
.table
.data
, &cache
->gdef
.table
.size
,
3142 &cache
->gdef
.table
.context
);
3144 if (cache
->gdef
.table
.data
)
3146 unsigned int version
= table_read_be_dword(&cache
->gdef
.table
, 0);
3148 cache
->gdef
.classdef
= table_read_be_word(&cache
->gdef
.table
, FIELD_OFFSET(struct gdef_header
, classdef
));
3149 cache
->gdef
.markattachclassdef
= table_read_be_word(&cache
->gdef
.table
,
3150 FIELD_OFFSET(struct gdef_header
, markattach_classdef
));
3151 if (version
>= 0x00010002)
3152 cache
->gdef
.markglyphsetdef
= table_read_be_word(&cache
->gdef
.table
,
3153 FIELD_OFFSET(struct gdef_header
, markglyphsetdef
));
3157 unsigned int opentype_layout_find_script(const struct scriptshaping_cache
*cache
, unsigned int kind
, DWORD script
,
3158 unsigned int *script_index
)
3160 const struct ot_gsubgpos_table
*table
= kind
== MS_GSUB_TAG
? &cache
->gsub
: &cache
->gpos
;
3161 UINT16 script_count
;
3164 *script_index
= ~0u;
3166 script_count
= table_read_be_word(&table
->table
, table
->script_list
);
3170 for (i
= 0; i
< script_count
; i
++)
3172 unsigned int tag
= table_read_dword(&table
->table
, table
->script_list
+ FIELD_OFFSET(struct ot_script_list
, scripts
) +
3173 i
* sizeof(struct ot_script_record
));
3187 unsigned int opentype_layout_find_language(const struct scriptshaping_cache
*cache
, unsigned int kind
, DWORD language
,
3188 unsigned int script_index
, unsigned int *language_index
)
3190 const struct ot_gsubgpos_table
*table
= kind
== MS_GSUB_TAG
? &cache
->gsub
: &cache
->gpos
;
3191 UINT16 table_offset
, lang_count
;
3194 *language_index
= ~0u;
3196 table_offset
= table_read_be_word(&table
->table
, table
->script_list
+ FIELD_OFFSET(struct ot_script_list
, scripts
) +
3197 script_index
* sizeof(struct ot_script_record
) + FIELD_OFFSET(struct ot_script_record
, script
));
3201 lang_count
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
+
3202 FIELD_OFFSET(struct ot_script
, langsys_count
));
3203 for (i
= 0; i
< lang_count
; i
++)
3205 unsigned int tag
= table_read_dword(&table
->table
, table
->script_list
+ table_offset
+
3206 FIELD_OFFSET(struct ot_script
, langsys
) + i
* sizeof(struct ot_langsys_record
));
3208 if (tag
== language
)
3210 *language_index
= i
;
3215 /* Try 'defaultLangSys' if it's set. */
3216 if (table_read_be_word(&table
->table
, table
->script_list
+ table_offset
))
3222 static int gdef_class_compare_format2(const void *g
, const void *r
)
3224 const struct ot_gdef_class_range
*range
= r
;
3225 UINT16 glyph
= *(UINT16
*)g
;
3227 if (glyph
< GET_BE_WORD(range
->start_glyph
))
3229 else if (glyph
> GET_BE_WORD(range
->end_glyph
))
3235 static unsigned int opentype_layout_get_glyph_class(const struct dwrite_fonttable
*table
,
3236 unsigned int offset
, UINT16 glyph
)
3238 WORD format
= table_read_be_word(table
, offset
), count
;
3239 unsigned int glyph_class
= GDEF_CLASS_UNCLASSIFIED
;
3243 const struct ot_gdef_classdef_format1
*format1
;
3245 count
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gdef_classdef_format1
, glyph_count
));
3246 format1
= table_read_ensure(table
, offset
, FIELD_OFFSET(struct ot_gdef_classdef_format1
, classes
[count
]));
3249 WORD start_glyph
= GET_BE_WORD(format1
->start_glyph
);
3250 if (glyph
>= start_glyph
&& (glyph
- start_glyph
) < count
)
3252 glyph_class
= GET_BE_WORD(format1
->classes
[glyph
- start_glyph
]);
3253 if (glyph_class
> GDEF_CLASS_MAX
)
3254 glyph_class
= GDEF_CLASS_UNCLASSIFIED
;
3258 else if (format
== 2)
3260 const struct ot_gdef_classdef_format2
*format2
;
3262 count
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gdef_classdef_format2
, range_count
));
3263 format2
= table_read_ensure(table
, offset
, FIELD_OFFSET(struct ot_gdef_classdef_format2
, ranges
[count
]));
3266 const struct ot_gdef_class_range
*range
= bsearch(&glyph
, format2
->ranges
, count
,
3267 sizeof(struct ot_gdef_class_range
), gdef_class_compare_format2
);
3268 glyph_class
= range
&& glyph
<= GET_BE_WORD(range
->end_glyph
) ?
3269 GET_BE_WORD(range
->glyph_class
) : GDEF_CLASS_UNCLASSIFIED
;
3270 if (glyph_class
> GDEF_CLASS_MAX
)
3271 glyph_class
= GDEF_CLASS_UNCLASSIFIED
;
3275 WARN("Unknown GDEF format %u.\n", format
);
3280 static unsigned int opentype_set_glyph_props(struct scriptshaping_context
*context
, unsigned int idx
)
3282 struct scriptshaping_cache
*cache
= context
->cache
;
3283 unsigned int glyph_class
= 0, props
;
3285 if (cache
->gdef
.classdef
)
3287 glyph_class
= opentype_layout_get_glyph_class(&cache
->gdef
.table
, cache
->gdef
.classdef
,
3288 context
->u
.buffer
.glyphs
[idx
]);
3291 switch (glyph_class
)
3293 case GDEF_CLASS_BASE
:
3294 props
= GLYPH_PROP_BASE
;
3296 case GDEF_CLASS_LIGATURE
:
3297 props
= GLYPH_PROP_LIGATURE
;
3299 case GDEF_CLASS_MARK
:
3300 props
= GLYPH_PROP_MARK
;
3301 if (cache
->gdef
.markattachclassdef
)
3303 glyph_class
= opentype_layout_get_glyph_class(&cache
->gdef
.table
, cache
->gdef
.markattachclassdef
,
3304 context
->u
.buffer
.glyphs
[idx
]);
3305 props
|= glyph_class
<< 8;
3312 context
->glyph_infos
[idx
].props
= props
;
3317 static void opentype_set_subst_glyph_props(struct scriptshaping_context
*context
, unsigned int idx
)
3319 unsigned int glyph_props
= opentype_set_glyph_props(context
, idx
) & LOOKUP_FLAG_IGNORE_MASK
;
3320 context
->u
.subst
.glyph_props
[idx
].isDiacritic
= !!(glyph_props
== GLYPH_PROP_MARK
);
3321 context
->u
.subst
.glyph_props
[idx
].isZeroWidthSpace
= !!(glyph_props
== GLYPH_PROP_MARK
);
3324 struct coverage_compare_format1_context
3327 const UINT16
*table_base
;
3328 unsigned int *coverage_index
;
3331 static int coverage_compare_format1(const void *left
, const void *right
)
3333 const struct coverage_compare_format1_context
*context
= left
;
3334 UINT16 glyph
= GET_BE_WORD(*(UINT16
*)right
);
3337 ret
= context
->glyph
- glyph
;
3339 *context
->coverage_index
= (UINT16
*)right
- context
->table_base
;
3344 static int coverage_compare_format2(const void *g
, const void *r
)
3346 const struct ot_coverage_range
*range
= r
;
3347 UINT16 glyph
= *(UINT16
*)g
;
3349 if (glyph
< GET_BE_WORD(range
->start_glyph
))
3351 else if (glyph
> GET_BE_WORD(range
->end_glyph
))
3357 static unsigned int opentype_layout_is_glyph_covered(const struct dwrite_fonttable
*table
, unsigned int coverage
,
3360 WORD format
= table_read_be_word(table
, coverage
), count
;
3362 count
= table_read_be_word(table
, coverage
+ 2);
3366 const struct ot_coverage_format1
*format1
= table_read_ensure(table
, coverage
,
3367 FIELD_OFFSET(struct ot_coverage_format1
, glyphs
[count
]));
3368 struct coverage_compare_format1_context context
;
3369 unsigned int coverage_index
= GLYPH_NOT_COVERED
;
3373 context
.glyph
= glyph
;
3374 context
.table_base
= format1
->glyphs
;
3375 context
.coverage_index
= &coverage_index
;
3377 bsearch(&context
, format1
->glyphs
, count
, sizeof(glyph
), coverage_compare_format1
);
3380 return coverage_index
;
3382 else if (format
== 2)
3384 const struct ot_coverage_format2
*format2
= table_read_ensure(table
, coverage
,
3385 FIELD_OFFSET(struct ot_coverage_format2
, ranges
[count
]));
3388 const struct ot_coverage_range
*range
= bsearch(&glyph
, format2
->ranges
, count
,
3389 sizeof(struct ot_coverage_range
), coverage_compare_format2
);
3390 return range
&& glyph
<= GET_BE_WORD(range
->end_glyph
) ?
3391 GET_BE_WORD(range
->startcoverage_index
) + glyph
- GET_BE_WORD(range
->start_glyph
) :
3396 WARN("Unknown coverage format %u.\n", format
);
3401 static inline unsigned int dwrite_popcount(unsigned int x
)
3403 #ifdef HAVE___BUILTIN_POPCOUNT
3404 return __builtin_popcount(x
);
3406 x
-= x
>> 1 & 0x55555555;
3407 x
= (x
& 0x33333333) + (x
>> 2 & 0x33333333);
3408 return ((x
+ (x
>> 4)) & 0x0f0f0f0f) * 0x01010101 >> 24;
3412 static float opentype_scale_gpos_be_value(WORD value
, float emsize
, UINT16 upem
)
3414 return (short)GET_BE_WORD(value
) * emsize
/ upem
;
3417 static int opentype_layout_gpos_get_dev_value(const struct scriptshaping_context
*context
, unsigned int offset
)
3419 const struct dwrite_fonttable
*table
= &context
->table
->table
;
3420 unsigned int start_size
, end_size
, format
, value_word
;
3421 unsigned int index
, ppem
, mask
;
3427 start_size
= table_read_be_word(table
, offset
);
3428 end_size
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gpos_device_table
, end_size
));
3430 ppem
= context
->emsize
;
3431 if (ppem
< start_size
|| ppem
> end_size
)
3434 format
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gpos_device_table
, format
));
3436 if (format
< 1 || format
> 3)
3439 index
= ppem
- start_size
;
3441 value_word
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gpos_device_table
, values
[index
>> (4 - format
)]));
3442 mask
= 0xffff >> (16 - (1 << format
));
3444 value
= (value_word
>> ((index
% (4 - format
)) * (1 << format
))) & mask
;
3446 if ((unsigned int)value
>= ((mask
+ 1) >> 1))
3452 static void opentype_layout_apply_gpos_value(struct scriptshaping_context
*context
, unsigned int table_offset
,
3453 WORD value_format
, const WORD
*values
, unsigned int glyph
)
3455 const struct scriptshaping_cache
*cache
= context
->cache
;
3456 DWRITE_GLYPH_OFFSET
*offset
= &context
->offsets
[glyph
];
3457 float *advance
= &context
->advances
[glyph
];
3462 if (value_format
& GPOS_VALUE_X_PLACEMENT
)
3464 offset
->advanceOffset
+= opentype_scale_gpos_be_value(*values
, context
->emsize
, cache
->upem
);
3467 if (value_format
& GPOS_VALUE_Y_PLACEMENT
)
3469 offset
->ascenderOffset
+= opentype_scale_gpos_be_value(*values
, context
->emsize
, cache
->upem
);
3472 if (value_format
& GPOS_VALUE_X_ADVANCE
)
3474 *advance
+= opentype_scale_gpos_be_value(*values
, context
->emsize
, cache
->upem
);
3477 if (value_format
& GPOS_VALUE_Y_ADVANCE
)
3481 if (value_format
& GPOS_VALUE_X_PLACEMENT_DEVICE
)
3483 offset
->advanceOffset
+= opentype_layout_gpos_get_dev_value(context
, table_offset
+ GET_BE_WORD(*values
));
3486 if (value_format
& GPOS_VALUE_Y_PLACEMENT_DEVICE
)
3488 offset
->ascenderOffset
+= opentype_layout_gpos_get_dev_value(context
, table_offset
+ GET_BE_WORD(*values
));
3491 if (value_format
& GPOS_VALUE_X_ADVANCE_DEVICE
)
3493 *advance
+= opentype_layout_gpos_get_dev_value(context
, table_offset
+ GET_BE_WORD(*values
));
3496 if (value_format
& GPOS_VALUE_Y_ADVANCE_DEVICE
)
3504 unsigned short index
;
3505 unsigned short type
;
3506 unsigned short flags
;
3507 unsigned short subtable_count
;
3510 unsigned int offset
;
3513 static unsigned int opentype_layout_get_gsubgpos_subtable(const struct scriptshaping_context
*context
,
3514 const struct lookup
*lookup
, unsigned int subtable
, unsigned int *lookup_type
)
3516 unsigned int subtable_offset
= table_read_be_word(&context
->table
->table
, lookup
->offset
+
3517 FIELD_OFFSET(struct ot_lookup_table
, subtable
[subtable
]));
3518 const struct ot_gsubgpos_extension_format1
*format1
;
3520 subtable_offset
+= lookup
->offset
;
3522 if ((context
->table
== &context
->cache
->gsub
&& lookup
->type
!= GSUB_LOOKUP_EXTENSION_SUBST
) ||
3523 (context
->table
== &context
->cache
->gpos
&& lookup
->type
!= GPOS_LOOKUP_EXTENSION_POSITION
))
3525 *lookup_type
= lookup
->type
;
3526 return subtable_offset
;
3531 if (!(format1
= table_read_ensure(&context
->table
->table
, subtable_offset
, sizeof(*format1
))))
3534 if (GET_BE_WORD(format1
->format
) != 1)
3536 WARN("Unexpected extension table format %#x.\n", format1
->format
);
3540 *lookup_type
= GET_BE_WORD(format1
->lookup_type
);
3541 return subtable_offset
+ GET_BE_DWORD(format1
->extension_offset
);
3546 unsigned int offset
;
3547 unsigned int subtable_count
;
3553 /* First two to fit matching callback result. */
3559 struct match_context
;
3562 const struct match_context
*mc
;
3563 unsigned int subtable_offset
;
3566 typedef BOOL (*p_match_func
)(UINT16 glyph
, UINT16 glyph_data
, const struct match_data
*match_data
);
3568 struct match_context
3570 struct scriptshaping_context
*context
;
3571 unsigned int backtrack_offset
;
3572 unsigned int input_offset
;
3573 unsigned int lookahead_offset
;
3574 p_match_func match_func
;
3575 const struct lookup
*lookup
;
3578 struct glyph_iterator
3580 struct scriptshaping_context
*context
;
3585 p_match_func match_func
;
3586 const UINT16
*glyph_data
;
3587 const struct match_data
*match_data
;
3590 static void glyph_iterator_init(struct scriptshaping_context
*context
, unsigned int flags
, unsigned int pos
,
3591 unsigned int len
, struct glyph_iterator
*iter
)
3593 iter
->context
= context
;
3594 iter
->flags
= flags
;
3598 iter
->match_func
= NULL
;
3599 iter
->match_data
= NULL
;
3600 iter
->glyph_data
= NULL
;
3603 struct ot_gdef_mark_glyph_sets
3610 static BOOL
opentype_match_glyph_func(UINT16 glyph
, UINT16 glyph_data
, const struct match_data
*data
)
3612 return glyph
== glyph_data
;
3615 static BOOL
opentype_match_class_func(UINT16 glyph
, UINT16 glyph_data
, const struct match_data
*data
)
3617 const struct match_context
*mc
= data
->mc
;
3618 UINT16 glyph_class
= opentype_layout_get_glyph_class(&mc
->context
->table
->table
, data
->subtable_offset
, glyph
);
3619 return glyph_class
== glyph_data
;
3622 static BOOL
opentype_match_coverage_func(UINT16 glyph
, UINT16 glyph_data
, const struct match_data
*data
)
3624 const struct match_context
*mc
= data
->mc
;
3625 return opentype_layout_is_glyph_covered(&mc
->context
->table
->table
, data
->subtable_offset
+ glyph_data
, glyph
)
3626 != GLYPH_NOT_COVERED
;
3629 static BOOL
opentype_layout_mark_set_covers(const struct scriptshaping_cache
*cache
, unsigned int set_index
,
3632 unsigned int format
, offset
= cache
->gdef
.markglyphsetdef
, coverage_offset
, set_count
;
3637 format
= table_read_be_word(&cache
->gdef
.table
, offset
);
3641 set_count
= table_read_be_word(&cache
->gdef
.table
, offset
+ 2);
3642 if (!set_count
|| set_index
>= set_count
)
3645 coverage_offset
= table_read_be_dword(&cache
->gdef
.table
, offset
+ 2 + set_index
* sizeof(coverage_offset
));
3646 return opentype_layout_is_glyph_covered(&cache
->gdef
.table
, offset
+ coverage_offset
, glyph
) != GLYPH_NOT_COVERED
;
3649 WARN("Unexpected MarkGlyphSets format %#x.\n", format
);
3654 static BOOL
lookup_is_glyph_match(const struct scriptshaping_context
*context
, unsigned int idx
, unsigned int match_props
)
3656 unsigned int glyph_props
= context
->glyph_infos
[idx
].props
;
3657 UINT16 glyph
= context
->u
.buffer
.glyphs
[idx
];
3659 if (glyph_props
& match_props
& LOOKUP_FLAG_IGNORE_MASK
)
3662 if (!(glyph_props
& GLYPH_PROP_MARK
))
3665 if (match_props
& LOOKUP_FLAG_USE_MARK_FILTERING_SET
)
3666 return opentype_layout_mark_set_covers(context
->cache
, match_props
>> 16, glyph
);
3668 if (match_props
& LOOKUP_FLAG_MARK_ATTACHMENT_TYPE
)
3669 return (match_props
& LOOKUP_FLAG_MARK_ATTACHMENT_TYPE
) == (glyph_props
& LOOKUP_FLAG_MARK_ATTACHMENT_TYPE
);
3674 static enum iterator_match
glyph_iterator_may_skip(const struct glyph_iterator
*iter
)
3676 if (!lookup_is_glyph_match(iter
->context
, iter
->pos
, iter
->flags
))
3682 static enum iterator_match
glyph_iterator_may_match(const struct glyph_iterator
*iter
)
3684 if (!(iter
->mask
& iter
->context
->glyph_infos
[iter
->pos
].mask
))
3687 /* Glyph data is used for input, backtrack, and lookahead arrays, swap it here instead of doing that
3688 in all matching functions. */
3689 if (iter
->match_func
)
3690 return !!iter
->match_func(iter
->context
->u
.buffer
.glyphs
[iter
->pos
], GET_BE_WORD(*iter
->glyph_data
), iter
->match_data
);
3695 static BOOL
glyph_iterator_next(struct glyph_iterator
*iter
)
3697 enum iterator_match skip
, match
;
3699 while (iter
->pos
+ iter
->len
< iter
->context
->glyph_count
)
3703 skip
= glyph_iterator_may_skip(iter
);
3704 if (skip
== ITER_YES
)
3707 match
= glyph_iterator_may_match(iter
);
3708 if (match
== ITER_YES
|| (match
== ITER_MAYBE
&& skip
== ITER_NO
))
3711 if (iter
->glyph_data
)
3716 if (skip
== ITER_NO
)
3723 static BOOL
glyph_iterator_prev(struct glyph_iterator
*iter
)
3725 enum iterator_match skip
, match
;
3727 while (iter
->pos
> iter
->len
- 1)
3731 skip
= glyph_iterator_may_skip(iter
);
3732 if (skip
== ITER_YES
)
3735 match
= glyph_iterator_may_match(iter
);
3736 if (match
== ITER_YES
|| (match
== ITER_MAYBE
&& skip
== ITER_NO
))
3739 if (iter
->glyph_data
)
3744 if (skip
== ITER_NO
)
3751 static BOOL
opentype_layout_apply_gpos_single_adjustment(struct scriptshaping_context
*context
,
3752 const struct lookup
*lookup
, unsigned int subtable_offset
)
3754 const struct dwrite_fonttable
*table
= &context
->table
->table
;
3755 UINT16 format
, value_format
, value_len
, coverage
, glyph
;
3757 unsigned int coverage_index
;
3759 format
= table_read_be_word(table
, subtable_offset
);
3761 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_singlepos_format1
, coverage
));
3762 value_format
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_singlepos_format1
, value_format
));
3763 value_len
= dwrite_popcount(value_format
);
3765 glyph
= context
->u
.pos
.glyphs
[context
->cur
];
3769 const struct ot_gpos_singlepos_format1
*format1
= table_read_ensure(table
, subtable_offset
,
3770 FIELD_OFFSET(struct ot_gpos_singlepos_format1
, value
[value_len
]));
3772 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
3773 if (coverage_index
== GLYPH_NOT_COVERED
)
3776 opentype_layout_apply_gpos_value(context
, subtable_offset
, value_format
, format1
->value
, context
->cur
);
3778 else if (format
== 2)
3780 WORD value_count
= table_read_be_word(table
, subtable_offset
+
3781 FIELD_OFFSET(struct ot_gpos_singlepos_format2
, value_count
));
3782 const struct ot_gpos_singlepos_format2
*format2
= table_read_ensure(table
, subtable_offset
,
3783 FIELD_OFFSET(struct ot_gpos_singlepos_format2
, values
) + value_count
* value_len
* sizeof(WORD
));
3785 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
3786 if (coverage_index
== GLYPH_NOT_COVERED
|| coverage_index
>= value_count
)
3789 opentype_layout_apply_gpos_value(context
, subtable_offset
, value_format
, &format2
->values
[coverage_index
* value_len
],
3794 WARN("Unknown single adjustment format %u.\n", format
);
3803 static int gpos_pair_adjustment_compare_format1(const void *g
, const void *r
)
3805 const struct ot_gpos_pairvalue
*pairvalue
= r
;
3806 UINT16 second_glyph
= GET_BE_WORD(pairvalue
->second_glyph
);
3807 return *(UINT16
*)g
- second_glyph
;
3810 static BOOL
opentype_layout_apply_gpos_pair_adjustment(struct scriptshaping_context
*context
,
3811 const struct lookup
*lookup
, unsigned int subtable_offset
)
3813 const struct dwrite_fonttable
*table
= &context
->table
->table
;
3814 unsigned int first_glyph
, second_glyph
;
3815 struct glyph_iterator iter_pair
;
3816 WORD format
, coverage
;
3818 WORD value_format1
, value_format2
, value_len1
, value_len2
;
3819 unsigned int coverage_index
;
3821 glyph_iterator_init(context
, lookup
->flags
, context
->cur
, 1, &iter_pair
);
3822 if (!glyph_iterator_next(&iter_pair
))
3825 if (context
->is_rtl
)
3827 first_glyph
= iter_pair
.pos
;
3828 second_glyph
= context
->cur
;
3832 first_glyph
= context
->cur
;
3833 second_glyph
= iter_pair
.pos
;
3836 format
= table_read_be_word(table
, subtable_offset
);
3838 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_pairpos_format1
, coverage
));
3842 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, context
->u
.pos
.glyphs
[first_glyph
]);
3843 if (coverage_index
== GLYPH_NOT_COVERED
)
3848 const struct ot_gpos_pairpos_format1
*format1
;
3849 WORD pairset_count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_pairpos_format1
,
3851 unsigned int pairvalue_len
, pairset_offset
;
3852 const struct ot_gpos_pairset
*pairset
;
3853 const WORD
*pairvalue
;
3854 WORD pairvalue_count
;
3856 if (!pairset_count
|| coverage_index
>= pairset_count
)
3859 format1
= table_read_ensure(table
, subtable_offset
, FIELD_OFFSET(struct ot_gpos_pairpos_format1
, pairsets
[pairset_count
]));
3863 /* Ordered paired values. */
3864 pairvalue_count
= table_read_be_word(table
, subtable_offset
+ GET_BE_WORD(format1
->pairsets
[coverage_index
]));
3865 if (!pairvalue_count
)
3868 /* Structure length is variable, but does not change across the subtable. */
3869 value_format1
= GET_BE_WORD(format1
->value_format1
) & 0xff;
3870 value_format2
= GET_BE_WORD(format1
->value_format2
) & 0xff;
3872 value_len1
= dwrite_popcount(value_format1
);
3873 value_len2
= dwrite_popcount(value_format2
);
3874 pairvalue_len
= FIELD_OFFSET(struct ot_gpos_pairvalue
, data
) + value_len1
* sizeof(WORD
) +
3875 value_len2
* sizeof(WORD
);
3877 pairset_offset
= subtable_offset
+ GET_BE_WORD(format1
->pairsets
[coverage_index
]);
3878 pairset
= table_read_ensure(table
, subtable_offset
+ pairset_offset
, pairvalue_len
* pairvalue_count
);
3882 pairvalue
= bsearch(&context
->u
.pos
.glyphs
[second_glyph
], pairset
->pairvalues
, pairvalue_count
,
3883 pairvalue_len
, gpos_pair_adjustment_compare_format1
);
3887 pairvalue
+= 1; /* Skip SecondGlyph. */
3888 opentype_layout_apply_gpos_value(context
, pairset_offset
, value_format1
, pairvalue
, first_glyph
);
3889 opentype_layout_apply_gpos_value(context
, pairset_offset
, value_format2
, pairvalue
+ value_len1
,
3892 context
->cur
= iter_pair
.pos
;
3896 else if (format
== 2)
3898 const struct ot_gpos_pairpos_format2
*format2
;
3899 WORD class1_count
, class2_count
;
3900 unsigned int class1
, class2
;
3901 const WCHAR
*values
;
3903 value_format1
= table_read_be_word(table
, subtable_offset
+
3904 FIELD_OFFSET(struct ot_gpos_pairpos_format2
, value_format1
)) & 0xff;
3905 value_format2
= table_read_be_word(table
, subtable_offset
+
3906 FIELD_OFFSET(struct ot_gpos_pairpos_format2
, value_format2
)) & 0xff;
3908 class1_count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_pairpos_format2
, class1_count
));
3909 class2_count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_pairpos_format2
, class2_count
));
3911 value_len1
= dwrite_popcount(value_format1
);
3912 value_len2
= dwrite_popcount(value_format2
);
3914 format2
= table_read_ensure(table
, subtable_offset
, FIELD_OFFSET(struct ot_gpos_pairpos_format2
,
3915 values
[class1_count
* class2_count
* (value_len1
+ value_len2
)]));
3919 class1
= opentype_layout_get_glyph_class(table
, subtable_offset
+ GET_BE_WORD(format2
->class_def1
),
3920 context
->u
.pos
.glyphs
[first_glyph
]);
3921 class2
= opentype_layout_get_glyph_class(table
, subtable_offset
+ GET_BE_WORD(format2
->class_def2
),
3922 context
->u
.pos
.glyphs
[second_glyph
]);
3924 if (!(class1
< class1_count
&& class2
< class2_count
))
3927 values
= &format2
->values
[(class1
* class2_count
+ class2
) * (value_len1
+ value_len2
)];
3928 opentype_layout_apply_gpos_value(context
, subtable_offset
, value_format1
, values
, first_glyph
);
3929 opentype_layout_apply_gpos_value(context
, subtable_offset
, value_format2
, values
+ value_len1
,
3932 context
->cur
= iter_pair
.pos
;
3938 WARN("Unknown pair adjustment format %u.\n", format
);
3945 static void opentype_layout_gpos_get_anchor(const struct scriptshaping_context
*context
, unsigned int anchor_offset
,
3946 unsigned int glyph_index
, float *x
, float *y
)
3948 const struct scriptshaping_cache
*cache
= context
->cache
;
3949 const struct dwrite_fonttable
*table
= &context
->table
->table
;
3951 WORD format
= table_read_be_word(table
, anchor_offset
);
3957 const struct ot_gpos_anchor_format1
*format1
= table_read_ensure(table
, anchor_offset
, sizeof(*format1
));
3961 *x
= opentype_scale_gpos_be_value(format1
->x_coord
, context
->emsize
, cache
->upem
);
3962 *y
= opentype_scale_gpos_be_value(format1
->y_coord
, context
->emsize
, cache
->upem
);
3965 else if (format
== 2)
3967 const struct ot_gpos_anchor_format2
*format2
= table_read_ensure(table
, anchor_offset
, sizeof(*format2
));
3971 if (context
->measuring_mode
!= DWRITE_MEASURING_MODE_NATURAL
)
3972 FIXME("Use outline anchor point for glyph %u.\n", context
->u
.pos
.glyphs
[glyph_index
]);
3974 *x
= opentype_scale_gpos_be_value(format2
->x_coord
, context
->emsize
, cache
->upem
);
3975 *y
= opentype_scale_gpos_be_value(format2
->y_coord
, context
->emsize
, cache
->upem
);
3978 else if (format
== 3)
3980 const struct ot_gpos_anchor_format3
*format3
= table_read_ensure(table
, anchor_offset
, sizeof(*format3
));
3984 *x
= opentype_scale_gpos_be_value(format3
->x_coord
, context
->emsize
, cache
->upem
);
3985 *y
= opentype_scale_gpos_be_value(format3
->y_coord
, context
->emsize
, cache
->upem
);
3987 if (context
->measuring_mode
!= DWRITE_MEASURING_MODE_NATURAL
)
3989 if (format3
->x_dev_offset
)
3990 *x
+= opentype_layout_gpos_get_dev_value(context
, anchor_offset
+ GET_BE_WORD(format3
->x_dev_offset
));
3991 if (format3
->y_dev_offset
)
3992 *y
+= opentype_layout_gpos_get_dev_value(context
, anchor_offset
+ GET_BE_WORD(format3
->y_dev_offset
));
3997 WARN("Unknown anchor format %u.\n", format
);
4000 static BOOL
opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_context
*context
,
4001 const struct lookup
*lookup
, unsigned int subtable_offset
)
4003 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4004 UINT16 format
, glyph
;
4006 format
= table_read_be_word(table
, subtable_offset
);
4007 glyph
= context
->u
.pos
.glyphs
[context
->cur
];
4011 WORD coverage_offset
= table_read_be_word(table
, subtable_offset
+
4012 FIELD_OFFSET(struct ot_gpos_cursive_format1
, coverage
));
4013 unsigned int glyph_index
, entry_count
, entry_anchor
, exit_anchor
;
4014 float entry_x
, entry_y
, exit_x
, exit_y
, delta
;
4015 struct glyph_iterator prev_iter
;
4017 if (!coverage_offset
)
4020 entry_count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_cursive_format1
, count
));
4022 glyph_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage_offset
, glyph
);
4023 if (glyph_index
== GLYPH_NOT_COVERED
|| glyph_index
>= entry_count
)
4026 entry_anchor
= table_read_be_word(table
, subtable_offset
+
4027 FIELD_OFFSET(struct ot_gpos_cursive_format1
, anchors
[glyph_index
* 2]));
4031 glyph_iterator_init(context
, lookup
->flags
, context
->cur
, 1, &prev_iter
);
4032 if (!glyph_iterator_prev(&prev_iter
))
4035 glyph_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage_offset
,
4036 context
->u
.pos
.glyphs
[prev_iter
.pos
]);
4037 if (glyph_index
== GLYPH_NOT_COVERED
|| glyph_index
>= entry_count
)
4040 exit_anchor
= table_read_be_word(table
, subtable_offset
+
4041 FIELD_OFFSET(struct ot_gpos_cursive_format1
, anchors
[glyph_index
* 2 + 1]));
4045 opentype_layout_gpos_get_anchor(context
, subtable_offset
+ exit_anchor
, prev_iter
.pos
, &exit_x
, &exit_y
);
4046 opentype_layout_gpos_get_anchor(context
, subtable_offset
+ entry_anchor
, context
->cur
, &entry_x
, &entry_y
);
4048 if (context
->is_rtl
)
4050 delta
= exit_x
+ context
->offsets
[prev_iter
.pos
].advanceOffset
;
4051 context
->advances
[prev_iter
.pos
] -= delta
;
4052 context
->advances
[context
->cur
] = entry_x
+ context
->offsets
[context
->cur
].advanceOffset
;
4053 context
->offsets
[prev_iter
.pos
].advanceOffset
-= delta
;
4057 delta
= entry_x
+ context
->offsets
[context
->cur
].advanceOffset
;
4058 context
->advances
[prev_iter
.pos
] = exit_x
+ context
->offsets
[prev_iter
.pos
].advanceOffset
;
4059 context
->advances
[context
->cur
] -= delta
;
4060 context
->offsets
[context
->cur
].advanceOffset
-= delta
;
4063 if (lookup
->flags
& LOOKUP_FLAG_RTL
)
4064 context
->offsets
[prev_iter
.pos
].ascenderOffset
= entry_y
- exit_y
;
4066 context
->offsets
[context
->cur
].ascenderOffset
= exit_y
- entry_y
;
4072 WARN("Unknown cursive attachment format %u.\n", format
);
4079 static BOOL
opentype_layout_apply_mark_array(struct scriptshaping_context
*context
, unsigned int subtable_offset
,
4080 unsigned int mark_array
, unsigned int mark_index
, unsigned int glyph_index
, unsigned int anchors_matrix
,
4081 unsigned int class_count
, unsigned int glyph_pos
)
4083 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4084 unsigned int mark_class
, mark_count
, glyph_count
;
4085 const struct ot_gpos_mark_record
*record
;
4086 float mark_x
, mark_y
, base_x
, base_y
;
4087 const UINT16
*anchors
;
4089 mark_count
= table_read_be_word(table
, subtable_offset
+ mark_array
);
4090 if (mark_index
>= mark_count
) return FALSE
;
4092 if (!(record
= table_read_ensure(table
, subtable_offset
+ mark_array
+
4093 FIELD_OFFSET(struct ot_gpos_mark_array
, records
[mark_index
]), sizeof(*record
))))
4098 mark_class
= GET_BE_WORD(record
->mark_class
);
4099 if (mark_class
>= class_count
) return FALSE
;
4101 glyph_count
= table_read_be_word(table
, subtable_offset
+ anchors_matrix
);
4102 if (glyph_index
>= glyph_count
) return FALSE
;
4104 /* Anchors data is stored as two dimensional array [glyph_count][class_count], starting with row count field. */
4105 anchors
= table_read_ensure(table
, subtable_offset
+ anchors_matrix
+ 2, glyph_count
* class_count
* sizeof(*anchors
));
4106 if (!anchors
) return FALSE
;
4108 opentype_layout_gpos_get_anchor(context
, subtable_offset
+ mark_array
+ GET_BE_WORD(record
->mark_anchor
),
4109 context
->cur
, &mark_x
, &mark_y
);
4110 opentype_layout_gpos_get_anchor(context
, subtable_offset
+ anchors_matrix
+
4111 GET_BE_WORD(anchors
[glyph_index
* class_count
+ mark_class
]), glyph_pos
, &base_x
, &base_y
);
4113 if (context
->is_rtl
)
4114 context
->offsets
[context
->cur
].advanceOffset
= mark_x
- base_x
;
4116 context
->offsets
[context
->cur
].advanceOffset
= -context
->advances
[glyph_pos
] + base_x
- mark_x
;
4118 context
->offsets
[context
->cur
].ascenderOffset
= base_y
- mark_y
;
4124 static BOOL
opentype_layout_apply_gpos_mark_to_base_attachment(struct scriptshaping_context
*context
,
4125 const struct lookup
*lookup
, unsigned int subtable_offset
)
4127 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4130 format
= table_read_be_word(table
, subtable_offset
);
4134 const struct ot_gpos_mark_to_base_format1
*format1
;
4135 unsigned int base_index
, mark_index
;
4136 struct glyph_iterator base_iter
;
4138 if (!(format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
)))) return FALSE
;
4140 mark_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->mark_coverage
),
4141 context
->u
.pos
.glyphs
[context
->cur
]);
4142 if (mark_index
== GLYPH_NOT_COVERED
) return FALSE
;
4144 /* Look back for first base glyph. */
4145 glyph_iterator_init(context
, LOOKUP_FLAG_IGNORE_MARKS
, context
->cur
, 1, &base_iter
);
4146 if (!glyph_iterator_prev(&base_iter
))
4149 base_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->base_coverage
),
4150 context
->u
.pos
.glyphs
[base_iter
.pos
]);
4151 if (base_index
== GLYPH_NOT_COVERED
) return FALSE
;
4153 return opentype_layout_apply_mark_array(context
, subtable_offset
, GET_BE_WORD(format1
->mark_array
), mark_index
,
4154 base_index
, GET_BE_WORD(format1
->base_array
), GET_BE_WORD(format1
->mark_class_count
), base_iter
.pos
);
4158 WARN("Unknown mark-to-base format %u.\n", format
);
4165 static const UINT16
* table_read_array_be_word(const struct dwrite_fonttable
*table
, unsigned int offset
,
4166 unsigned int index
, UINT16
*data
)
4168 unsigned int count
= table_read_be_word(table
, offset
);
4169 const UINT16
*array
;
4171 if (index
!= ~0u && index
>= count
) return NULL
;
4172 if (!(array
= table_read_ensure(table
, offset
+ 2, count
* sizeof(*array
)))) return FALSE
;
4173 *data
= index
== ~0u ? count
: GET_BE_WORD(array
[index
]);
4177 static BOOL
opentype_layout_apply_gpos_mark_to_lig_attachment(struct scriptshaping_context
*context
,
4178 const struct lookup
*lookup
, unsigned int subtable_offset
)
4180 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4183 format
= table_read_be_word(table
, subtable_offset
);
4187 unsigned int mark_index
, lig_index
, comp_index
, class_count
, comp_count
;
4188 const struct ot_gpos_mark_to_lig_format1
*format1
;
4189 struct glyph_iterator lig_iter
;
4190 unsigned int lig_array
;
4193 if (!(format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
)))) return FALSE
;
4195 mark_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->mark_coverage
),
4196 context
->u
.pos
.glyphs
[context
->cur
]);
4197 if (mark_index
== GLYPH_NOT_COVERED
) return FALSE
;
4199 glyph_iterator_init(context
, LOOKUP_FLAG_IGNORE_MARKS
, context
->cur
, 1, &lig_iter
);
4200 if (!glyph_iterator_prev(&lig_iter
))
4203 lig_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->lig_coverage
),
4204 context
->u
.pos
.glyphs
[lig_iter
.pos
]);
4205 if (lig_index
== GLYPH_NOT_COVERED
) return FALSE
;
4207 class_count
= GET_BE_WORD(format1
->mark_class_count
);
4209 lig_array
= GET_BE_WORD(format1
->lig_array
);
4211 if (!table_read_array_be_word(table
, subtable_offset
+ lig_array
, lig_index
, &lig_attach
)) return FALSE
;
4213 comp_count
= table_read_be_word(table
, subtable_offset
+ lig_array
+ lig_attach
);
4214 if (!comp_count
) return FALSE
;
4216 comp_index
= context
->u
.buffer
.glyph_props
[lig_iter
.pos
].components
-
4217 context
->u
.buffer
.glyph_props
[context
->cur
].lig_component
- 1;
4218 if (comp_index
>= comp_count
) return FALSE
;
4220 return opentype_layout_apply_mark_array(context
, subtable_offset
, GET_BE_WORD(format1
->mark_array
), mark_index
,
4221 comp_index
, lig_array
+ lig_attach
, class_count
, lig_iter
.pos
);
4224 WARN("Unknown mark-to-ligature format %u.\n", format
);
4229 static BOOL
opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshaping_context
*context
,
4230 const struct lookup
*lookup
, unsigned int subtable_offset
)
4232 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4235 format
= table_read_be_word(table
, subtable_offset
);
4239 const struct ot_gpos_mark_to_mark_format1
*format1
;
4240 unsigned int mark1_index
, mark2_index
;
4241 struct glyph_iterator mark_iter
;
4243 if (!(format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
)))) return FALSE
;
4245 mark1_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->mark1_coverage
),
4246 context
->u
.pos
.glyphs
[context
->cur
]);
4247 if (mark1_index
== GLYPH_NOT_COVERED
) return FALSE
;
4249 glyph_iterator_init(context
, lookup
->flags
& ~LOOKUP_FLAG_IGNORE_MASK
, context
->cur
, 1, &mark_iter
);
4250 if (!glyph_iterator_prev(&mark_iter
))
4253 if (!context
->u
.pos
.glyph_props
[mark_iter
.pos
].isDiacritic
)
4256 mark2_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->mark2_coverage
),
4257 context
->u
.pos
.glyphs
[mark_iter
.pos
]);
4258 if (mark2_index
== GLYPH_NOT_COVERED
) return FALSE
;
4260 return opentype_layout_apply_mark_array(context
, subtable_offset
, GET_BE_WORD(format1
->mark1_array
), mark1_index
,
4261 mark2_index
, GET_BE_WORD(format1
->mark2_array
), GET_BE_WORD(format1
->mark_class_count
), mark_iter
.pos
);
4265 WARN("Unknown mark-to-mark format %u.\n", format
);
4272 static BOOL
opentype_layout_apply_context(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4273 unsigned int subtable_offset
);
4274 static BOOL
opentype_layout_apply_chain_context(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4275 unsigned int subtable_offset
);
4277 static BOOL
opentype_layout_apply_gpos_lookup(struct scriptshaping_context
*context
, const struct lookup
*lookup
)
4279 unsigned int i
, lookup_type
;
4282 for (i
= 0; i
< lookup
->subtable_count
; ++i
)
4284 unsigned int subtable_offset
= opentype_layout_get_gsubgpos_subtable(context
, lookup
, i
, &lookup_type
);
4286 switch (lookup_type
)
4288 case GPOS_LOOKUP_SINGLE_ADJUSTMENT
:
4289 ret
= opentype_layout_apply_gpos_single_adjustment(context
, lookup
, subtable_offset
);
4291 case GPOS_LOOKUP_PAIR_ADJUSTMENT
:
4292 ret
= opentype_layout_apply_gpos_pair_adjustment(context
, lookup
, subtable_offset
);
4294 case GPOS_LOOKUP_CURSIVE_ATTACHMENT
:
4295 ret
= opentype_layout_apply_gpos_cursive_attachment(context
, lookup
, subtable_offset
);
4297 case GPOS_LOOKUP_MARK_TO_BASE_ATTACHMENT
:
4298 ret
= opentype_layout_apply_gpos_mark_to_base_attachment(context
, lookup
, subtable_offset
);
4300 case GPOS_LOOKUP_MARK_TO_LIGATURE_ATTACHMENT
:
4301 ret
= opentype_layout_apply_gpos_mark_to_lig_attachment(context
, lookup
, subtable_offset
);
4303 case GPOS_LOOKUP_MARK_TO_MARK_ATTACHMENT
:
4304 ret
= opentype_layout_apply_gpos_mark_to_mark_attachment(context
, lookup
, subtable_offset
);
4306 case GPOS_LOOKUP_CONTEXTUAL_POSITION
:
4307 ret
= opentype_layout_apply_context(context
, lookup
, subtable_offset
);
4309 case GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION
:
4310 ret
= opentype_layout_apply_chain_context(context
, lookup
, subtable_offset
);
4312 case GPOS_LOOKUP_EXTENSION_POSITION
:
4313 WARN("Recursive extension lookup.\n");
4316 WARN("Unknown lookup type %u.\n", lookup_type
);
4328 struct lookup
*lookups
;
4333 static int lookups_sorting_compare(const void *a
, const void *b
)
4335 const struct lookup
*left
= (const struct lookup
*)a
;
4336 const struct lookup
*right
= (const struct lookup
*)b
;
4337 return left
->index
< right
->index
? -1 : left
->index
> right
->index
? 1 : 0;
4340 static BOOL
opentype_layout_init_lookup(const struct ot_gsubgpos_table
*table
, unsigned short lookup_index
, unsigned int mask
,
4341 struct lookup
*lookup
)
4343 unsigned short subtable_count
, lookup_type
, flags
, mark_filtering_set
;
4344 const struct ot_lookup_table
*lookup_table
;
4345 unsigned int offset
;
4347 if (!(offset
= table_read_be_word(&table
->table
, table
->lookup_list
+
4348 FIELD_OFFSET(struct ot_lookup_list
, lookup
[lookup_index
]))))
4353 offset
+= table
->lookup_list
;
4355 if (!(lookup_table
= table_read_ensure(&table
->table
, offset
, sizeof(*lookup_table
))))
4358 if (!(subtable_count
= GET_BE_WORD(lookup_table
->subtable_count
)))
4361 lookup_type
= GET_BE_WORD(lookup_table
->lookup_type
);
4362 flags
= GET_BE_WORD(lookup_table
->flags
);
4364 if (flags
& LOOKUP_FLAG_USE_MARK_FILTERING_SET
)
4366 mark_filtering_set
= table_read_be_word(&table
->table
, offset
+
4367 FIELD_OFFSET(struct ot_lookup_table
, subtable
[subtable_count
]));
4368 flags
|= mark_filtering_set
<< 16;
4371 lookup
->index
= lookup_index
;
4372 lookup
->type
= lookup_type
;
4373 lookup
->flags
= flags
;
4374 lookup
->subtable_count
= subtable_count
;
4375 lookup
->mask
= mask
;
4376 lookup
->offset
= offset
;
4381 static void opentype_layout_add_lookups(const struct ot_feature_list
*feature_list
, UINT16 total_lookup_count
,
4382 const struct ot_gsubgpos_table
*table
, struct shaping_feature
*feature
, struct lookups
*lookups
)
4384 UINT16 feature_offset
, lookup_count
;
4387 /* Feature wasn't found */
4388 if (feature
->index
== 0xffff)
4391 feature_offset
= GET_BE_WORD(feature_list
->features
[feature
->index
].offset
);
4393 lookup_count
= table_read_be_word(&table
->table
, table
->feature_list
+ feature_offset
+
4394 FIELD_OFFSET(struct ot_feature
, lookup_count
));
4398 if (!dwrite_array_reserve((void **)&lookups
->lookups
, &lookups
->capacity
, lookups
->count
+ lookup_count
,
4399 sizeof(*lookups
->lookups
)))
4404 for (i
= 0; i
< lookup_count
; ++i
)
4406 UINT16 lookup_index
= table_read_be_word(&table
->table
, table
->feature_list
+ feature_offset
+
4407 FIELD_OFFSET(struct ot_feature
, lookuplist_index
[i
]));
4409 if (lookup_index
>= total_lookup_count
)
4412 if (opentype_layout_init_lookup(table
, lookup_index
, feature
->mask
, &lookups
->lookups
[lookups
->count
]))
4417 static void opentype_layout_collect_lookups(struct scriptshaping_context
*context
, unsigned int script_index
,
4418 unsigned int language_index
, const struct shaping_features
*features
, const struct ot_gsubgpos_table
*table
,
4419 struct lookups
*lookups
)
4421 unsigned int last_num_lookups
= 0, stage
, script_feature_count
= 0;
4422 UINT16 total_feature_count
, total_lookup_count
;
4423 struct shaping_feature required_feature
= { 0 };
4424 const struct ot_feature_list
*feature_list
;
4425 const struct ot_langsys
*langsys
= NULL
;
4426 struct shaping_feature
*feature
;
4427 unsigned int i
, j
, next_bit
;
4428 unsigned int global_bit_shift
= 1;
4429 unsigned int global_bit_mask
= 2;
4430 UINT16 feature_index
;
4432 if (!table
->table
.data
)
4435 if (script_index
!= ~0u)
4437 unsigned int table_offset
, langsys_offset
;
4439 /* ScriptTable offset. */
4440 table_offset
= table_read_be_word(&table
->table
, table
->script_list
+ FIELD_OFFSET(struct ot_script_list
, scripts
) +
4441 script_index
* sizeof(struct ot_script_record
) + FIELD_OFFSET(struct ot_script_record
, script
));
4445 if (language_index
== ~0u)
4446 langsys_offset
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
);
4448 langsys_offset
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
+
4449 FIELD_OFFSET(struct ot_script
, langsys
) + language_index
* sizeof(struct ot_langsys_record
) +
4450 FIELD_OFFSET(struct ot_langsys_record
, langsys
));
4451 langsys_offset
+= table
->script_list
+ table_offset
;
4453 script_feature_count
= table_read_be_word(&table
->table
, langsys_offset
+ FIELD_OFFSET(struct ot_langsys
, feature_count
));
4454 if (script_feature_count
)
4455 langsys
= table_read_ensure(&table
->table
, langsys_offset
,
4456 FIELD_OFFSET(struct ot_langsys
, feature_index
[script_feature_count
]));
4458 script_feature_count
= 0;
4461 total_feature_count
= table_read_be_word(&table
->table
, table
->feature_list
);
4462 if (!total_feature_count
)
4465 total_lookup_count
= table_read_be_word(&table
->table
, table
->lookup_list
);
4466 if (!total_lookup_count
)
4469 feature_list
= table_read_ensure(&table
->table
, table
->feature_list
,
4470 FIELD_OFFSET(struct ot_feature_list
, features
[total_feature_count
]));
4474 /* Required feature. */
4475 required_feature
.index
= langsys
? GET_BE_WORD(langsys
->required_feature_index
) : 0xffff;
4476 if (required_feature
.index
< total_feature_count
)
4477 required_feature
.tag
= feature_list
->features
[required_feature
.index
].tag
;
4478 required_feature
.mask
= global_bit_mask
;
4480 context
->global_mask
= global_bit_mask
;
4481 next_bit
= global_bit_shift
+ 1;
4482 for (i
= 0; i
< features
->count
; ++i
)
4484 unsigned int bits_needed
;
4487 feature
= &features
->features
[i
];
4489 feature
->index
= 0xffff;
4491 if ((feature
->flags
& FEATURE_GLOBAL
) && feature
->max_value
== 1)
4494 BitScanReverse(&bits_needed
, min(feature
->max_value
, 256));
4496 if (!feature
->max_value
|| next_bit
+ bits_needed
> 8 * sizeof (feature
->mask
))
4499 if (required_feature
.tag
== feature
->tag
)
4500 required_feature
.stage
= feature
->stage
;
4502 for (j
= 0; j
< script_feature_count
; ++j
)
4504 feature_index
= GET_BE_WORD(langsys
->feature_index
[j
]);
4505 if (feature_index
>= total_feature_count
)
4507 if ((found
= feature_list
->features
[feature_index
].tag
== feature
->tag
))
4509 feature
->index
= feature_index
;
4514 if (!found
&& (features
->features
[i
].flags
& FEATURE_GLOBAL_SEARCH
))
4516 for (j
= 0; j
< total_feature_count
; ++j
)
4518 if ((found
= (feature_list
->features
[j
].tag
== feature
->tag
)))
4529 if (feature
->flags
& FEATURE_GLOBAL
&& feature
->max_value
== 1)
4531 feature
->shift
= global_bit_shift
;
4532 feature
->mask
= global_bit_mask
;
4536 feature
->shift
= next_bit
;
4537 feature
->mask
= (1 << (next_bit
+ bits_needed
)) - (1 << next_bit
);
4538 next_bit
+= bits_needed
;
4539 context
->global_mask
|= (feature
->default_value
<< feature
->shift
) & feature
->mask
;
4543 for (stage
= 0; stage
<= features
->stage
; ++stage
)
4545 if (required_feature
.index
!= 0xffff && required_feature
.stage
== stage
)
4546 opentype_layout_add_lookups(feature_list
, total_lookup_count
, table
, &required_feature
, lookups
);
4548 for (i
= 0; i
< features
->count
; ++i
)
4550 if (features
->features
[i
].stage
== stage
)
4551 opentype_layout_add_lookups(feature_list
, total_lookup_count
, table
, &features
->features
[i
], lookups
);
4554 /* Sort and merge lookups for current stage. */
4555 if (last_num_lookups
< lookups
->count
)
4557 qsort(lookups
->lookups
+ last_num_lookups
, lookups
->count
- last_num_lookups
, sizeof(*lookups
->lookups
),
4558 lookups_sorting_compare
);
4560 j
= last_num_lookups
;
4561 for (i
= j
+ 1; i
< lookups
->count
; ++i
)
4563 if (lookups
->lookups
[i
].index
!= lookups
->lookups
[j
].index
)
4565 lookups
->lookups
[++j
] = lookups
->lookups
[i
];
4569 lookups
->lookups
[j
].mask
|= lookups
->lookups
[i
].mask
;
4572 lookups
->count
= j
+ 1;
4575 last_num_lookups
= lookups
->count
;
4579 static int feature_search_compare(const void *a
, const void* b
)
4581 unsigned int tag
= *(unsigned int *)a
;
4582 const struct shaping_feature
*feature
= b
;
4584 return tag
< feature
->tag
? -1 : tag
> feature
->tag
? 1 : 0;
4587 static unsigned int shaping_features_get_mask(const struct shaping_features
*features
, unsigned int tag
, unsigned int *shift
)
4589 struct shaping_feature
*feature
;
4591 feature
= bsearch(&tag
, features
->features
, features
->count
, sizeof(*features
->features
), feature_search_compare
);
4593 if (!feature
|| feature
->index
== 0xffff)
4596 if (shift
) *shift
= feature
->shift
;
4597 return feature
->mask
;
4600 static void opentype_layout_get_glyph_range_for_text(struct scriptshaping_context
*context
, unsigned int start_char
,
4601 unsigned int end_char
, unsigned int *start_glyph
, unsigned int *end_glyph
)
4603 *start_glyph
= context
->u
.buffer
.clustermap
[start_char
];
4604 if (end_char
>= context
->length
- 1)
4605 *end_glyph
= context
->glyph_count
- 1;
4607 *end_glyph
= context
->u
.buffer
.clustermap
[end_char
+ 1] - 1;
4610 static void opentype_layout_set_glyph_masks(struct scriptshaping_context
*context
, const struct shaping_features
*features
)
4612 const DWRITE_TYPOGRAPHIC_FEATURES
**user_features
= context
->user_features
.features
;
4613 unsigned int f
, r
, g
, start_char
, mask
, shift
, value
;
4615 for (g
= 0; g
< context
->glyph_count
; ++g
)
4616 context
->glyph_infos
[g
].mask
= context
->global_mask
;
4618 /* FIXME: set shaper masks */
4620 for (r
= 0, start_char
= 0; r
< context
->user_features
.range_count
; ++r
)
4622 unsigned int start_glyph
, end_glyph
;
4624 if (start_char
>= context
->length
)
4627 opentype_layout_get_glyph_range_for_text(context
, start_char
, start_char
+ context
->user_features
.range_lengths
[r
],
4628 &start_glyph
, &end_glyph
);
4629 start_char
+= context
->user_features
.range_lengths
[r
];
4631 if (start_glyph
> end_glyph
|| end_glyph
>= context
->glyph_count
)
4634 for (f
= 0; f
< user_features
[r
]->featureCount
; ++f
)
4636 mask
= shaping_features_get_mask(features
, user_features
[r
]->features
[f
].nameTag
, &shift
);
4640 value
= (user_features
[r
]->features
[f
].parameter
<< shift
) & mask
;
4642 for (g
= start_glyph
; g
<= end_glyph
; ++g
)
4643 context
->glyph_infos
[g
].mask
= (context
->glyph_infos
[g
].mask
& ~mask
) | value
;
4648 static void opentype_layout_apply_gpos_context_lookup(struct scriptshaping_context
*context
, unsigned int lookup_index
)
4650 struct lookup lookup
= { 0 };
4651 /* Feature mask is intentionally zero, it's not used outside of main loop. */
4652 if (opentype_layout_init_lookup(context
->table
, lookup_index
, 0, &lookup
))
4653 opentype_layout_apply_gpos_lookup(context
, &lookup
);
4656 void opentype_layout_apply_gpos_features(struct scriptshaping_context
*context
, unsigned int script_index
,
4657 unsigned int language_index
, const struct shaping_features
*features
)
4659 struct lookups lookups
= { 0 };
4663 context
->nesting_level_left
= SHAPE_MAX_NESTING_LEVEL
;
4664 context
->u
.buffer
.apply_context_lookup
= opentype_layout_apply_gpos_context_lookup
;
4665 opentype_layout_collect_lookups(context
, script_index
, language_index
, features
, &context
->cache
->gpos
, &lookups
);
4667 for (i
= 0; i
< context
->glyph_count
; ++i
)
4668 opentype_set_glyph_props(context
, i
);
4669 opentype_layout_set_glyph_masks(context
, features
);
4671 for (i
= 0; i
< lookups
.count
; ++i
)
4673 const struct lookup
*lookup
= &lookups
.lookups
[i
];
4676 context
->lookup_mask
= lookup
->mask
;
4678 while (context
->cur
< context
->glyph_count
)
4682 if ((context
->glyph_infos
[context
->cur
].mask
& lookup
->mask
) &&
4683 lookup_is_glyph_match(context
, context
->cur
, lookup
->flags
))
4685 ret
= opentype_layout_apply_gpos_lookup(context
, lookup
);
4693 heap_free(lookups
.lookups
);
4696 static void opentype_layout_replace_glyph(struct scriptshaping_context
*context
, UINT16 glyph
)
4698 UINT16 orig_glyph
= context
->u
.subst
.glyphs
[context
->cur
];
4699 if (glyph
!= orig_glyph
)
4701 context
->u
.subst
.glyphs
[context
->cur
] = glyph
;
4702 opentype_set_subst_glyph_props(context
, context
->cur
);
4706 static BOOL
opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4707 unsigned int subtable_offset
)
4709 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4710 UINT16 format
, coverage
, orig_glyph
, glyph
;
4711 unsigned int coverage_index
;
4713 orig_glyph
= glyph
= context
->u
.subst
.glyphs
[context
->cur
];
4715 format
= table_read_be_word(table
, subtable_offset
);
4717 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format1
, coverage
));
4721 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
4722 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
4724 glyph
= orig_glyph
+ table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format1
, delta
));
4726 else if (format
== 2)
4728 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
4729 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
4731 if (!table_read_array_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format2
, count
),
4732 coverage_index
, &glyph
))
4739 WARN("Unknown single substitution format %u.\n", format
);
4743 opentype_layout_replace_glyph(context
, glyph
);
4749 static BOOL
opentype_layout_gsub_ensure_buffer(struct scriptshaping_context
*context
, unsigned int count
)
4751 DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
;
4752 struct shaping_glyph_info
*glyph_infos
;
4753 unsigned int new_capacity
;
4757 if (context
->u
.subst
.capacity
>= count
)
4760 new_capacity
= context
->u
.subst
.capacity
* 2;
4762 if ((glyphs
= heap_realloc(context
->u
.subst
.glyphs
, new_capacity
* sizeof(*glyphs
))))
4763 context
->u
.subst
.glyphs
= glyphs
;
4764 if ((glyph_props
= heap_realloc(context
->u
.subst
.glyph_props
, new_capacity
* sizeof(*glyph_props
))))
4765 context
->u
.subst
.glyph_props
= glyph_props
;
4766 if ((glyph_infos
= heap_realloc(context
->glyph_infos
, new_capacity
* sizeof(*glyph_infos
))))
4767 context
->glyph_infos
= glyph_infos
;
4769 if ((ret
= (glyphs
&& glyph_props
&& glyph_infos
)))
4770 context
->u
.subst
.capacity
= new_capacity
;
4775 static BOOL
opentype_layout_apply_gsub_mult_substitution(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4776 unsigned int subtable_offset
)
4778 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4779 UINT16 format
, coverage
, glyph
, glyph_count
;
4780 unsigned int i
, idx
, coverage_index
;
4781 const UINT16
*glyphs
;
4784 glyph
= context
->u
.subst
.glyphs
[idx
];
4786 format
= table_read_be_word(table
, subtable_offset
);
4788 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_multsubst_format1
, coverage
));
4794 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
4795 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
4797 if (!table_read_array_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_multsubst_format1
, seq_count
),
4798 coverage_index
, &seq_offset
))
4803 if (!(glyphs
= table_read_array_be_word(table
, subtable_offset
+ seq_offset
, ~0u, &glyph_count
))) return FALSE
;
4805 if (glyph_count
== 1)
4807 /* Equivalent of single substitution. */
4808 opentype_layout_replace_glyph(context
, GET_BE_WORD(glyphs
[0]));
4811 else if (glyph_count
== 0)
4817 unsigned int shift_len
, src_idx
, dest_idx
, mask
;
4819 /* Current glyph is also replaced. */
4822 if (!(opentype_layout_gsub_ensure_buffer(context
, context
->glyph_count
+ glyph_count
)))
4825 shift_len
= context
->cur
+ 1 < context
->glyph_count
? context
->glyph_count
- context
->cur
- 1 : 0;
4829 src_idx
= context
->cur
+ 1;
4830 dest_idx
= src_idx
+ glyph_count
;
4832 memmove(&context
->u
.subst
.glyphs
[dest_idx
], &context
->u
.subst
.glyphs
[src_idx
],
4833 shift_len
* sizeof(*context
->u
.subst
.glyphs
));
4834 memmove(&context
->u
.subst
.glyph_props
[dest_idx
], &context
->u
.subst
.glyph_props
[src_idx
],
4835 shift_len
* sizeof(*context
->u
.subst
.glyph_props
));
4836 memmove(&context
->glyph_infos
[dest_idx
], &context
->glyph_infos
[src_idx
],
4837 shift_len
* sizeof(*context
->glyph_infos
));
4840 mask
= context
->glyph_infos
[context
->cur
].mask
;
4841 for (i
= 0, idx
= context
->cur
; i
<= glyph_count
; ++i
)
4843 glyph
= GET_BE_WORD(glyphs
[i
]);
4844 context
->u
.subst
.glyphs
[idx
+ i
] = glyph
;
4847 context
->u
.subst
.glyph_props
[idx
+ i
].isClusterStart
= 0;
4848 context
->u
.buffer
.glyph_props
[idx
+ i
].components
= 0;
4849 context
->glyph_infos
[idx
+ i
].start_text_idx
= 0;
4851 opentype_set_subst_glyph_props(context
, idx
+ i
);
4852 /* Inherit feature mask from original matched glyph. */
4853 context
->glyph_infos
[idx
+ i
].mask
= mask
;
4856 context
->cur
+= glyph_count
+ 1;
4857 context
->glyph_count
+= glyph_count
;
4862 WARN("Unknown multiple substitution format %u.\n", format
);
4869 static BOOL
opentype_layout_apply_gsub_alt_substitution(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4870 unsigned int subtable_offset
)
4872 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4873 unsigned int idx
, coverage_index
;
4874 UINT16 format
, coverage
, glyph
;
4877 glyph
= context
->u
.subst
.glyphs
[idx
];
4879 format
= table_read_be_word(table
, subtable_offset
);
4883 const struct ot_gsub_altsubst_format1
*format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
));
4884 unsigned int shift
, alt_index
;
4887 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_altsubst_format1
, coverage
));
4889 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
4890 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
4892 if (!table_read_array_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_altsubst_format1
, count
),
4893 coverage_index
, &set_offset
))
4896 /* Argument is 1-based. */
4897 BitScanForward(&shift
, context
->lookup_mask
);
4898 alt_index
= (context
->lookup_mask
& context
->glyph_infos
[idx
].mask
) >> shift
;
4899 if (!alt_index
) return FALSE
;
4901 if (!table_read_array_be_word(table
, subtable_offset
+ set_offset
, alt_index
- 1, &glyph
)) return FALSE
;
4905 WARN("Unexpected alternate substitution format %d.\n", format
);
4909 opentype_layout_replace_glyph(context
, glyph
);
4915 static BOOL
opentype_layout_context_match_input(const struct match_context
*mc
, unsigned int count
, const UINT16
*input
,
4916 unsigned int *end_offset
, unsigned int *match_positions
)
4918 struct match_data match_data
= { .mc
= mc
, .subtable_offset
= mc
->input_offset
};
4919 struct scriptshaping_context
*context
= mc
->context
;
4920 struct glyph_iterator iter
;
4923 if (count
> GLYPH_CONTEXT_MAX_LENGTH
)
4926 match_positions
[0] = context
->cur
;
4928 glyph_iterator_init(context
, mc
->lookup
->flags
, context
->cur
, count
- 1, &iter
);
4929 iter
.mask
= context
->lookup_mask
;
4930 iter
.match_func
= mc
->match_func
;
4931 iter
.match_data
= &match_data
;
4932 iter
.glyph_data
= input
;
4934 for (i
= 1; i
< count
; ++i
)
4936 if (!glyph_iterator_next(&iter
))
4939 match_positions
[i
] = iter
.pos
;
4942 *end_offset
= iter
.pos
- context
->cur
+ 1;
4947 static void opentype_layout_unsafe_to_break(struct scriptshaping_context
*context
, unsigned int idx
)
4949 if (context
->u
.buffer
.glyph_props
[idx
].isClusterStart
)
4950 context
->u
.buffer
.text_props
[context
->glyph_infos
[idx
].start_text_idx
].canBreakShapingAfter
= 0;
4953 static void opentype_layout_delete_glyph(struct scriptshaping_context
*context
, unsigned int idx
)
4955 unsigned int shift_len
;
4957 shift_len
= context
->glyph_count
- context
->cur
- 1;
4961 memmove(&context
->u
.buffer
.glyphs
[idx
], &context
->u
.buffer
.glyphs
[idx
+ 1],
4962 shift_len
* sizeof(*context
->u
.buffer
.glyphs
));
4963 memmove(&context
->u
.buffer
.glyph_props
[idx
], &context
->u
.buffer
.glyph_props
[idx
+ 1],
4964 shift_len
* sizeof(*context
->u
.buffer
.glyph_props
));
4965 memmove(&context
->glyph_infos
[idx
], &context
->glyph_infos
[idx
+ 1], shift_len
* sizeof(*context
->glyph_infos
));
4968 context
->glyph_count
--;
4971 static BOOL
opentype_layout_apply_ligature(struct scriptshaping_context
*context
, unsigned int offset
,
4972 const struct lookup
*lookup
)
4974 struct match_context mc
= { .context
= context
, .lookup
= lookup
, .match_func
= opentype_match_glyph_func
};
4975 const struct dwrite_fonttable
*gsub
= &context
->table
->table
;
4976 unsigned int match_positions
[GLYPH_CONTEXT_MAX_LENGTH
];
4977 unsigned int i
, j
, comp_count
, match_length
= 0;
4978 const struct ot_gsub_lig
*lig
;
4981 comp_count
= table_read_be_word(gsub
, offset
+ FIELD_OFFSET(struct ot_gsub_lig
, comp_count
));
4986 lig
= table_read_ensure(gsub
, offset
, FIELD_OFFSET(struct ot_gsub_lig
, components
[comp_count
-1]));
4990 lig_glyph
= GET_BE_WORD(lig
->lig_glyph
);
4992 if (comp_count
== 1)
4994 opentype_layout_replace_glyph(context
, lig_glyph
);
4999 if (!opentype_layout_context_match_input(&mc
, comp_count
, lig
->components
, &match_length
, match_positions
))
5002 opentype_layout_replace_glyph(context
, lig_glyph
);
5003 context
->u
.buffer
.glyph_props
[context
->cur
].components
= comp_count
;
5005 /* Positioning against a ligature implies keeping track of ligature component
5006 glyph should be attached to. Update per-glyph property for interleaving glyphs,
5007 0 means attaching to last component, n - attaching to n-th glyph before last. */
5008 for (i
= 1; i
< comp_count
; ++i
)
5010 j
= match_positions
[i
- 1] + 1;
5011 while (j
< match_positions
[i
])
5013 context
->u
.buffer
.glyph_props
[j
++].lig_component
= comp_count
- i
;
5015 opentype_layout_unsafe_to_break(context
, i
);
5016 context
->u
.buffer
.glyph_props
[i
].isClusterStart
= 0;
5017 context
->glyph_infos
[i
].start_text_idx
= 0;
5020 /* Delete ligated glyphs, backwards to preserve index. */
5021 for (i
= 1; i
< comp_count
; ++i
)
5023 opentype_layout_delete_glyph(context
, match_positions
[comp_count
- i
]);
5026 /* Skip whole matched sequence, accounting for deleted glyphs. */
5027 context
->cur
+= match_length
- (comp_count
- 1);
5032 static BOOL
opentype_layout_apply_gsub_lig_substitution(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
5033 unsigned int subtable_offset
)
5035 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5036 UINT16 format
, coverage
, glyph
, lig_set_offset
;
5037 unsigned int coverage_index
;
5039 glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5041 format
= table_read_be_word(table
, subtable_offset
);
5045 const struct ot_gsub_ligsubst_format1
*format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
));
5047 const UINT16
*offsets
;
5050 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_ligsubst_format1
, coverage
));
5052 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5053 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
5055 if (!table_read_array_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_ligsubst_format1
, lig_set_count
),
5056 coverage_index
, &lig_set_offset
))
5059 if (!(offsets
= table_read_array_be_word(table
, subtable_offset
+ lig_set_offset
, ~0u, &lig_count
)))
5062 /* First applicable ligature is used. */
5063 for (i
= 0; i
< lig_count
; ++i
)
5065 if (opentype_layout_apply_ligature(context
, subtable_offset
+ lig_set_offset
+ GET_BE_WORD(offsets
[i
]), lookup
))
5070 WARN("Unexpected ligature substitution format %d.\n", format
);
5075 static BOOL
opentype_layout_context_match_backtrack(const struct match_context
*mc
, unsigned int count
,
5076 const UINT16
*backtrack
, unsigned int *match_start
)
5078 struct match_data match_data
= { .mc
= mc
, .subtable_offset
= mc
->backtrack_offset
};
5079 struct scriptshaping_context
*context
= mc
->context
;
5080 struct glyph_iterator iter
;
5083 glyph_iterator_init(context
, mc
->lookup
->flags
, context
->cur
, count
, &iter
);
5084 iter
.match_func
= mc
->match_func
;
5085 iter
.match_data
= &match_data
;
5086 iter
.glyph_data
= backtrack
;
5088 for (i
= 0; i
< count
; ++i
)
5090 if (!glyph_iterator_prev(&iter
))
5094 *match_start
= iter
.pos
;
5099 static BOOL
opentype_layout_context_match_lookahead(const struct match_context
*mc
, unsigned int count
,
5100 const UINT16
*lookahead
, unsigned int offset
, unsigned int *end_index
)
5102 struct match_data match_data
= { .mc
= mc
, .subtable_offset
= mc
->lookahead_offset
};
5103 struct scriptshaping_context
*context
= mc
->context
;
5104 struct glyph_iterator iter
;
5107 glyph_iterator_init(context
, mc
->lookup
->flags
, context
->cur
+ offset
- 1, count
, &iter
);
5108 iter
.match_func
= mc
->match_func
;
5109 iter
.match_data
= &match_data
;
5110 iter
.glyph_data
= lookahead
;
5112 for (i
= 0; i
< count
; ++i
)
5114 if (!glyph_iterator_next(&iter
))
5118 *end_index
= iter
.pos
;
5123 static BOOL
opentype_layout_context_apply_lookup(struct scriptshaping_context
*context
, unsigned int count
,
5124 unsigned int *match_positions
, unsigned int lookup_count
, const UINT16
*lookup_records
, unsigned int match_length
)
5129 if (!context
->nesting_level_left
)
5132 end
= context
->cur
+ match_length
;
5134 for (i
= 0; i
< lookup_count
; ++i
)
5136 unsigned int idx
= GET_BE_WORD(lookup_records
[i
]);
5137 unsigned int orig_len
, lookup_index
, next
;
5142 context
->cur
= match_positions
[idx
];
5144 orig_len
= context
->glyph_count
;
5146 lookup_index
= GET_BE_WORD(lookup_records
[i
+1]);
5148 --context
->nesting_level_left
;
5149 context
->u
.buffer
.apply_context_lookup(context
, lookup_index
);
5150 ++context
->nesting_level_left
;
5152 delta
= context
->glyph_count
- orig_len
;
5157 if (end
<= (int)match_positions
[idx
])
5159 end
= match_positions
[idx
];
5167 if (delta
+ count
> GLYPH_CONTEXT_MAX_LENGTH
)
5172 delta
= max(delta
, (int)next
- (int)count
);
5176 memmove(match_positions
+ next
+ delta
, match_positions
+ next
,
5177 (count
- next
) * sizeof (*match_positions
));
5181 for (j
= idx
+ 1; j
< next
; j
++)
5182 match_positions
[j
] = match_positions
[j
- 1] + 1;
5184 for (; next
< count
; next
++)
5185 match_positions
[next
] += delta
;
5193 static BOOL
opentype_layout_apply_chain_context_match(unsigned int backtrack_count
, const UINT16
*backtrack
,
5194 unsigned int input_count
, const UINT16
*input
, unsigned int lookahead_count
, const UINT16
*lookahead
,
5195 unsigned int lookup_count
, const UINT16
*lookup_records
, const struct match_context
*mc
)
5197 unsigned int start_index
= 0, match_length
= 0, end_index
= 0;
5198 unsigned int match_positions
[GLYPH_CONTEXT_MAX_LENGTH
];
5200 return opentype_layout_context_match_input(mc
, input_count
, input
, &match_length
, match_positions
) &&
5201 opentype_layout_context_match_backtrack(mc
, backtrack_count
, backtrack
, &start_index
) &&
5202 opentype_layout_context_match_lookahead(mc
, lookahead_count
, lookahead
, input_count
, &end_index
) &&
5203 opentype_layout_context_apply_lookup(mc
->context
, input_count
, match_positions
, lookup_count
, lookup_records
, match_length
);
5206 static BOOL
opentype_layout_apply_chain_rule_set(const struct match_context
*mc
, unsigned int offset
)
5208 unsigned int backtrack_count
, input_count
, lookahead_count
, lookup_count
;
5209 const struct dwrite_fonttable
*table
= &mc
->context
->table
->table
;
5210 const UINT16
*backtrack
, *lookahead
, *input
, *lookup_records
;
5211 const struct ot_gsubgpos_ruleset
*ruleset
;
5212 unsigned int i
, count
;
5214 count
= table_read_be_word(table
, offset
);
5215 ruleset
= table_read_ensure(table
, offset
, count
* sizeof(ruleset
->offsets
));
5217 for (i
= 0; i
< count
; ++i
)
5219 unsigned int rule_offset
= offset
+ GET_BE_WORD(ruleset
->offsets
[i
]);
5221 backtrack_count
= table_read_be_word(table
, rule_offset
);
5223 backtrack
= table_read_ensure(table
, rule_offset
, backtrack_count
* sizeof(*backtrack
));
5224 rule_offset
+= backtrack_count
* sizeof(*backtrack
);
5226 if (!(input_count
= table_read_be_word(table
, rule_offset
)))
5230 input
= table_read_ensure(table
, rule_offset
, (input_count
- 1) * sizeof(*input
));
5231 rule_offset
+= (input_count
- 1) * sizeof(*input
);
5233 lookahead_count
= table_read_be_word(table
, rule_offset
);
5235 lookahead
= table_read_ensure(table
, rule_offset
, lookahead_count
* sizeof(*lookahead
));
5236 rule_offset
+= lookahead_count
* sizeof(*lookahead
);
5238 lookup_count
= table_read_be_word(table
, rule_offset
);
5240 lookup_records
= table_read_ensure(table
, rule_offset
, lookup_count
* 2 * sizeof(*lookup_records
));
5242 /* First applicable rule is used. */
5243 if (opentype_layout_apply_chain_context_match(backtrack_count
, backtrack
, input_count
, input
, lookahead_count
,
5244 lookahead
, lookup_count
, lookup_records
, mc
))
5253 static BOOL
opentype_layout_apply_context_match(unsigned int input_count
, const UINT16
*input
, unsigned int lookup_count
,
5254 const UINT16
*lookup_records
, const struct match_context
*mc
)
5256 unsigned int match_positions
[GLYPH_CONTEXT_MAX_LENGTH
];
5257 unsigned int match_length
= 0;
5259 return opentype_layout_context_match_input(mc
, input_count
, input
, &match_length
, match_positions
) &&
5260 opentype_layout_context_apply_lookup(mc
->context
, input_count
, match_positions
, lookup_count
,
5261 lookup_records
, match_length
);
5264 static BOOL
opentype_layout_apply_rule_set(const struct match_context
*mc
, unsigned int offset
)
5266 unsigned int input_count
, lookup_count
;
5267 const struct dwrite_fonttable
*table
= &mc
->context
->table
->table
;
5268 const UINT16
*input
, *lookup_records
;
5269 const struct ot_gsubgpos_ruleset
*ruleset
;
5270 unsigned int i
, count
;
5272 count
= table_read_be_word(table
, offset
);
5273 ruleset
= table_read_ensure(table
, offset
, count
* sizeof(ruleset
->offsets
));
5275 for (i
= 0; i
< count
; ++i
)
5277 unsigned int rule_offset
= offset
+ GET_BE_WORD(ruleset
->offsets
[i
]);
5279 if (!(input_count
= table_read_be_word(table
, rule_offset
)))
5283 if (!(lookup_count
= table_read_be_word(table
, rule_offset
)))
5287 if (!(input
= table_read_ensure(table
, rule_offset
, (input_count
- 1) * sizeof(*input
))))
5289 rule_offset
+= (input_count
- 1) * sizeof(*input
);
5291 if (!(lookup_records
= table_read_ensure(table
, rule_offset
, lookup_count
* 2 * sizeof(*lookup_records
))))
5294 /* First applicable rule is used. */
5295 if (opentype_layout_apply_context_match(input_count
, input
, lookup_count
, lookup_records
, mc
))
5302 static BOOL
opentype_layout_apply_context(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
5303 unsigned int subtable_offset
)
5305 struct match_context mc
= { .context
= context
, .lookup
= lookup
};
5306 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5307 unsigned int coverage_index
= GLYPH_NOT_COVERED
, count
, offset
;
5308 UINT16 glyph
, format
, coverage
;
5311 glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5313 format
= table_read_be_word(table
, subtable_offset
);
5317 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
, coverage
));
5319 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5320 if (coverage_index
== GLYPH_NOT_COVERED
)
5323 count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
, ruleset_count
));
5324 if (coverage_index
>= count
)
5327 offset
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
,
5328 rulesets
[coverage_index
]));
5329 offset
+= subtable_offset
;
5331 mc
.match_func
= opentype_match_glyph_func
;
5333 ret
= opentype_layout_apply_rule_set(&mc
, offset
);
5335 else if (format
== 2)
5337 unsigned int input_classdef
, rule_set_idx
;
5339 offset
= subtable_offset
+ 2 /* format */;
5341 coverage
= table_read_be_word(table
, offset
);
5344 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5345 if (coverage_index
== GLYPH_NOT_COVERED
)
5348 input_classdef
= table_read_be_word(table
, offset
) + subtable_offset
;
5351 count
= table_read_be_word(table
, offset
);
5354 rule_set_idx
= opentype_layout_get_glyph_class(table
, input_classdef
, glyph
);
5355 if (rule_set_idx
>= count
)
5358 offset
= table_read_be_word(table
, offset
+ rule_set_idx
* 2);
5359 offset
+= subtable_offset
;
5361 mc
.input_offset
= input_classdef
;
5362 mc
.match_func
= opentype_match_class_func
;
5364 ret
= opentype_layout_apply_rule_set(&mc
, offset
);
5366 else if (format
== 3)
5368 unsigned int input_count
, lookup_count
;
5369 const UINT16
*input
, *lookup_records
;
5371 offset
= subtable_offset
+ 2 /* format */;
5373 input_count
= table_read_be_word(table
, offset
);
5379 lookup_count
= table_read_be_word(table
, offset
);
5382 if (!(input
= table_read_ensure(table
, offset
, sizeof(*input
) * input_count
)))
5384 offset
+= sizeof(*input
) * input_count
;
5386 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(input
[0]), glyph
);
5387 if (coverage_index
== GLYPH_NOT_COVERED
)
5390 lookup_records
= table_read_ensure(table
, offset
, lookup_count
* 2 * sizeof(*lookup_records
));
5392 mc
.input_offset
= subtable_offset
;
5393 mc
.match_func
= opentype_match_coverage_func
;
5395 ret
= opentype_layout_apply_context_match(input_count
, input
+ 1, lookup_count
, lookup_records
, &mc
);
5398 WARN("Unknown contextual substitution format %u.\n", format
);
5403 static BOOL
opentype_layout_apply_chain_context(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
5404 unsigned int subtable_offset
)
5406 struct match_context mc
= { .context
= context
, .lookup
= lookup
};
5407 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5408 unsigned int coverage_index
= GLYPH_NOT_COVERED
, count
, offset
;
5409 UINT16 glyph
, format
, coverage
;
5412 glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5414 format
= table_read_be_word(table
, subtable_offset
);
5418 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
, coverage
));
5420 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5421 if (coverage_index
== GLYPH_NOT_COVERED
)
5424 count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
, ruleset_count
));
5425 if (coverage_index
>= count
)
5428 offset
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
,
5429 rulesets
[coverage_index
]));
5430 offset
+= subtable_offset
;
5432 mc
.match_func
= opentype_match_glyph_func
;
5434 ret
= opentype_layout_apply_chain_rule_set(&mc
, offset
);
5436 else if (format
== 2)
5438 unsigned int backtrack_classdef
, input_classdef
, lookahead_classdef
, rule_set_idx
;
5440 offset
= subtable_offset
+ 2 /* format */;
5442 coverage
= table_read_be_word(table
, offset
);
5445 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5446 if (coverage_index
== GLYPH_NOT_COVERED
)
5449 backtrack_classdef
= table_read_be_word(table
, offset
) + subtable_offset
;
5452 input_classdef
= table_read_be_word(table
, offset
) + subtable_offset
;
5455 lookahead_classdef
= table_read_be_word(table
, offset
) + subtable_offset
;
5458 count
= table_read_be_word(table
, offset
);
5461 rule_set_idx
= opentype_layout_get_glyph_class(table
, input_classdef
, glyph
);
5462 if (rule_set_idx
>= count
)
5465 offset
= table_read_be_word(table
, offset
+ rule_set_idx
* 2);
5466 offset
+= subtable_offset
;
5468 mc
.backtrack_offset
= backtrack_classdef
;
5469 mc
.input_offset
= input_classdef
;
5470 mc
.lookahead_offset
= lookahead_classdef
;
5471 mc
.match_func
= opentype_match_class_func
;
5473 ret
= opentype_layout_apply_chain_rule_set(&mc
, offset
);
5475 else if (format
== 3)
5477 unsigned int backtrack_count
, input_count
, lookahead_count
, lookup_count
;
5478 const UINT16
*backtrack
, *lookahead
, *input
, *lookup_records
;
5480 offset
= subtable_offset
+ 2 /* format */;
5482 backtrack_count
= table_read_be_word(table
, offset
);
5484 backtrack
= table_read_ensure(table
, offset
, backtrack_count
* sizeof(*backtrack
));
5485 offset
+= backtrack_count
* sizeof(*backtrack
);
5487 input_count
= table_read_be_word(table
, offset
);
5489 input
= table_read_ensure(table
, offset
, input_count
* sizeof(*input
));
5490 offset
+= input_count
* sizeof(*input
);
5492 lookahead_count
= table_read_be_word(table
, offset
);
5494 lookahead
= table_read_ensure(table
, offset
, lookahead_count
* sizeof(*lookahead
));
5495 offset
+= lookahead_count
* sizeof(*lookahead
);
5497 lookup_count
= table_read_be_word(table
, offset
);
5499 lookup_records
= table_read_ensure(table
, offset
, lookup_count
* 2 * sizeof(*lookup_records
));
5502 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(input
[0]), glyph
);
5504 if (coverage_index
== GLYPH_NOT_COVERED
)
5507 mc
.backtrack_offset
= subtable_offset
;
5508 mc
.input_offset
= subtable_offset
;
5509 mc
.lookahead_offset
= subtable_offset
;
5510 mc
.match_func
= opentype_match_coverage_func
;
5512 ret
= opentype_layout_apply_chain_context_match(backtrack_count
, backtrack
, input_count
, input
+ 1, lookahead_count
,
5513 lookahead
, lookup_count
, lookup_records
, &mc
);
5516 WARN("Unknown chaining contextual substitution format %u.\n", format
);
5521 static BOOL
opentype_layout_apply_gsub_reverse_chain_context_substitution(struct scriptshaping_context
*context
,
5522 const struct lookup
*lookup
, unsigned int subtable_offset
)
5524 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5525 unsigned int offset
= subtable_offset
;
5526 UINT16 glyph
, format
;
5528 if (context
->nesting_level_left
!= SHAPE_MAX_NESTING_LEVEL
)
5531 glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5533 format
= table_read_be_word(table
, offset
);
5538 struct match_context mc
= { .context
= context
, .lookup
= lookup
};
5539 unsigned int start_index
= 0, end_index
= 0, backtrack_count
, lookahead_count
;
5540 unsigned int coverage
, coverage_index
;
5541 const UINT16
*backtrack
, *lookahead
;
5543 coverage
= table_read_be_word(table
, offset
);
5546 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5547 if (coverage_index
== GLYPH_NOT_COVERED
)
5550 backtrack_count
= table_read_be_word(table
, offset
);
5553 backtrack
= table_read_ensure(table
, offset
, sizeof(*backtrack
) * backtrack_count
);
5554 offset
+= sizeof(*backtrack
) * backtrack_count
;
5556 lookahead_count
= table_read_be_word(table
, offset
);
5559 lookahead
= table_read_ensure(table
, offset
, sizeof(*lookahead
) * lookahead_count
);
5560 offset
+= sizeof(*lookahead
) * lookahead_count
;
5562 mc
.match_func
= opentype_match_coverage_func
;
5563 mc
.backtrack_offset
= subtable_offset
;
5564 mc
.lookahead_offset
= subtable_offset
;
5566 if (opentype_layout_context_match_backtrack(&mc
, backtrack_count
, backtrack
, &start_index
) &&
5567 opentype_layout_context_match_lookahead(&mc
, lookahead_count
, lookahead
, 1, &end_index
))
5569 unsigned int glyph_count
= table_read_be_word(table
, offset
);
5570 if (coverage_index
>= glyph_count
)
5574 glyph
= table_read_be_word(table
, offset
+ coverage_index
* sizeof(glyph
));
5575 opentype_layout_replace_glyph(context
, glyph
);
5581 WARN("Unknown reverse chaining contextual substitution format %u.\n", format
);
5586 static BOOL
opentype_layout_apply_gsub_lookup(struct scriptshaping_context
*context
, const struct lookup
*lookup
)
5588 unsigned int i
, lookup_type
;
5591 for (i
= 0; i
< lookup
->subtable_count
; ++i
)
5593 unsigned int subtable_offset
= opentype_layout_get_gsubgpos_subtable(context
, lookup
, i
, &lookup_type
);
5595 switch (lookup_type
)
5597 case GSUB_LOOKUP_SINGLE_SUBST
:
5598 ret
= opentype_layout_apply_gsub_single_substitution(context
, lookup
, subtable_offset
);
5600 case GSUB_LOOKUP_MULTIPLE_SUBST
:
5601 ret
= opentype_layout_apply_gsub_mult_substitution(context
, lookup
, subtable_offset
);
5603 case GSUB_LOOKUP_ALTERNATE_SUBST
:
5604 ret
= opentype_layout_apply_gsub_alt_substitution(context
, lookup
, subtable_offset
);
5606 case GSUB_LOOKUP_LIGATURE_SUBST
:
5607 ret
= opentype_layout_apply_gsub_lig_substitution(context
, lookup
, subtable_offset
);
5609 case GSUB_LOOKUP_CONTEXTUAL_SUBST
:
5610 ret
= opentype_layout_apply_context(context
, lookup
, subtable_offset
);
5612 case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST
:
5613 ret
= opentype_layout_apply_chain_context(context
, lookup
, subtable_offset
);
5615 case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST
:
5616 ret
= opentype_layout_apply_gsub_reverse_chain_context_substitution(context
, lookup
, subtable_offset
);
5618 case GSUB_LOOKUP_EXTENSION_SUBST
:
5619 WARN("Invalid lookup type for extension substitution %#x.\n", lookup_type
);
5622 WARN("Unknown lookup type %u.\n", lookup_type
);
5632 static unsigned int unicode_get_mirrored_char(unsigned int codepoint
)
5634 extern const WCHAR wine_mirror_map
[] DECLSPEC_HIDDEN
;
5636 /* TODO: check if mirroring for higher planes makes sense at all */
5637 if (codepoint
> 0xffff) return codepoint
;
5638 mirror
= get_table_entry(wine_mirror_map
, codepoint
);
5639 return mirror
? mirror
: codepoint
;
5643 * 034F # Mn COMBINING GRAPHEME JOINER
5644 * 061C # Cf ARABIC LETTER MARK
5645 * 180B..180D # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
5646 * 180E # Cf MONGOLIAN VOWEL SEPARATOR
5647 * 200B..200F # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
5648 * FEFF # Cf ZERO WIDTH NO-BREAK SPACE
5650 static unsigned int opentype_is_default_ignorable(unsigned int codepoint
)
5652 return codepoint
== 0x34f || codepoint
== 0x61c || codepoint
== 0xfeff ||
5653 (codepoint
>= 0x180b && codepoint
<= 0x180e) || (codepoint
>= 0x200b && codepoint
<= 0x200f);
5656 static unsigned int opentype_is_diacritic(unsigned int codepoint
)
5658 WCHAR ch
= codepoint
;
5660 /* Ignore higher planes for now. */
5661 if (codepoint
> 0xffff) return 0;
5662 GetStringTypeW(CT_CTYPE3
, &ch
, 1, &type
);
5663 return !!(type
& C3_DIACRITIC
);
5666 static void opentype_get_nominal_glyphs(struct scriptshaping_context
*context
, const struct shaping_features
*features
)
5668 unsigned int rtlm_mask
= shaping_features_get_mask(features
, DWRITE_MAKE_OPENTYPE_TAG('r','t','l','m'), NULL
);
5669 const struct shaping_font_ops
*font
= context
->cache
->font
;
5670 unsigned int i
, g
, c
, codepoint
, cluster_start_idx
= 0;
5671 UINT16
*clustermap
= context
->u
.subst
.clustermap
;
5672 const WCHAR
*text
= context
->text
;
5675 memset(context
->u
.subst
.glyph_props
, 0, context
->u
.subst
.max_glyph_count
* sizeof(*context
->u
.subst
.glyph_props
));
5676 memset(context
->u
.buffer
.text_props
, 0, context
->length
* sizeof(*context
->u
.buffer
.text_props
));
5678 for (i
= 0; i
< context
->length
; ++i
)
5680 g
= context
->glyph_count
;
5682 if ((bmp
= !(IS_HIGH_SURROGATE(text
[i
]) && (i
< context
->length
- 1) && IS_LOW_SURROGATE(text
[i
+ 1]))))
5684 codepoint
= text
[i
];
5688 codepoint
= 0x10000 + ((text
[i
] - 0xd800) << 10) + (text
[i
+ 1] - 0xdc00);
5691 if (context
->is_rtl
)
5693 c
= unicode_get_mirrored_char(codepoint
);
5694 if (c
!= codepoint
&& font
->has_glyph(context
->cache
->context
, c
))
5697 context
->glyph_infos
[i
].mask
|= rtlm_mask
;
5700 /* TODO: should this check for glyph availability? */
5701 if (*context
->u
.subst
.digits
&& codepoint
>= '0' && codepoint
<= '9')
5702 codepoint
= context
->u
.subst
.digits
[codepoint
- '0'];
5704 context
->u
.buffer
.glyphs
[g
] = font
->get_glyph(context
->cache
->context
, codepoint
);
5705 context
->u
.buffer
.glyph_props
[g
].justification
= SCRIPT_JUSTIFY_CHARACTER
;
5706 opentype_set_subst_glyph_props(context
, g
);
5708 /* Group diacritics with preceding base. Glyph class is ignored here. */
5709 if (!g
|| !opentype_is_diacritic(codepoint
))
5711 context
->u
.buffer
.glyph_props
[g
].isClusterStart
= 1;
5712 context
->glyph_infos
[g
].start_text_idx
= i
;
5713 cluster_start_idx
= g
;
5716 if (opentype_is_default_ignorable(codepoint
))
5717 context
->u
.buffer
.glyph_props
[g
].isZeroWidthSpace
= 1;
5718 context
->u
.buffer
.glyph_props
[g
].components
= 1;
5719 context
->glyph_count
++;
5721 /* Set initial cluster map here, it's used for setting user features masks. */
5722 clustermap
[i
] = cluster_start_idx
;
5724 context
->u
.buffer
.text_props
[i
].canBreakShapingAfter
= 1;
5727 clustermap
[i
+ 1] = cluster_start_idx
;
5728 context
->u
.buffer
.text_props
[i
+ 1].canBreakShapingAfter
= 1;
5734 static BOOL
opentype_is_gsub_lookup_reversed(const struct scriptshaping_context
*context
, const struct lookup
*lookup
)
5736 unsigned int lookup_type
;
5738 opentype_layout_get_gsubgpos_subtable(context
, lookup
, 0, &lookup_type
);
5739 return lookup_type
== GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST
;
5742 static void opentype_layout_apply_gsub_context_lookup(struct scriptshaping_context
*context
, unsigned int lookup_index
)
5744 struct lookup lookup
= { 0 };
5745 /* Feature mask is intentionally zero, it's not used outside of main loop. */
5746 if (opentype_layout_init_lookup(context
->table
, lookup_index
, 0, &lookup
))
5747 opentype_layout_apply_gsub_lookup(context
, &lookup
);
5750 void opentype_layout_apply_gsub_features(struct scriptshaping_context
*context
, unsigned int script_index
,
5751 unsigned int language_index
, const struct shaping_features
*features
)
5753 struct lookups lookups
= { 0 };
5754 unsigned int i
, j
, start_idx
;
5757 context
->nesting_level_left
= SHAPE_MAX_NESTING_LEVEL
;
5758 context
->u
.buffer
.apply_context_lookup
= opentype_layout_apply_gsub_context_lookup
;
5759 opentype_layout_collect_lookups(context
, script_index
, language_index
, features
, context
->table
, &lookups
);
5761 opentype_get_nominal_glyphs(context
, features
);
5762 opentype_layout_set_glyph_masks(context
, features
);
5764 for (i
= 0; i
< lookups
.count
; ++i
)
5766 const struct lookup
*lookup
= &lookups
.lookups
[i
];
5768 context
->lookup_mask
= lookup
->mask
;
5770 if (!opentype_is_gsub_lookup_reversed(context
, lookup
))
5773 while (context
->cur
< context
->glyph_count
)
5777 if ((context
->glyph_infos
[context
->cur
].mask
& lookup
->mask
) &&
5778 lookup_is_glyph_match(context
, context
->cur
, lookup
->flags
))
5780 ret
= opentype_layout_apply_gsub_lookup(context
, lookup
);
5789 context
->cur
= context
->glyph_count
- 1;
5793 if ((context
->glyph_infos
[context
->cur
].mask
& lookup
->mask
) &&
5794 lookup_is_glyph_match(context
, context
->cur
, lookup
->flags
))
5796 opentype_layout_apply_gsub_lookup(context
, lookup
);
5799 if (context
->cur
== 0) break;
5805 /* For every glyph range of [<last>.isClusterStart, <next>.isClusterStart) set corresponding
5806 text span to start_idx. */
5808 for (i
= 1; i
< context
->glyph_count
; ++i
)
5810 if (context
->u
.buffer
.glyph_props
[i
].isClusterStart
)
5812 unsigned int start_text
, end_text
;
5814 start_text
= context
->glyph_infos
[start_idx
].start_text_idx
;
5815 end_text
= context
->glyph_infos
[i
].start_text_idx
;
5817 for (j
= start_text
; j
< end_text
; ++j
)
5818 context
->u
.buffer
.clustermap
[j
] = start_idx
;
5824 /* Fill the tail. */
5825 for (j
= context
->glyph_infos
[start_idx
].start_text_idx
; j
< context
->length
; ++j
)
5826 context
->u
.buffer
.clustermap
[j
] = start_idx
;
5828 heap_free(lookups
.lookups
);
5831 static BOOL
opentype_layout_contextual_lookup_is_glyph_covered(struct scriptshaping_context
*context
, UINT16 glyph
,
5832 unsigned int subtable_offset
, unsigned int coverage
, unsigned int format
)
5834 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5835 const UINT16
*offsets
;
5838 if (format
== 1 || format
== 2)
5840 if (opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
) != GLYPH_NOT_COVERED
)
5843 else if (format
== 3)
5845 count
= table_read_be_word(table
, subtable_offset
+ 2);
5846 if (!count
|| !(offsets
= table_read_ensure(table
, subtable_offset
+ 6, count
* sizeof(*offsets
))))
5849 if (opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(offsets
[0]), glyph
) != GLYPH_NOT_COVERED
)
5856 static BOOL
opentype_layout_chain_contextual_lookup_is_glyph_covered(struct scriptshaping_context
*context
, UINT16 glyph
,
5857 unsigned int subtable_offset
, unsigned int coverage
, unsigned int format
)
5859 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5860 unsigned int count
, backtrack_count
;
5861 const UINT16
*offsets
;
5863 if (format
== 1 || format
== 2)
5865 if (opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
) != GLYPH_NOT_COVERED
)
5868 else if (format
== 3)
5870 backtrack_count
= table_read_be_word(table
, subtable_offset
+ 2);
5872 count
= table_read_be_word(table
, subtable_offset
+ 4 + backtrack_count
* sizeof(*offsets
));
5874 if (!count
|| !(offsets
= table_read_ensure(table
, subtable_offset
+ 6 + backtrack_count
* sizeof(*offsets
),
5875 count
* sizeof(*offsets
))))
5878 if (opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(offsets
[0]), glyph
) != GLYPH_NOT_COVERED
)
5885 static BOOL
opentype_layout_gsub_lookup_is_glyph_covered(struct scriptshaping_context
*context
, UINT16 glyph
,
5886 const struct lookup
*lookup
)
5888 const struct dwrite_fonttable
*gsub
= &context
->table
->table
;
5889 static const unsigned short gsub_formats
[] =
5892 1, /* SingleSubst */
5893 1, /* MultipleSubst */
5894 1, /* AlternateSubst */
5895 1, /* LigatureSubst */
5896 3, /* ContextSubst */
5897 3, /* ChainContextSubst */
5898 0, /* Extension, unused */
5899 1, /* ReverseChainSubst */
5901 unsigned int i
, coverage
, lookup_type
, format
;
5903 for (i
= 0; i
< lookup
->subtable_count
; ++i
)
5905 unsigned int subtable_offset
= opentype_layout_get_gsubgpos_subtable(context
, lookup
, i
, &lookup_type
);
5907 format
= table_read_be_word(gsub
, subtable_offset
);
5909 if (!format
|| format
> ARRAY_SIZE(gsub_formats
) || format
> gsub_formats
[lookup_type
])
5912 coverage
= table_read_be_word(gsub
, subtable_offset
+ 2);
5914 switch (lookup_type
)
5916 case GSUB_LOOKUP_SINGLE_SUBST
:
5917 case GSUB_LOOKUP_MULTIPLE_SUBST
:
5918 case GSUB_LOOKUP_ALTERNATE_SUBST
:
5919 case GSUB_LOOKUP_LIGATURE_SUBST
:
5920 case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST
:
5922 if (opentype_layout_is_glyph_covered(gsub
, subtable_offset
+ coverage
, glyph
) != GLYPH_NOT_COVERED
)
5927 case GSUB_LOOKUP_CONTEXTUAL_SUBST
:
5929 if (opentype_layout_contextual_lookup_is_glyph_covered(context
, glyph
, subtable_offset
, coverage
, format
))
5934 case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST
:
5936 if (opentype_layout_chain_contextual_lookup_is_glyph_covered(context
, glyph
, subtable_offset
, coverage
, format
))
5942 WARN("Unknown lookup type %u.\n", lookup_type
);
5949 static BOOL
opentype_layout_gpos_lookup_is_glyph_covered(struct scriptshaping_context
*context
, UINT16 glyph
,
5950 const struct lookup
*lookup
)
5952 const struct dwrite_fonttable
*gpos
= &context
->table
->table
;
5953 static const unsigned short gpos_formats
[] =
5959 1, /* MarkBasePos */
5961 1, /* MarkMarkPos */
5963 3, /* ChainContextPos */
5964 0, /* Extension, unused */
5966 unsigned int i
, coverage
, lookup_type
, format
;
5968 for (i
= 0; i
< lookup
->subtable_count
; ++i
)
5970 unsigned int subtable_offset
= opentype_layout_get_gsubgpos_subtable(context
, lookup
, i
, &lookup_type
);
5972 format
= table_read_be_word(gpos
, subtable_offset
);
5974 if (!format
|| format
> ARRAY_SIZE(gpos_formats
) || format
> gpos_formats
[lookup_type
])
5977 coverage
= table_read_be_word(gpos
, subtable_offset
+ 2);
5979 switch (lookup_type
)
5981 case GPOS_LOOKUP_SINGLE_ADJUSTMENT
:
5982 case GPOS_LOOKUP_PAIR_ADJUSTMENT
:
5983 case GPOS_LOOKUP_CURSIVE_ATTACHMENT
:
5984 case GPOS_LOOKUP_MARK_TO_BASE_ATTACHMENT
:
5985 case GPOS_LOOKUP_MARK_TO_LIGATURE_ATTACHMENT
:
5986 case GPOS_LOOKUP_MARK_TO_MARK_ATTACHMENT
:
5988 if (opentype_layout_is_glyph_covered(gpos
, subtable_offset
+ coverage
, glyph
) != GLYPH_NOT_COVERED
)
5993 case GPOS_LOOKUP_CONTEXTUAL_POSITION
:
5995 if (opentype_layout_contextual_lookup_is_glyph_covered(context
, glyph
, subtable_offset
, coverage
, format
))
6000 case GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION
:
6002 if (opentype_layout_chain_contextual_lookup_is_glyph_covered(context
, glyph
, subtable_offset
, coverage
, format
))
6008 WARN("Unknown lookup type %u.\n", lookup_type
);
6015 typedef BOOL (*p_lookup_is_glyph_covered_func
)(struct scriptshaping_context
*context
, UINT16 glyph
, const struct lookup
*lookup
);
6017 BOOL
opentype_layout_check_feature(struct scriptshaping_context
*context
, unsigned int script_index
,
6018 unsigned int language_index
, struct shaping_feature
*feature
, unsigned int glyph_count
,
6019 const UINT16
*glyphs
, UINT8
*feature_applies
)
6021 p_lookup_is_glyph_covered_func func_is_covered
;
6022 struct shaping_features features
= { 0 };
6023 struct lookups lookups
= { 0 };
6024 BOOL ret
= FALSE
, is_covered
;
6025 unsigned int i
, j
, applies
;
6027 features
.features
= feature
;
6030 for (i
= 0; i
< context
->glyph_count
; ++i
)
6031 opentype_set_glyph_props(context
, i
);
6033 opentype_layout_collect_lookups(context
, script_index
, language_index
, &features
, context
->table
, &lookups
);
6035 func_is_covered
= context
->table
== &context
->cache
->gsub
? opentype_layout_gsub_lookup_is_glyph_covered
:
6036 opentype_layout_gpos_lookup_is_glyph_covered
;
6038 for (i
= 0; i
< lookups
.count
; ++i
)
6040 struct lookup
*lookup
= &lookups
.lookups
[i
];
6043 for (j
= 0; j
< context
->glyph_count
; ++j
)
6045 if (lookup_is_glyph_match(context
, j
, lookup
->flags
))
6047 if ((is_covered
= func_is_covered(context
, glyphs
[i
], lookup
)))
6049 feature_applies
[j
] |= is_covered
;
6053 if ((ret
= (applies
== context
->glyph_count
)))
6057 heap_free(lookups
.lookups
);
6062 BOOL
opentype_has_vertical_variants(struct dwrite_fontface
*fontface
)
6064 unsigned int i
, j
, count
= 0, lookup_type
, subtable_offset
;
6065 struct shaping_features features
= { 0 };
6066 struct shaping_feature vert_feature
= { 0 };
6067 struct scriptshaping_context context
= { 0 };
6068 struct lookups lookups
= { 0 };
6071 context
.cache
= fontface_get_shaping_cache(fontface
);
6072 context
.table
= &context
.cache
->gsub
;
6074 vert_feature
.tag
= DWRITE_MAKE_OPENTYPE_TAG('v','e','r','t');
6075 vert_feature
.flags
= FEATURE_GLOBAL
| FEATURE_GLOBAL_SEARCH
;
6076 vert_feature
.max_value
= 1;
6077 vert_feature
.default_value
= 1;
6079 features
.features
= &vert_feature
;
6080 features
.count
= features
.capacity
= 1;
6082 opentype_layout_collect_lookups(&context
, ~0u, ~0u, &features
, context
.table
, &lookups
);
6084 for (i
= 0; i
< lookups
.count
&& !count
; ++i
)
6086 const struct dwrite_fonttable
*table
= &context
.table
->table
;
6087 const struct lookup
*lookup
= &lookups
.lookups
[i
];
6089 for (j
= 0; j
< lookup
->subtable_count
&& !count
; ++j
)
6091 subtable_offset
= opentype_layout_get_gsubgpos_subtable(&context
, lookup
, j
, &lookup_type
);
6093 if (lookup_type
!= GSUB_LOOKUP_SINGLE_SUBST
)
6096 format
= table_read_be_word(table
, subtable_offset
);
6102 else if (format
== 2)
6104 count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format2
, count
));
6107 WARN("Unrecognized single substitution format %u.\n", format
);
6111 heap_free(lookups
.lookups
);
6116 HRESULT
opentype_get_vertical_glyph_variants(struct dwrite_fontface
*fontface
, unsigned int glyph_count
,
6117 const UINT16
*nominal_glyphs
, UINT16
*glyphs
)
6119 struct shaping_features features
= { 0 };
6120 struct shaping_feature vert_feature
= { 0 };
6121 struct scriptshaping_context context
= { 0 };
6122 struct lookups lookups
= { 0 };
6125 memcpy(glyphs
, nominal_glyphs
, glyph_count
* sizeof(*glyphs
));
6127 if (!(fontface
->flags
& FONTFACE_HAS_VERTICAL_VARIANTS
))
6130 context
.cache
= fontface_get_shaping_cache(fontface
);
6131 context
.u
.subst
.glyphs
= glyphs
;
6132 context
.u
.subst
.glyph_props
= heap_calloc(glyph_count
, sizeof(*context
.u
.subst
.glyph_props
));
6133 context
.u
.subst
.max_glyph_count
= glyph_count
;
6134 context
.u
.subst
.capacity
= glyph_count
;
6135 context
.glyph_infos
= heap_alloc_zero(sizeof(*context
.glyph_infos
) * glyph_count
);
6136 context
.table
= &context
.cache
->gsub
;
6138 vert_feature
.tag
= DWRITE_MAKE_OPENTYPE_TAG('v','e','r','t');
6139 vert_feature
.flags
= FEATURE_GLOBAL
| FEATURE_GLOBAL_SEARCH
;
6140 vert_feature
.max_value
= 1;
6141 vert_feature
.default_value
= 1;
6143 features
.features
= &vert_feature
;
6144 features
.count
= features
.capacity
= 1;
6146 opentype_layout_collect_lookups(&context
, ~0u, ~0u, &features
, context
.table
, &lookups
);
6147 opentype_layout_set_glyph_masks(&context
, &features
);
6149 for (i
= 0; i
< lookups
.count
; ++i
)
6151 const struct lookup
*lookup
= &lookups
.lookups
[i
];
6154 while (context
.cur
< context
.glyph_count
)
6158 if (lookup_is_glyph_match(&context
, context
.cur
, lookup
->flags
))
6159 ret
= opentype_layout_apply_gsub_lookup(&context
, lookup
);
6166 heap_free(context
.u
.subst
.glyph_props
);
6167 heap_free(context
.glyph_infos
);
6168 heap_free(lookups
.lookups
);