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"
27 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
29 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
30 #define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
31 #define MS_OTTO_TAG DWRITE_MAKE_OPENTYPE_TAG('O','T','T','O')
32 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
33 #define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
34 #define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f')
35 #define MS_GDEF_TAG DWRITE_MAKE_OPENTYPE_TAG('G','D','E','F')
36 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
37 #define MS_GLYF_TAG DWRITE_MAKE_OPENTYPE_TAG('g','l','y','f')
38 #define MS_CFF__TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F',' ')
39 #define MS_CFF2_TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F','2')
40 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
41 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
42 #define MS_SVG__TAG DWRITE_MAKE_OPENTYPE_TAG('S','V','G',' ')
43 #define MS_SBIX_TAG DWRITE_MAKE_OPENTYPE_TAG('s','b','i','x')
44 #define MS_MAXP_TAG DWRITE_MAKE_OPENTYPE_TAG('m','a','x','p')
45 #define MS_CBLC_TAG DWRITE_MAKE_OPENTYPE_TAG('C','B','L','C')
46 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
47 #define MS_META_TAG DWRITE_MAKE_OPENTYPE_TAG('m','e','t','a')
48 #define MS_KERN_TAG DWRITE_MAKE_OPENTYPE_TAG('k','e','r','n')
49 #define MS_FVAR_TAG DWRITE_MAKE_OPENTYPE_TAG('f','v','a','r')
52 #define MS_PNG__TAG DWRITE_MAKE_OPENTYPE_TAG('p','n','g',' ')
53 #define MS_JPG__TAG DWRITE_MAKE_OPENTYPE_TAG('j','p','g',' ')
54 #define MS_TIFF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','i','f','f')
56 #define MS_WOFF_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','F')
57 #define MS_WOF2_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','2')
60 #define MS_DLNG_TAG DWRITE_MAKE_OPENTYPE_TAG('d','l','n','g')
61 #define MS_SLNG_TAG DWRITE_MAKE_OPENTYPE_TAG('s','l','n','g')
63 #ifdef WORDS_BIGENDIAN
64 #define GET_BE_WORD(x) (x)
65 #define GET_BE_DWORD(x) (x)
66 #define GET_BE_FIXED(x) (x / 65536.0f)
68 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
69 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
70 #define GET_BE_FIXED(x) ((int32_t)GET_BE_DWORD(x) / 65536.0f)
73 #define GLYPH_CONTEXT_MAX_LENGTH 64
74 #define SHAPE_MAX_NESTING_LEVEL 6
79 uint16_t major_version
;
80 uint16_t minor_version
;
90 uint16_t entrySelector
;
94 struct ot_table_record
102 struct cmap_encoding_record
113 struct cmap_encoding_record tables
[1];
116 enum OPENTYPE_CMAP_TABLE_FORMAT
118 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
= 4,
119 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
= 12
122 enum opentype_cmap_table_platform
124 OPENTYPE_CMAP_TABLE_PLATFORM_WIN
= 3,
127 enum opentype_cmap_table_encoding
129 OPENTYPE_CMAP_TABLE_ENCODING_SYMBOL
= 0,
130 OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_BMP
= 1,
131 OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_FULL
= 10,
134 /* PANOSE is 10 bytes in size, need to pack the structure properly */
135 #include "pshpack2.h"
152 USHORT lowestRecPPEM
;
153 SHORT direction_hint
;
155 SHORT glyphdata_format
;
158 enum tt_head_macstyle
160 TT_HEAD_MACSTYLE_BOLD
= 1 << 0,
161 TT_HEAD_MACSTYLE_ITALIC
= 1 << 1,
162 TT_HEAD_MACSTYLE_UNDERLINE
= 1 << 2,
163 TT_HEAD_MACSTYLE_OUTLINE
= 1 << 3,
164 TT_HEAD_MACSTYLE_SHADOW
= 1 << 4,
165 TT_HEAD_MACSTYLE_CONDENSED
= 1 << 5,
166 TT_HEAD_MACSTYLE_EXTENDED
= 1 << 6,
173 int16_t underlinePosition
;
174 int16_t underlineThickness
;
175 uint32_t fixed_pitch
;
176 uint32_t minmemType42
;
177 uint32_t maxmemType42
;
178 uint32_t minmemType1
;
179 uint32_t maxmemType1
;
186 USHORT usWeightClass
;
189 SHORT ySubscriptXSize
;
190 SHORT ySubscriptYSize
;
191 SHORT ySubscriptXOffset
;
192 SHORT ySubscriptYOffset
;
193 SHORT ySuperscriptXSize
;
194 SHORT ySuperscriptYSize
;
195 SHORT ySuperscriptXOffset
;
196 SHORT ySuperscriptYOffset
;
197 SHORT yStrikeoutSize
;
198 SHORT yStrikeoutPosition
;
201 ULONG ulUnicodeRange1
;
202 ULONG ulUnicodeRange2
;
203 ULONG ulUnicodeRange3
;
204 ULONG ulUnicodeRange4
;
207 USHORT usFirstCharIndex
;
208 USHORT usLastCharIndex
;
209 /* According to the Apple spec, original version didn't have the below fields,
210 * version numbers were taken from the OpenType spec.
212 /* version 0 (TrueType 1.5) */
213 USHORT sTypoAscender
;
214 USHORT sTypoDescender
;
218 /* version 1 (TrueType 1.66) */
219 ULONG ulCodePageRange1
;
220 ULONG ulCodePageRange2
;
221 /* version 2 (OpenType 1.2) */
224 USHORT usDefaultChar
;
231 uint16_t majorVersion
;
232 uint16_t minorVersion
;
236 uint16_t advanceWidthMax
;
237 int16_t minLeftSideBearing
;
238 int16_t minRightSideBearing
;
240 int16_t caretSlopeRise
;
241 int16_t caretSlopeRun
;
244 int16_t metricDataFormat
;
245 uint16_t numberOfHMetrics
;
252 uint32_t num_strikes
;
253 uint32_t strike_offset
[1];
260 uint32_t glyphdata_offsets
[1];
263 struct sbix_glyph_data
265 int16_t originOffsetX
;
266 int16_t originOffsetY
;
267 uint32_t graphic_type
;
279 uint16_t major_version
;
280 uint16_t minor_version
;
284 struct sbit_line_metrics
289 int8_t caretSlopeNumerator
;
290 int8_t caretSlopeDenominator
;
300 struct cblc_bitmapsize_table
302 uint32_t indexSubTableArrayOffset
;
303 uint32_t indexTablesSize
;
304 uint32_t numberofIndexSubTables
;
306 struct sbit_line_metrics hori
;
307 struct sbit_line_metrics vert
;
308 uint16_t startGlyphIndex
;
309 uint16_t endGlyphIndex
;
326 struct gasp_range ranges
[1];
329 enum OS2_FSSELECTION
{
330 OS2_FSSELECTION_ITALIC
= 1 << 0,
331 OS2_FSSELECTION_UNDERSCORE
= 1 << 1,
332 OS2_FSSELECTION_NEGATIVE
= 1 << 2,
333 OS2_FSSELECTION_OUTLINED
= 1 << 3,
334 OS2_FSSELECTION_STRIKEOUT
= 1 << 4,
335 OS2_FSSELECTION_BOLD
= 1 << 5,
336 OS2_FSSELECTION_REGULAR
= 1 << 6,
337 OS2_FSSELECTION_USE_TYPO_METRICS
= 1 << 7,
338 OS2_FSSELECTION_WWS
= 1 << 8,
339 OS2_FSSELECTION_OBLIQUE
= 1 << 9
356 uint16_t stringOffset
;
357 struct name_record records
[1];
387 struct vdmx_vtable entries
[1];
390 struct ot_feature_record
396 struct ot_feature_list
398 uint16_t feature_count
;
399 struct ot_feature_record features
[1];
404 uint16_t lookup_order
; /* Reserved */
405 uint16_t required_feature_index
;
406 uint16_t feature_count
;
407 uint16_t feature_index
[1];
410 struct ot_langsys_record
418 uint16_t default_langsys
;
419 uint16_t langsys_count
;
420 struct ot_langsys_record langsys
[1];
423 struct ot_script_record
429 struct ot_script_list
431 uint16_t script_count
;
432 struct ot_script_record scripts
[1];
437 GDEF_CLASS_UNCLASSIFIED
= 0,
439 GDEF_CLASS_LIGATURE
= 2,
441 GDEF_CLASS_COMPONENT
= 4,
442 GDEF_CLASS_MAX
= GDEF_CLASS_COMPONENT
,
447 uint16_t major_version
;
448 uint16_t minor_version
;
450 uint16_t attach_list
;
451 uint16_t ligcaret_list
;
452 uint16_t markattach_classdef
;
453 uint16_t markglyphsetdef
;
456 struct ot_gdef_classdef_format1
459 uint16_t start_glyph
;
460 uint16_t glyph_count
;
464 struct ot_gdef_class_range
466 uint16_t start_glyph
;
468 uint16_t glyph_class
;
471 struct ot_gdef_classdef_format2
474 uint16_t range_count
;
475 struct ot_gdef_class_range ranges
[1];
478 struct ot_gdef_markglyphsets
485 struct gpos_gsub_header
487 uint16_t major_version
;
488 uint16_t minor_version
;
489 uint16_t script_list
;
490 uint16_t feature_list
;
491 uint16_t lookup_list
;
494 enum gsub_gpos_lookup_flags
496 LOOKUP_FLAG_RTL
= 0x1, /* Only used for GPOS cursive attachments. */
498 LOOKUP_FLAG_IGNORE_BASE
= 0x2,
499 LOOKUP_FLAG_IGNORE_LIGATURES
= 0x4,
500 LOOKUP_FLAG_IGNORE_MARKS
= 0x8,
501 LOOKUP_FLAG_IGNORE_MASK
= 0xe, /* Combined LOOKUP_FLAG_IGNORE_* flags. */
503 LOOKUP_FLAG_USE_MARK_FILTERING_SET
= 0x10,
504 LOOKUP_FLAG_MARK_ATTACHMENT_TYPE
= 0xff00,
509 GLYPH_ATTACH_NONE
= 0,
511 GLYPH_ATTACH_CURSIVE
,
514 enum glyph_prop_flags
516 GLYPH_PROP_BASE
= LOOKUP_FLAG_IGNORE_BASE
,
517 GLYPH_PROP_LIGATURE
= LOOKUP_FLAG_IGNORE_LIGATURES
,
518 GLYPH_PROP_MARK
= LOOKUP_FLAG_IGNORE_MARKS
,
520 GLYPH_PROP_ZWNJ
= 0x10,
521 GLYPH_PROP_ZWJ
= 0x20,
522 GLYPH_PROP_IGNORABLE
= 0x40,
523 GLYPH_PROP_HIDDEN
= 0x80,
525 GLYPH_PROP_MARK_ATTACH_CLASS_MASK
= 0xff00, /* Used with LOOKUP_FLAG_MARK_ATTACHMENT_TYPE. */
526 GLYPH_PROP_ATTACH_TYPE_MASK
= 0xff0000,
529 enum gpos_lookup_type
531 GPOS_LOOKUP_SINGLE_ADJUSTMENT
= 1,
532 GPOS_LOOKUP_PAIR_ADJUSTMENT
= 2,
533 GPOS_LOOKUP_CURSIVE_ATTACHMENT
= 3,
534 GPOS_LOOKUP_MARK_TO_BASE_ATTACHMENT
= 4,
535 GPOS_LOOKUP_MARK_TO_LIGATURE_ATTACHMENT
= 5,
536 GPOS_LOOKUP_MARK_TO_MARK_ATTACHMENT
= 6,
537 GPOS_LOOKUP_CONTEXTUAL_POSITION
= 7,
538 GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION
= 8,
539 GPOS_LOOKUP_EXTENSION_POSITION
= 9,
542 enum gsub_lookup_type
544 GSUB_LOOKUP_SINGLE_SUBST
= 1,
545 GSUB_LOOKUP_MULTIPLE_SUBST
= 2,
546 GSUB_LOOKUP_ALTERNATE_SUBST
= 3,
547 GSUB_LOOKUP_LIGATURE_SUBST
= 4,
548 GSUB_LOOKUP_CONTEXTUAL_SUBST
= 5,
549 GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST
= 6,
550 GSUB_LOOKUP_EXTENSION_SUBST
= 7,
551 GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST
= 8,
554 enum gpos_value_format
556 GPOS_VALUE_X_PLACEMENT
= 0x1,
557 GPOS_VALUE_Y_PLACEMENT
= 0x2,
558 GPOS_VALUE_X_ADVANCE
= 0x4,
559 GPOS_VALUE_Y_ADVANCE
= 0x8,
560 GPOS_VALUE_X_PLACEMENT_DEVICE
= 0x10,
561 GPOS_VALUE_Y_PLACEMENT_DEVICE
= 0x20,
562 GPOS_VALUE_X_ADVANCE_DEVICE
= 0x40,
563 GPOS_VALUE_Y_ADVANCE_DEVICE
= 0x80,
566 enum OPENTYPE_PLATFORM_ID
568 OPENTYPE_PLATFORM_UNICODE
= 0,
569 OPENTYPE_PLATFORM_MAC
,
570 OPENTYPE_PLATFORM_ISO
,
571 OPENTYPE_PLATFORM_WIN
,
572 OPENTYPE_PLATFORM_CUSTOM
575 struct ot_gsubgpos_extension_format1
578 uint16_t lookup_type
;
579 uint32_t extension_offset
;
582 struct ot_gsub_singlesubst_format1
589 struct ot_gsub_singlesubst_format2
594 uint16_t substitutes
[1];
597 struct ot_gsub_multsubst_format1
605 struct ot_gsub_altsubst_format1
613 struct ot_gsub_ligsubst_format1
617 uint16_t lig_set_count
;
618 uint16_t lig_sets
[1];
621 struct ot_gsub_ligset
631 uint16_t components
[1];
634 struct ot_gsubgpos_context_format1
638 uint16_t ruleset_count
;
639 uint16_t rulesets
[1];
642 struct ot_gsubgpos_ruleset
650 uint16_t feature_params
;
651 uint16_t lookup_count
;
652 uint16_t lookuplist_index
[1];
655 struct ot_lookup_list
657 uint16_t lookup_count
;
661 struct ot_lookup_table
663 uint16_t lookup_type
;
665 uint16_t subtable_count
;
666 uint16_t subtable
[1];
669 #define GLYPH_NOT_COVERED (~0u)
671 struct ot_coverage_format1
674 uint16_t glyph_count
;
678 struct ot_coverage_range
680 uint16_t start_glyph
;
682 uint16_t startcoverage_index
;
685 struct ot_coverage_format2
688 uint16_t range_count
;
689 struct ot_coverage_range ranges
[1];
692 struct ot_gpos_device_table
700 struct ot_gpos_singlepos_format1
704 uint16_t value_format
;
708 struct ot_gpos_singlepos_format2
712 uint16_t value_format
;
713 uint16_t value_count
;
717 struct ot_gpos_pairvalue
719 uint16_t second_glyph
;
723 struct ot_gpos_pairset
725 uint16_t pairvalue_count
;
726 struct ot_gpos_pairvalue pairvalues
[1];
729 struct ot_gpos_pairpos_format1
733 uint16_t value_format1
;
734 uint16_t value_format2
;
735 uint16_t pairset_count
;
736 uint16_t pairsets
[1];
739 struct ot_gpos_pairpos_format2
743 uint16_t value_format1
;
744 uint16_t value_format2
;
747 uint16_t class1_count
;
748 uint16_t class2_count
;
752 struct ot_gpos_anchor_format1
759 struct ot_gpos_anchor_format2
764 uint16_t anchor_point
;
767 struct ot_gpos_anchor_format3
772 uint16_t x_dev_offset
;
773 uint16_t y_dev_offset
;
776 struct ot_gpos_cursive_format1
784 struct ot_gpos_mark_record
787 uint16_t mark_anchor
;
790 struct ot_gpos_mark_array
793 struct ot_gpos_mark_record records
[1];
796 struct ot_gpos_base_array
802 struct ot_gpos_mark_to_base_format1
805 uint16_t mark_coverage
;
806 uint16_t base_coverage
;
807 uint16_t mark_class_count
;
812 struct ot_gpos_mark_to_lig_format1
815 uint16_t mark_coverage
;
816 uint16_t lig_coverage
;
817 uint16_t mark_class_count
;
822 struct ot_gpos_mark_to_mark_format1
825 uint16_t mark1_coverage
;
826 uint16_t mark2_coverage
;
827 uint16_t mark_class_count
;
828 uint16_t mark1_array
;
829 uint16_t mark2_array
;
835 uint16_t table_count
;
838 struct kern_subtable_header
847 enum TT_NAME_WINDOWS_ENCODING_ID
849 TT_NAME_WINDOWS_ENCODING_SYMBOL
= 0,
850 TT_NAME_WINDOWS_ENCODING_UNICODE_BMP
,
851 TT_NAME_WINDOWS_ENCODING_SJIS
,
852 TT_NAME_WINDOWS_ENCODING_PRC
,
853 TT_NAME_WINDOWS_ENCODING_BIG5
,
854 TT_NAME_WINDOWS_ENCODING_WANSUNG
,
855 TT_NAME_WINDOWS_ENCODING_JOHAB
,
856 TT_NAME_WINDOWS_ENCODING_RESERVED1
,
857 TT_NAME_WINDOWS_ENCODING_RESERVED2
,
858 TT_NAME_WINDOWS_ENCODING_RESERVED3
,
859 TT_NAME_WINDOWS_ENCODING_UNICODE_FULL
862 enum TT_NAME_MAC_ENCODING_ID
864 TT_NAME_MAC_ENCODING_ROMAN
= 0,
865 TT_NAME_MAC_ENCODING_JAPANESE
,
866 TT_NAME_MAC_ENCODING_TRAD_CHINESE
,
867 TT_NAME_MAC_ENCODING_KOREAN
,
868 TT_NAME_MAC_ENCODING_ARABIC
,
869 TT_NAME_MAC_ENCODING_HEBREW
,
870 TT_NAME_MAC_ENCODING_GREEK
,
871 TT_NAME_MAC_ENCODING_RUSSIAN
,
872 TT_NAME_MAC_ENCODING_RSYMBOL
,
873 TT_NAME_MAC_ENCODING_DEVANAGARI
,
874 TT_NAME_MAC_ENCODING_GURMUKHI
,
875 TT_NAME_MAC_ENCODING_GUJARATI
,
876 TT_NAME_MAC_ENCODING_ORIYA
,
877 TT_NAME_MAC_ENCODING_BENGALI
,
878 TT_NAME_MAC_ENCODING_TAMIL
,
879 TT_NAME_MAC_ENCODING_TELUGU
,
880 TT_NAME_MAC_ENCODING_KANNADA
,
881 TT_NAME_MAC_ENCODING_MALAYALAM
,
882 TT_NAME_MAC_ENCODING_SINHALESE
,
883 TT_NAME_MAC_ENCODING_BURMESE
,
884 TT_NAME_MAC_ENCODING_KHMER
,
885 TT_NAME_MAC_ENCODING_THAI
,
886 TT_NAME_MAC_ENCODING_LAOTIAN
,
887 TT_NAME_MAC_ENCODING_GEORGIAN
,
888 TT_NAME_MAC_ENCODING_ARMENIAN
,
889 TT_NAME_MAC_ENCODING_SIMPL_CHINESE
,
890 TT_NAME_MAC_ENCODING_TIBETAN
,
891 TT_NAME_MAC_ENCODING_MONGOLIAN
,
892 TT_NAME_MAC_ENCODING_GEEZ
,
893 TT_NAME_MAC_ENCODING_SLAVIC
,
894 TT_NAME_MAC_ENCODING_VIETNAMESE
,
895 TT_NAME_MAC_ENCODING_SINDHI
,
896 TT_NAME_MAC_ENCODING_UNINTERPRETED
899 enum TT_NAME_MAC_LANGUAGE_ID
901 TT_NAME_MAC_LANGID_ENGLISH
= 0,
902 TT_NAME_MAC_LANGID_FRENCH
,
903 TT_NAME_MAC_LANGID_GERMAN
,
904 TT_NAME_MAC_LANGID_ITALIAN
,
905 TT_NAME_MAC_LANGID_DUTCH
,
906 TT_NAME_MAC_LANGID_SWEDISH
,
907 TT_NAME_MAC_LANGID_SPANISH
,
908 TT_NAME_MAC_LANGID_DANISH
,
909 TT_NAME_MAC_LANGID_PORTUGUESE
,
910 TT_NAME_MAC_LANGID_NORWEGIAN
,
911 TT_NAME_MAC_LANGID_HEBREW
,
912 TT_NAME_MAC_LANGID_JAPANESE
,
913 TT_NAME_MAC_LANGID_ARABIC
,
914 TT_NAME_MAC_LANGID_FINNISH
,
915 TT_NAME_MAC_LANGID_GREEK
,
916 TT_NAME_MAC_LANGID_ICELANDIC
,
917 TT_NAME_MAC_LANGID_MALTESE
,
918 TT_NAME_MAC_LANGID_TURKISH
,
919 TT_NAME_MAC_LANGID_CROATIAN
,
920 TT_NAME_MAC_LANGID_TRAD_CHINESE
,
921 TT_NAME_MAC_LANGID_URDU
,
922 TT_NAME_MAC_LANGID_HINDI
,
923 TT_NAME_MAC_LANGID_THAI
,
924 TT_NAME_MAC_LANGID_KOREAN
,
925 TT_NAME_MAC_LANGID_LITHUANIAN
,
926 TT_NAME_MAC_LANGID_POLISH
,
927 TT_NAME_MAC_LANGID_HUNGARIAN
,
928 TT_NAME_MAC_LANGID_ESTONIAN
,
929 TT_NAME_MAC_LANGID_LATVIAN
,
930 TT_NAME_MAC_LANGID_SAMI
,
931 TT_NAME_MAC_LANGID_FAROESE
,
932 TT_NAME_MAC_LANGID_FARSI
,
933 TT_NAME_MAC_LANGID_RUSSIAN
,
934 TT_NAME_MAC_LANGID_SIMPL_CHINESE
,
935 TT_NAME_MAC_LANGID_FLEMISH
,
936 TT_NAME_MAC_LANGID_GAELIC
,
937 TT_NAME_MAC_LANGID_ALBANIAN
,
938 TT_NAME_MAC_LANGID_ROMANIAN
,
939 TT_NAME_MAC_LANGID_CZECH
,
940 TT_NAME_MAC_LANGID_SLOVAK
,
941 TT_NAME_MAC_LANGID_SLOVENIAN
,
942 TT_NAME_MAC_LANGID_YIDDISH
,
943 TT_NAME_MAC_LANGID_SERBIAN
,
944 TT_NAME_MAC_LANGID_MACEDONIAN
,
945 TT_NAME_MAC_LANGID_BULGARIAN
,
946 TT_NAME_MAC_LANGID_UKRAINIAN
,
947 TT_NAME_MAC_LANGID_BYELORUSSIAN
,
948 TT_NAME_MAC_LANGID_UZBEK
,
949 TT_NAME_MAC_LANGID_KAZAKH
,
950 TT_NAME_MAC_LANGID_AZERB_CYR
,
951 TT_NAME_MAC_LANGID_AZERB_ARABIC
,
952 TT_NAME_MAC_LANGID_ARMENIAN
,
953 TT_NAME_MAC_LANGID_GEORGIAN
,
954 TT_NAME_MAC_LANGID_MOLDAVIAN
,
955 TT_NAME_MAC_LANGID_KIRGHIZ
,
956 TT_NAME_MAC_LANGID_TAJIKI
,
957 TT_NAME_MAC_LANGID_TURKMEN
,
958 TT_NAME_MAC_LANGID_MONGOLIAN
,
959 TT_NAME_MAC_LANGID_MONGOLIAN_CYR
,
960 TT_NAME_MAC_LANGID_PASHTO
,
961 TT_NAME_MAC_LANGID_KURDISH
,
962 TT_NAME_MAC_LANGID_KASHMIRI
,
963 TT_NAME_MAC_LANGID_SINDHI
,
964 TT_NAME_MAC_LANGID_TIBETAN
,
965 TT_NAME_MAC_LANGID_NEPALI
,
966 TT_NAME_MAC_LANGID_SANSKRIT
,
967 TT_NAME_MAC_LANGID_MARATHI
,
968 TT_NAME_MAC_LANGID_BENGALI
,
969 TT_NAME_MAC_LANGID_ASSAMESE
,
970 TT_NAME_MAC_LANGID_GUJARATI
,
971 TT_NAME_MAC_LANGID_PUNJABI
,
972 TT_NAME_MAC_LANGID_ORIYA
,
973 TT_NAME_MAC_LANGID_MALAYALAM
,
974 TT_NAME_MAC_LANGID_KANNADA
,
975 TT_NAME_MAC_LANGID_TAMIL
,
976 TT_NAME_MAC_LANGID_TELUGU
,
977 TT_NAME_MAC_LANGID_SINHALESE
,
978 TT_NAME_MAC_LANGID_BURMESE
,
979 TT_NAME_MAC_LANGID_KHMER
,
980 TT_NAME_MAC_LANGID_LAO
,
981 TT_NAME_MAC_LANGID_VIETNAMESE
,
982 TT_NAME_MAC_LANGID_INDONESIAN
,
983 TT_NAME_MAC_LANGID_TAGALOG
,
984 TT_NAME_MAC_LANGID_MALAY_ROMAN
,
985 TT_NAME_MAC_LANGID_MALAY_ARABIC
,
986 TT_NAME_MAC_LANGID_AMHARIC
,
987 TT_NAME_MAC_LANGID_TIGRINYA
,
988 TT_NAME_MAC_LANGID_GALLA
,
989 TT_NAME_MAC_LANGID_SOMALI
,
990 TT_NAME_MAC_LANGID_SWAHILI
,
991 TT_NAME_MAC_LANGID_KINYARWANDA
,
992 TT_NAME_MAC_LANGID_RUNDI
,
993 TT_NAME_MAC_LANGID_NYANJA
,
994 TT_NAME_MAC_LANGID_MALAGASY
,
995 TT_NAME_MAC_LANGID_ESPERANTO
,
996 TT_NAME_MAC_LANGID_WELSH
= 128,
997 TT_NAME_MAC_LANGID_BASQUE
,
998 TT_NAME_MAC_LANGID_CATALAN
,
999 TT_NAME_MAC_LANGID_LATIN
,
1000 TT_NAME_MAC_LANGID_QUECHUA
,
1001 TT_NAME_MAC_LANGID_GUARANI
,
1002 TT_NAME_MAC_LANGID_AYMARA
,
1003 TT_NAME_MAC_LANGID_TATAR
,
1004 TT_NAME_MAC_LANGID_UIGHUR
,
1005 TT_NAME_MAC_LANGID_DZONGKHA
,
1006 TT_NAME_MAC_LANGID_JAVANESE
,
1007 TT_NAME_MAC_LANGID_SUNDANESE
,
1008 TT_NAME_MAC_LANGID_GALICIAN
,
1009 TT_NAME_MAC_LANGID_AFRIKAANS
,
1010 TT_NAME_MAC_LANGID_BRETON
,
1011 TT_NAME_MAC_LANGID_INUKTITUT
,
1012 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC
,
1013 TT_NAME_MAC_LANGID_MANX_GAELIC
,
1014 TT_NAME_MAC_LANGID_IRISH_GAELIC
,
1015 TT_NAME_MAC_LANGID_TONGAN
,
1016 TT_NAME_MAC_LANGID_GREEK_POLYTONIC
,
1017 TT_NAME_MAC_LANGID_GREENLANDIC
,
1018 TT_NAME_MAC_LANGID_AZER_ROMAN
1021 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
1022 static const char name_mac_langid_to_locale
[][10] = {
1176 enum OPENTYPE_STRING_ID
1178 OPENTYPE_STRING_COPYRIGHT_NOTICE
= 0,
1179 OPENTYPE_STRING_FAMILY_NAME
,
1180 OPENTYPE_STRING_SUBFAMILY_NAME
,
1181 OPENTYPE_STRING_UNIQUE_IDENTIFIER
,
1182 OPENTYPE_STRING_FULL_FONTNAME
,
1183 OPENTYPE_STRING_VERSION_STRING
,
1184 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
1185 OPENTYPE_STRING_TRADEMARK
,
1186 OPENTYPE_STRING_MANUFACTURER
,
1187 OPENTYPE_STRING_DESIGNER
,
1188 OPENTYPE_STRING_DESCRIPTION
,
1189 OPENTYPE_STRING_VENDOR_URL
,
1190 OPENTYPE_STRING_DESIGNER_URL
,
1191 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
1192 OPENTYPE_STRING_LICENSE_INFO_URL
,
1193 OPENTYPE_STRING_RESERVED_ID15
,
1194 OPENTYPE_STRING_TYPOGRAPHIC_FAMILY_NAME
,
1195 OPENTYPE_STRING_TYPOGRAPHIC_SUBFAMILY_NAME
,
1196 OPENTYPE_STRING_COMPATIBLE_FULLNAME
,
1197 OPENTYPE_STRING_SAMPLE_TEXT
,
1198 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
1199 OPENTYPE_STRING_WWS_FAMILY_NAME
,
1200 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
1203 static const UINT16 dwriteid_to_opentypeid
[DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME
+ 1] =
1205 (UINT16
)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
1206 OPENTYPE_STRING_COPYRIGHT_NOTICE
,
1207 OPENTYPE_STRING_VERSION_STRING
,
1208 OPENTYPE_STRING_TRADEMARK
,
1209 OPENTYPE_STRING_MANUFACTURER
,
1210 OPENTYPE_STRING_DESIGNER
,
1211 OPENTYPE_STRING_DESIGNER_URL
,
1212 OPENTYPE_STRING_DESCRIPTION
,
1213 OPENTYPE_STRING_VENDOR_URL
,
1214 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
1215 OPENTYPE_STRING_LICENSE_INFO_URL
,
1216 OPENTYPE_STRING_FAMILY_NAME
,
1217 OPENTYPE_STRING_SUBFAMILY_NAME
,
1218 OPENTYPE_STRING_TYPOGRAPHIC_FAMILY_NAME
,
1219 OPENTYPE_STRING_TYPOGRAPHIC_SUBFAMILY_NAME
,
1220 OPENTYPE_STRING_SAMPLE_TEXT
,
1221 OPENTYPE_STRING_FULL_FONTNAME
,
1222 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
1223 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
1224 OPENTYPE_STRING_WWS_FAMILY_NAME
,
1228 struct cpal_header_0
1231 uint16_t num_palette_entries
;
1232 uint16_t num_palettes
;
1233 uint16_t num_color_records
;
1234 uint32_t offset_first_color_record
;
1235 uint16_t color_record_indices
[1];
1238 struct cpal_color_record
1250 uint16_t num_baseglyph_records
;
1251 uint32_t offset_baseglyph_records
;
1252 uint32_t offset_layer_records
;
1253 uint16_t num_layer_records
;
1256 struct colr_baseglyph_record
1259 uint16_t first_layer_index
;
1260 uint16_t num_layers
;
1263 struct colr_layer_record
1266 uint16_t palette_index
;
1269 struct meta_data_map
1281 uint32_t data_maps_count
;
1282 struct meta_data_map maps
[1];
1287 uint16_t major_version
;
1288 uint16_t minor_version
;
1289 uint16_t axes_array_offset
;
1291 uint16_t axis_count
;
1293 uint16_t instance_count
;
1294 uint16_t instance_size
;
1297 struct var_axis_record
1301 int32_t default_value
;
1307 static const void *table_read_ensure(const struct dwrite_fonttable
*table
, unsigned int offset
, unsigned int size
)
1309 if (size
> table
->size
|| offset
> table
->size
- size
)
1312 return table
->data
+ offset
;
1315 static WORD
table_read_be_word(const struct dwrite_fonttable
*table
, unsigned int offset
)
1317 const WORD
*ptr
= table_read_ensure(table
, offset
, sizeof(*ptr
));
1318 return ptr
? GET_BE_WORD(*ptr
) : 0;
1321 static DWORD
table_read_be_dword(const struct dwrite_fonttable
*table
, unsigned int offset
)
1323 const DWORD
*ptr
= table_read_ensure(table
, offset
, sizeof(*ptr
));
1324 return ptr
? GET_BE_DWORD(*ptr
) : 0;
1327 static float table_read_be_fixed(const struct dwrite_fonttable
*table
, unsigned int offset
)
1329 return (int32_t)table_read_be_dword(table
, offset
) / 65536.0;
1332 static DWORD
table_read_dword(const struct dwrite_fonttable
*table
, unsigned int offset
)
1334 const DWORD
*ptr
= table_read_ensure(table
, offset
, sizeof(*ptr
));
1335 return ptr
? *ptr
: 0;
1338 BOOL
is_face_type_supported(DWRITE_FONT_FACE_TYPE type
)
1340 return (type
== DWRITE_FONT_FACE_TYPE_CFF
) ||
1341 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE
) ||
1342 (type
== DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
) ||
1343 (type
== DWRITE_FONT_FACE_TYPE_RAW_CFF
);
1346 typedef HRESULT (*dwrite_fontfile_analyzer
)(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1347 DWRITE_FONT_FACE_TYPE
*face_type
);
1349 static HRESULT
opentype_ttc_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1350 DWRITE_FONT_FACE_TYPE
*face_type
)
1352 const struct ttc_header
*header
;
1356 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(header
), &context
);
1360 if (header
->tag
== MS_TTCF_TAG
)
1362 *font_count
= GET_BE_DWORD(header
->num_fonts
);
1363 *file_type
= DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION
;
1364 *face_type
= DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
;
1367 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1369 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1372 static HRESULT
opentype_ttf_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1373 DWRITE_FONT_FACE_TYPE
*face_type
)
1375 const DWORD
*header
;
1379 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
1383 if (GET_BE_DWORD(*header
) == 0x10000) {
1385 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE
;
1386 *face_type
= DWRITE_FONT_FACE_TYPE_TRUETYPE
;
1389 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1391 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1394 static HRESULT
opentype_otf_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1395 DWRITE_FONT_FACE_TYPE
*face_type
)
1397 const DWORD
*header
;
1401 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
1405 if (GET_BE_DWORD(*header
) == MS_OTTO_TAG
) {
1407 *file_type
= DWRITE_FONT_FILE_TYPE_CFF
;
1408 *face_type
= DWRITE_FONT_FACE_TYPE_CFF
;
1411 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1413 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1416 static HRESULT
opentype_type1_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
1417 DWRITE_FONT_FACE_TYPE
*face_type
)
1419 #include "pshpack1.h"
1420 /* Specified in Adobe TechNote #5178 */
1428 #include "poppack.h"
1429 struct type1_header
{
1433 const struct type1_header
*header
;
1437 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
1441 /* tag is followed by plain text section */
1442 if (header
->tag
== 0x8001 &&
1443 (!memcmp(header
->data
, "%!PS-AdobeFont", 14) ||
1444 !memcmp(header
->data
, "%!FontType", 10))) {
1446 *file_type
= DWRITE_FONT_FILE_TYPE_TYPE1_PFB
;
1447 *face_type
= DWRITE_FONT_FACE_TYPE_TYPE1
;
1450 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1452 /* let's see if it's a .pfm metrics file */
1453 if (*file_type
== DWRITE_FONT_FILE_TYPE_UNKNOWN
) {
1454 const struct pfm_header
*pfm_header
;
1457 BOOL header_checked
;
1459 hr
= IDWriteFontFileStream_GetFileSize(stream
, &filesize
);
1463 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&pfm_header
, 0, sizeof(*pfm_header
), &context
);
1467 offset
= pfm_header
->dfDevice
;
1468 header_checked
= pfm_header
->dfVersion
== 0x100 && pfm_header
->dfSize
== filesize
;
1469 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1471 /* as a last test check static string in PostScript information section */
1472 if (header_checked
) {
1473 static const char postscript
[] = "PostScript";
1476 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&devtype_name
, offset
, sizeof(postscript
), &context
);
1480 if (!memcmp(devtype_name
, postscript
, sizeof(postscript
))) {
1482 *file_type
= DWRITE_FONT_FILE_TYPE_TYPE1_PFM
;
1483 *face_type
= DWRITE_FONT_FACE_TYPE_TYPE1
;
1486 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1490 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1493 HRESULT
opentype_analyze_font(IDWriteFontFileStream
*stream
, BOOL
*supported
, DWRITE_FONT_FILE_TYPE
*file_type
,
1494 DWRITE_FONT_FACE_TYPE
*face_type
, UINT32
*face_count
)
1496 static dwrite_fontfile_analyzer fontfile_analyzers
[] = {
1497 opentype_ttf_analyzer
,
1498 opentype_otf_analyzer
,
1499 opentype_ttc_analyzer
,
1500 opentype_type1_analyzer
,
1503 dwrite_fontfile_analyzer
*analyzer
= fontfile_analyzers
;
1504 DWRITE_FONT_FACE_TYPE face
;
1510 *file_type
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
1511 *face_type
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
1515 hr
= (*analyzer
)(stream
, face_count
, file_type
, face_type
);
1525 *supported
= is_face_type_supported(*face_type
);
1529 HRESULT
opentype_try_get_font_table(const struct file_stream_desc
*stream_desc
, UINT32 tag
, const void **table_data
,
1530 void **table_context
, UINT32
*table_size
, BOOL
*found
)
1532 void *table_directory_context
, *sfnt_context
;
1533 const struct ot_table_record
*table_record
= NULL
;
1534 const struct ot_table_dir
*table_dir
= NULL
;
1535 UINT32 table_offset
= 0;
1539 if (found
) *found
= FALSE
;
1540 if (table_size
) *table_size
= 0;
1543 *table_context
= NULL
;
1545 if (stream_desc
->face_type
== DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
)
1547 const struct ttc_header
*ttc_header
;
1550 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void **)&ttc_header
, 0,
1551 sizeof(*ttc_header
), &ttc_context
);
1554 if (stream_desc
->face_index
>= GET_BE_DWORD(ttc_header
->num_fonts
))
1558 table_offset
= GET_BE_DWORD(ttc_header
->offsets
[stream_desc
->face_index
]);
1559 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void **)&table_dir
, table_offset
,
1560 sizeof(*table_dir
), &sfnt_context
);
1562 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, ttc_context
);
1566 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void **)&table_dir
, 0,
1567 sizeof(*table_dir
), &sfnt_context
);
1572 table_count
= GET_BE_WORD(table_dir
->numTables
);
1573 table_offset
+= sizeof(*table_dir
);
1575 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, sfnt_context
);
1577 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void **)&table_record
, table_offset
,
1578 table_count
* sizeof(*table_record
), &table_directory_context
);
1583 for (i
= 0; i
< table_count
; ++i
)
1585 if (table_record
->tag
== tag
)
1587 UINT32 offset
= GET_BE_DWORD(table_record
->offset
);
1588 UINT32 length
= GET_BE_DWORD(table_record
->length
);
1593 *table_size
= length
;
1594 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, table_data
, offset
,
1595 length
, table_context
);
1601 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, table_directory_context
);
1607 static HRESULT
opentype_get_font_table(const struct file_stream_desc
*stream_desc
, UINT32 tag
,
1608 struct dwrite_fonttable
*table
)
1610 return opentype_try_get_font_table(stream_desc
, tag
, (const void **)&table
->data
, &table
->context
, &table
->size
, &table
->exists
);
1617 static UINT16
opentype_cmap_format0_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1619 const UINT8
*glyphs
= cmap
->data
;
1620 return (ch
< 0xff) ? glyphs
[ch
] : 0;
1623 static unsigned int opentype_cmap_format0_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1624 DWRITE_UNICODE_RANGE
*ranges
)
1635 struct cmap_format4_compare_context
1637 const struct dwrite_cmap
*cmap
;
1641 static int __cdecl
cmap_format4_compare_range(const void *a
, const void *b
)
1643 const struct cmap_format4_compare_context
*key
= a
;
1644 const UINT16
*end
= b
;
1647 if (key
->ch
> GET_BE_WORD(*end
))
1650 idx
= end
- key
->cmap
->u
.format4
.ends
;
1651 if (key
->ch
< GET_BE_WORD(key
->cmap
->u
.format4
.starts
[idx
]))
1657 static UINT16
opentype_cmap_format4_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1659 struct cmap_format4_compare_context key
= { .cmap
= cmap
, .ch
= ch
};
1660 unsigned int glyph
, idx
, range_offset
;
1661 const UINT16
*end_found
;
1663 /* Look up range. */
1664 end_found
= bsearch(&key
, cmap
->u
.format4
.ends
, cmap
->u
.format4
.seg_count
, sizeof(*cmap
->u
.format4
.ends
),
1665 cmap_format4_compare_range
);
1669 idx
= end_found
- cmap
->u
.format4
.ends
;
1671 range_offset
= GET_BE_WORD(cmap
->u
.format4
.id_range_offset
[idx
]);
1675 glyph
= ch
+ GET_BE_WORD(cmap
->u
.format4
.id_delta
[idx
]);
1679 unsigned int index
= range_offset
/ 2 + (ch
- GET_BE_WORD(cmap
->u
.format4
.starts
[idx
])) + idx
- cmap
->u
.format4
.seg_count
;
1680 if (index
>= cmap
->u
.format4
.glyph_id_array_len
)
1682 glyph
= GET_BE_WORD(cmap
->u
.format4
.glyph_id_array
[index
]);
1685 glyph
+= GET_BE_WORD(cmap
->u
.format4
.id_delta
[idx
]);
1688 return glyph
& 0xffff;
1691 static unsigned int opentype_cmap_format4_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1692 DWRITE_UNICODE_RANGE
*ranges
)
1696 count
= min(count
, cmap
->u
.format4
.seg_count
);
1698 for (i
= 0; i
< count
; ++i
)
1700 ranges
[i
].first
= GET_BE_WORD(cmap
->u
.format4
.starts
[i
]);
1701 ranges
[i
].last
= GET_BE_WORD(cmap
->u
.format4
.ends
[i
]);
1704 return cmap
->u
.format4
.seg_count
;
1707 static UINT16
opentype_cmap_format6_10_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1709 const UINT16
*glyphs
= cmap
->data
;
1710 if (ch
< cmap
->u
.format6_10
.first
|| ch
> cmap
->u
.format6_10
.last
) return 0;
1711 return glyphs
[ch
- cmap
->u
.format6_10
.first
];
1714 static unsigned int opentype_cmap_format6_10_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1715 DWRITE_UNICODE_RANGE
*ranges
)
1719 ranges
->first
= cmap
->u
.format6_10
.first
;
1720 ranges
->last
= cmap
->u
.format6_10
.last
;
1726 static int __cdecl
cmap_format12_13_compare_group(const void *a
, const void *b
)
1728 const unsigned int *ch
= a
;
1729 const UINT32
*group
= b
;
1731 if (*ch
> GET_BE_DWORD(group
[1]))
1734 if (*ch
< GET_BE_DWORD(group
[0]))
1740 static UINT16
opentype_cmap_format12_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1742 const UINT32
*groups
= cmap
->data
;
1743 const UINT32
*group_found
;
1745 if (!(group_found
= bsearch(&ch
, groups
, cmap
->u
.format12_13
.group_count
, 3 * sizeof(*groups
),
1746 cmap_format12_13_compare_group
)))
1749 return GET_BE_DWORD(group_found
[0]) <= GET_BE_DWORD(group_found
[1]) ?
1750 GET_BE_DWORD(group_found
[2]) + (ch
- GET_BE_DWORD(group_found
[0])) : 0;
1753 static unsigned int opentype_cmap_format12_13_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1754 DWRITE_UNICODE_RANGE
*ranges
)
1756 unsigned int i
, group_count
= cmap
->u
.format12_13
.group_count
;
1757 const UINT32
*groups
= cmap
->data
;
1759 count
= min(count
, group_count
);
1761 for (i
= 0; i
< count
; ++i
)
1763 ranges
[i
].first
= GET_BE_DWORD(groups
[3 * i
]);
1764 ranges
[i
].last
= GET_BE_DWORD(groups
[3 * i
+ 1]);
1770 static UINT16
opentype_cmap_format13_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1772 const UINT32
*groups
= cmap
->data
;
1773 const UINT32
*group_found
;
1775 if (!(group_found
= bsearch(&ch
, groups
, cmap
->u
.format12_13
.group_count
, 3 * sizeof(*groups
),
1776 cmap_format12_13_compare_group
)))
1779 return GET_BE_DWORD(group_found
[2]);
1782 static UINT16
opentype_cmap_dummy_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1787 static unsigned int opentype_cmap_dummy_get_ranges(const struct dwrite_cmap
*cmap
, unsigned int count
,
1788 DWRITE_UNICODE_RANGE
*ranges
)
1793 UINT16
opentype_cmap_get_glyph(const struct dwrite_cmap
*cmap
, unsigned int ch
)
1797 if (!cmap
->get_glyph
) return 0;
1798 glyph
= cmap
->get_glyph(cmap
, ch
);
1799 if (!glyph
&& cmap
->symbol
&& ch
<= 0xff)
1800 glyph
= cmap
->get_glyph(cmap
, ch
+ 0xf000);
1804 static int __cdecl
cmap_header_compare(const void *a
, const void *b
)
1806 const UINT16
*key
= a
;
1807 const UINT16
*record
= b
;
1810 if (key
[0] < GET_BE_WORD(record
[0])) return -1;
1811 if (key
[0] > GET_BE_WORD(record
[0])) return 1;
1813 if (key
[1] < GET_BE_WORD(record
[1])) return -1;
1814 if (key
[1] > GET_BE_WORD(record
[1])) return 1;
1819 void dwrite_cmap_init(struct dwrite_cmap
*cmap
, IDWriteFontFile
*file
, unsigned int face_index
,
1820 DWRITE_FONT_FACE_TYPE face_type
)
1822 static const UINT16 encodings
[][2] =
1824 { 3, 0 }, /* MS Symbol encoding is preferred. */
1834 const struct cmap_encoding_record
*records
, *found_record
= NULL
;
1835 unsigned int length
, offset
, format
, count
, f
, i
, num_records
;
1836 struct file_stream_desc stream_desc
;
1837 struct dwrite_fonttable table
;
1838 const UINT16
*pair
= NULL
;
1841 if (cmap
->data
) return;
1843 /* For fontface stream is already available and preset. */
1844 if (!cmap
->stream
&& FAILED(hr
= get_filestream_from_file(file
, &cmap
->stream
)))
1846 WARN("Failed to get file stream, hr %#lx.\n", hr
);
1850 stream_desc
.stream
= cmap
->stream
;
1851 stream_desc
.face_type
= face_type
;
1852 stream_desc
.face_index
= face_index
;
1854 opentype_get_font_table(&stream_desc
, MS_CMAP_TAG
, &table
);
1857 cmap
->table_context
= table
.context
;
1859 num_records
= table_read_be_word(&table
, 2);
1860 records
= table_read_ensure(&table
, 4, sizeof(*records
) * num_records
);
1862 for (i
= 0; i
< ARRAY_SIZE(encodings
); ++i
)
1864 pair
= encodings
[i
];
1865 if ((found_record
= bsearch(pair
, records
, num_records
, sizeof(*records
), cmap_header_compare
)))
1871 WARN("No suitable cmap table were found.\n");
1875 /* Symbol encoding. */
1876 cmap
->symbol
= pair
[0] == 3 && pair
[1] == 0;
1877 offset
= GET_BE_DWORD(found_record
->offset
);
1879 format
= table_read_be_word(&table
, offset
);
1884 cmap
->data
= table_read_ensure(&table
, offset
+ 6, 256);
1885 cmap
->get_glyph
= opentype_cmap_format0_get_glyph
;
1886 cmap
->get_ranges
= opentype_cmap_format0_get_ranges
;
1889 length
= table_read_be_word(&table
, offset
+ 2);
1890 cmap
->u
.format4
.seg_count
= count
= table_read_be_word(&table
, offset
+ 6) / 2;
1891 cmap
->u
.format4
.ends
= table_read_ensure(&table
, offset
+ 14, count
* 2);
1892 cmap
->u
.format4
.starts
= cmap
->u
.format4
.ends
+ count
+ 1;
1893 cmap
->u
.format4
.id_delta
= cmap
->u
.format4
.starts
+ count
;
1894 cmap
->u
.format4
.id_range_offset
= cmap
->u
.format4
.id_delta
+ count
;
1895 cmap
->u
.format4
.glyph_id_array
= cmap
->data
= cmap
->u
.format4
.id_range_offset
+ count
;
1896 cmap
->u
.format4
.glyph_id_array_len
= (length
- 16 - 8 * count
) / 2;
1897 cmap
->get_glyph
= opentype_cmap_format4_get_glyph
;
1898 cmap
->get_ranges
= opentype_cmap_format4_get_ranges
;
1902 /* Format 10 uses 4 byte fields. */
1903 f
= format
== 6 ? 1 : 2;
1904 cmap
->u
.format6_10
.first
= table_read_be_word(&table
, offset
+ f
* 6);
1905 count
= table_read_be_word(&table
, offset
+ f
* 8);
1906 cmap
->u
.format6_10
.last
= cmap
->u
.format6_10
.first
+ count
;
1907 cmap
->data
= table_read_ensure(&table
, offset
+ f
* 10, count
* 2);
1908 cmap
->get_glyph
= opentype_cmap_format6_10_get_glyph
;
1909 cmap
->get_ranges
= opentype_cmap_format6_10_get_ranges
;
1913 cmap
->u
.format12_13
.group_count
= count
= table_read_be_dword(&table
, offset
+ 12);
1914 cmap
->data
= table_read_ensure(&table
, offset
+ 16, count
* 3 * 4);
1915 cmap
->get_glyph
= format
== 12 ? opentype_cmap_format12_get_glyph
: opentype_cmap_format13_get_glyph
;
1916 cmap
->get_ranges
= opentype_cmap_format12_13_get_ranges
;
1919 WARN("Unhandled subtable format %u.\n", format
);
1926 /* Dummy implementation, returns 0 unconditionally. */
1928 cmap
->get_glyph
= opentype_cmap_dummy_get_glyph
;
1929 cmap
->get_ranges
= opentype_cmap_dummy_get_ranges
;
1933 void dwrite_cmap_release(struct dwrite_cmap
*cmap
)
1937 IDWriteFontFileStream_ReleaseFileFragment(cmap
->stream
, cmap
->table_context
);
1938 IDWriteFontFileStream_Release(cmap
->stream
);
1941 cmap
->stream
= NULL
;
1944 HRESULT
opentype_cmap_get_unicode_ranges(const struct dwrite_cmap
*cmap
, unsigned int max_count
, DWRITE_UNICODE_RANGE
*ranges
,
1945 unsigned int *count
)
1950 *count
= cmap
->get_ranges(cmap
, max_count
, ranges
);
1952 return *count
> max_count
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
1955 void opentype_get_font_typo_metrics(struct file_stream_desc
*stream_desc
, unsigned int *ascent
, unsigned int *descent
)
1957 struct dwrite_fonttable os2
;
1959 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
1961 *ascent
= *descent
= 0;
1963 if (os2
.size
>= FIELD_OFFSET(struct tt_os2
, sTypoLineGap
))
1965 SHORT value
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoDescender
));
1966 *ascent
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoAscender
));
1967 *descent
= value
< 0 ? -value
: 0;
1971 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
1974 void opentype_get_font_metrics(struct file_stream_desc
*stream_desc
, DWRITE_FONT_METRICS1
*metrics
, DWRITE_CARET_METRICS
*caret
)
1976 struct dwrite_fonttable os2
, head
, post
, hhea
;
1978 memset(metrics
, 0, sizeof(*metrics
));
1980 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
1981 opentype_get_font_table(stream_desc
, MS_HEAD_TAG
, &head
);
1982 opentype_get_font_table(stream_desc
, MS_POST_TAG
, &post
);
1983 opentype_get_font_table(stream_desc
, MS_HHEA_TAG
, &hhea
);
1987 metrics
->designUnitsPerEm
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, unitsPerEm
));
1988 metrics
->glyphBoxLeft
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, xMin
));
1989 metrics
->glyphBoxTop
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, yMax
));
1990 metrics
->glyphBoxRight
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, xMax
));
1991 metrics
->glyphBoxBottom
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, yMin
));
1998 caret
->slopeRise
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, caretSlopeRise
));
1999 caret
->slopeRun
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, caretSlopeRun
));
2000 caret
->offset
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, caretOffset
));
2003 memset(caret
, 0, sizeof(*caret
));
2008 USHORT version
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, version
));
2010 metrics
->ascent
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, usWinAscent
));
2011 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
2012 interpreted as large unsigned value. */
2013 metrics
->descent
= abs((SHORT
)table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, usWinDescent
)));
2015 /* Line gap is estimated using two sets of ascender/descender values and 'hhea' line gap. */
2018 SHORT descender
= (SHORT
)table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, descender
));
2021 linegap
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, ascender
)) + abs(descender
) +
2022 table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, linegap
)) - metrics
->ascent
- metrics
->descent
;
2023 metrics
->lineGap
= linegap
> 0 ? linegap
: 0;
2026 metrics
->strikethroughPosition
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, yStrikeoutPosition
));
2027 metrics
->strikethroughThickness
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, yStrikeoutSize
));
2028 metrics
->subscriptPositionX
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySubscriptXOffset
));
2029 /* Y offset is stored as positive offset below baseline */
2030 metrics
->subscriptPositionY
= -table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySubscriptYOffset
));
2031 metrics
->subscriptSizeX
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySubscriptXSize
));
2032 metrics
->subscriptSizeY
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySubscriptYSize
));
2033 metrics
->superscriptPositionX
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySuperscriptXOffset
));
2034 metrics
->superscriptPositionY
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySuperscriptYOffset
));
2035 metrics
->superscriptSizeX
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySuperscriptXSize
));
2036 metrics
->superscriptSizeY
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, ySuperscriptYSize
));
2038 /* version 2 fields */
2041 metrics
->capHeight
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sCapHeight
));
2042 metrics
->xHeight
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sxHeight
));
2045 if (table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, fsSelection
)) & OS2_FSSELECTION_USE_TYPO_METRICS
)
2047 SHORT descent
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoDescender
));
2048 metrics
->ascent
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoAscender
));
2049 metrics
->descent
= descent
< 0 ? -descent
: 0;
2050 metrics
->lineGap
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, sTypoLineGap
));
2051 metrics
->hasTypographicMetrics
= TRUE
;
2056 metrics
->strikethroughPosition
= metrics
->designUnitsPerEm
/ 3;
2059 metrics
->ascent
= table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, ascender
));
2060 metrics
->descent
= abs((SHORT
)table_read_be_word(&hhea
, FIELD_OFFSET(struct tt_hhea
, descender
)));
2066 metrics
->underlinePosition
= table_read_be_word(&post
, FIELD_OFFSET(struct tt_post
, underlinePosition
));
2067 metrics
->underlineThickness
= table_read_be_word(&post
, FIELD_OFFSET(struct tt_post
, underlineThickness
));
2070 if (metrics
->underlineThickness
== 0)
2071 metrics
->underlineThickness
= metrics
->designUnitsPerEm
/ 14;
2072 if (metrics
->strikethroughThickness
== 0)
2073 metrics
->strikethroughThickness
= metrics
->underlineThickness
;
2075 /* estimate missing metrics */
2076 if (metrics
->xHeight
== 0)
2077 metrics
->xHeight
= metrics
->designUnitsPerEm
/ 2;
2078 if (metrics
->capHeight
== 0)
2079 metrics
->capHeight
= metrics
->designUnitsPerEm
* 7 / 10;
2082 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
2084 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, head
.context
);
2086 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, post
.context
);
2088 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, hhea
.context
);
2091 void opentype_get_font_properties(const struct file_stream_desc
*stream_desc
, struct dwrite_font_props
*props
)
2093 struct dwrite_fonttable os2
, head
, post
, colr
, cpal
;
2094 BOOL is_symbol
, is_monospaced
;
2096 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
2097 opentype_get_font_table(stream_desc
, MS_HEAD_TAG
, &head
);
2099 memset(props
, 0, sizeof(*props
));
2101 /* Default stretch, weight and style to normal */
2102 props
->stretch
= DWRITE_FONT_STRETCH_NORMAL
;
2103 props
->weight
= DWRITE_FONT_WEIGHT_NORMAL
;
2104 props
->style
= DWRITE_FONT_STYLE_NORMAL
;
2106 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
2109 USHORT version
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, version
));
2110 USHORT fsSelection
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, fsSelection
));
2111 USHORT usWeightClass
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, usWeightClass
));
2112 USHORT usWidthClass
= table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, usWidthClass
));
2115 if (usWidthClass
> DWRITE_FONT_STRETCH_UNDEFINED
&& usWidthClass
<= DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
2116 props
->stretch
= usWidthClass
;
2118 if (usWeightClass
>= 1 && usWeightClass
<= 9)
2119 usWeightClass
*= 100;
2121 if (usWeightClass
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
2122 props
->weight
= DWRITE_FONT_WEIGHT_ULTRA_BLACK
;
2123 else if (usWeightClass
> 0)
2124 props
->weight
= usWeightClass
;
2126 if (version
>= 4 && (fsSelection
& OS2_FSSELECTION_OBLIQUE
))
2127 props
->style
= DWRITE_FONT_STYLE_OBLIQUE
;
2128 else if (fsSelection
& OS2_FSSELECTION_ITALIC
)
2129 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
2130 props
->lf
.lfItalic
= !!(fsSelection
& OS2_FSSELECTION_ITALIC
);
2132 if ((panose
= table_read_ensure(&os2
, FIELD_OFFSET(struct tt_os2
, panose
), sizeof(props
->panose
))))
2133 memcpy(&props
->panose
, panose
, sizeof(props
->panose
));
2136 props
->fontsig
.fsUsb
[0] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulUnicodeRange1
));
2137 props
->fontsig
.fsUsb
[1] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulUnicodeRange2
));
2138 props
->fontsig
.fsUsb
[2] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulUnicodeRange3
));
2139 props
->fontsig
.fsUsb
[3] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulUnicodeRange4
));
2143 props
->fontsig
.fsCsb
[0] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulCodePageRange1
));
2144 props
->fontsig
.fsCsb
[1] = table_read_be_dword(&os2
, FIELD_OFFSET(struct tt_os2
, ulCodePageRange2
));
2149 USHORT macStyle
= table_read_be_word(&head
, FIELD_OFFSET(struct tt_head
, macStyle
));
2151 if (macStyle
& TT_HEAD_MACSTYLE_CONDENSED
)
2152 props
->stretch
= DWRITE_FONT_STRETCH_CONDENSED
;
2153 else if (macStyle
& TT_HEAD_MACSTYLE_EXTENDED
)
2154 props
->stretch
= DWRITE_FONT_STRETCH_EXPANDED
;
2156 if (macStyle
& TT_HEAD_MACSTYLE_BOLD
)
2157 props
->weight
= DWRITE_FONT_WEIGHT_BOLD
;
2159 if (macStyle
& TT_HEAD_MACSTYLE_ITALIC
) {
2160 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
2161 props
->lf
.lfItalic
= 1;
2165 props
->lf
.lfWeight
= props
->weight
;
2167 /* FONT_IS_SYMBOL */
2168 if (!(is_symbol
= props
->panose
.familyKind
== DWRITE_PANOSE_FAMILY_SYMBOL
))
2170 struct dwrite_fonttable cmap
;
2171 int i
, offset
, num_tables
;
2173 opentype_get_font_table(stream_desc
, MS_CMAP_TAG
, &cmap
);
2177 num_tables
= table_read_be_word(&cmap
, FIELD_OFFSET(struct cmap_header
, num_tables
));
2178 offset
= FIELD_OFFSET(struct cmap_header
, tables
);
2180 for (i
= 0; !is_symbol
&& i
< num_tables
; ++i
)
2182 WORD platform
, encoding
;
2184 platform
= table_read_be_word(&cmap
, offset
+ i
* sizeof(struct cmap_encoding_record
) +
2185 FIELD_OFFSET(struct cmap_encoding_record
, platformID
));
2186 encoding
= table_read_be_word(&cmap
, offset
+ i
* sizeof(struct cmap_encoding_record
) +
2187 FIELD_OFFSET(struct cmap_encoding_record
, encodingID
));
2189 is_symbol
= platform
== OPENTYPE_CMAP_TABLE_PLATFORM_WIN
&&
2190 encoding
== OPENTYPE_CMAP_TABLE_ENCODING_SYMBOL
;
2193 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, cmap
.context
);
2197 props
->flags
|= FONT_IS_SYMBOL
;
2199 /* FONT_IS_MONOSPACED, slant angle */
2200 opentype_get_font_table(stream_desc
, MS_POST_TAG
, &post
);
2201 is_monospaced
= props
->panose
.text
.proportion
== DWRITE_PANOSE_PROPORTION_MONOSPACED
;
2205 is_monospaced
= !!table_read_dword(&post
, FIELD_OFFSET(struct tt_post
, fixed_pitch
));
2206 props
->slant_angle
= table_read_be_fixed(&post
, FIELD_OFFSET(struct tt_post
, italicAngle
));
2209 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, post
.context
);
2212 props
->flags
|= FONT_IS_MONOSPACED
;
2214 /* FONT_IS_COLORED */
2215 opentype_get_font_table(stream_desc
, MS_COLR_TAG
, &colr
);
2218 opentype_get_font_table(stream_desc
, MS_CPAL_TAG
, &cpal
);
2221 props
->flags
|= FONT_IS_COLORED
;
2222 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, cpal
.context
);
2225 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, colr
.context
);
2228 TRACE("stretch %d, weight %d, style %d\n", props
->stretch
, props
->weight
, props
->style
);
2231 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
2233 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, head
.context
);
2236 static UINT
get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform
, USHORT encoding
)
2241 case OPENTYPE_PLATFORM_UNICODE
:
2243 case OPENTYPE_PLATFORM_MAC
:
2246 case TT_NAME_MAC_ENCODING_ROMAN
:
2249 case TT_NAME_MAC_ENCODING_JAPANESE
:
2252 case TT_NAME_MAC_ENCODING_TRAD_CHINESE
:
2255 case TT_NAME_MAC_ENCODING_KOREAN
:
2258 case TT_NAME_MAC_ENCODING_ARABIC
:
2261 case TT_NAME_MAC_ENCODING_HEBREW
:
2264 case TT_NAME_MAC_ENCODING_GREEK
:
2267 case TT_NAME_MAC_ENCODING_RUSSIAN
:
2270 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE
:
2273 case TT_NAME_MAC_ENCODING_THAI
:
2277 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
2281 case OPENTYPE_PLATFORM_WIN
:
2284 case TT_NAME_WINDOWS_ENCODING_SYMBOL
:
2285 case TT_NAME_WINDOWS_ENCODING_UNICODE_BMP
:
2286 case TT_NAME_WINDOWS_ENCODING_UNICODE_FULL
:
2288 case TT_NAME_WINDOWS_ENCODING_SJIS
:
2291 case TT_NAME_WINDOWS_ENCODING_PRC
:
2294 case TT_NAME_WINDOWS_ENCODING_BIG5
:
2297 case TT_NAME_WINDOWS_ENCODING_WANSUNG
:
2300 case TT_NAME_WINDOWS_ENCODING_JOHAB
:
2304 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
2309 FIXME("unknown platform %d\n", platform
);
2315 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform
, USHORT lang_id
, WCHAR
*locale
, USHORT locale_len
)
2319 case OPENTYPE_PLATFORM_MAC
:
2321 const char *locale_name
= NULL
;
2323 if (lang_id
> TT_NAME_MAC_LANGID_AZER_ROMAN
)
2324 WARN("invalid mac lang id %d\n", lang_id
);
2325 else if (!name_mac_langid_to_locale
[lang_id
][0])
2326 FIXME("failed to map mac lang id %d to locale name\n", lang_id
);
2328 locale_name
= name_mac_langid_to_locale
[lang_id
];
2331 MultiByteToWideChar(CP_ACP
, 0, name_mac_langid_to_locale
[lang_id
], -1, locale
, locale_len
);
2333 wcscpy(locale
, L
"en-US");
2336 case OPENTYPE_PLATFORM_WIN
:
2337 if (!LCIDToLocaleName(MAKELCID(lang_id
, SORT_DEFAULT
), locale
, locale_len
, 0))
2339 FIXME("failed to get locale name for lcid=0x%08lx\n", MAKELCID(lang_id
, SORT_DEFAULT
));
2340 wcscpy(locale
, L
"en-US");
2343 case OPENTYPE_PLATFORM_UNICODE
:
2344 wcscpy(locale
, L
"en-US");
2347 FIXME("unknown platform %d\n", platform
);
2351 static BOOL
opentype_is_english_namerecord(const struct dwrite_fonttable
*table
, unsigned int idx
)
2353 const struct name_header
*header
= (const struct name_header
*)table
->data
;
2354 const struct name_record
*record
;
2356 record
= &header
->records
[idx
];
2358 return GET_BE_WORD(record
->platformID
) == OPENTYPE_PLATFORM_MAC
&&
2359 GET_BE_WORD(record
->languageID
) == TT_NAME_MAC_LANGID_ENGLISH
;
2362 static BOOL
opentype_decode_namerecord(const struct dwrite_fonttable
*table
, unsigned int idx
,
2363 IDWriteLocalizedStrings
*strings
)
2365 USHORT lang_id
, length
, offset
, encoding
, platform
;
2366 const struct name_header
*header
= (const struct name_header
*)table
->data
;
2367 const struct name_record
*record
;
2368 unsigned int i
, string_offset
;
2372 string_offset
= table_read_be_word(table
, FIELD_OFFSET(struct name_header
, stringOffset
));
2374 record
= &header
->records
[idx
];
2376 platform
= GET_BE_WORD(record
->platformID
);
2377 lang_id
= GET_BE_WORD(record
->languageID
);
2378 length
= GET_BE_WORD(record
->length
);
2379 offset
= GET_BE_WORD(record
->offset
);
2380 encoding
= GET_BE_WORD(record
->encodingID
);
2382 if (!(name
= table_read_ensure(table
, string_offset
+ offset
, length
)))
2385 if (lang_id
< 0x8000)
2387 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
2391 codepage
= get_name_record_codepage(platform
, encoding
);
2392 get_name_record_locale(platform
, lang_id
, locale
, ARRAY_SIZE(locale
));
2396 DWORD len
= MultiByteToWideChar(codepage
, 0, name
, length
, NULL
, 0);
2397 name_string
= malloc(sizeof(WCHAR
) * (len
+1));
2398 MultiByteToWideChar(codepage
, 0, name
, length
, name_string
, len
);
2399 name_string
[len
] = 0;
2403 length
/= sizeof(WCHAR
);
2404 name_string
= heap_strdupnW(name
, length
);
2405 for (i
= 0; i
< length
; i
++)
2406 name_string
[i
] = GET_BE_WORD(name_string
[i
]);
2409 TRACE("string %s for locale %s found\n", debugstr_w(name_string
), debugstr_w(locale
));
2410 add_localizedstring(strings
, locale
, name_string
);
2413 ret
= !wcscmp(locale
, L
"en-US");
2416 FIXME("handle NAME format 1\n");
2421 static HRESULT
opentype_get_font_strings_from_id(const struct dwrite_fonttable
*table
, enum OPENTYPE_STRING_ID id
,
2422 IDWriteLocalizedStrings
**strings
)
2424 int i
, count
, candidate_mac
, candidate_mac_en
, candidate_unicode
;
2425 const struct name_record
*records
;
2433 if (FAILED(hr
= create_localizedstrings(strings
)))
2436 format
= table_read_be_word(table
, FIELD_OFFSET(struct name_header
, format
));
2438 if (format
!= 0 && format
!= 1)
2439 FIXME("unsupported NAME format %d\n", format
);
2441 count
= table_read_be_word(table
, FIELD_OFFSET(struct name_header
, count
));
2443 if (!(records
= table_read_ensure(table
, FIELD_OFFSET(struct name_header
, records
),
2444 count
* sizeof(struct name_record
))))
2449 has_english
= FALSE
;
2450 candidate_unicode
= candidate_mac
= candidate_mac_en
= -1;
2452 for (i
= 0; i
< count
; i
++)
2454 unsigned short platform
;
2456 if (GET_BE_WORD(records
[i
].nameID
) != id
)
2459 platform
= GET_BE_WORD(records
[i
].platformID
);
2462 /* Skip Unicode or Mac entries for now, fonts tend to duplicate those
2463 strings as WIN platform entries. If font does not have WIN entry for
2464 this id, we will use Mac or Unicode platform entry while assuming
2466 case OPENTYPE_PLATFORM_UNICODE
:
2467 if (candidate_unicode
== -1)
2468 candidate_unicode
= i
;
2470 case OPENTYPE_PLATFORM_MAC
:
2471 if (candidate_mac
== -1)
2473 if (candidate_mac_en
== -1 && opentype_is_english_namerecord(table
, i
))
2474 candidate_mac_en
= i
;
2476 case OPENTYPE_PLATFORM_WIN
:
2477 has_english
|= opentype_decode_namerecord(table
, i
, *strings
);
2480 FIXME("platform %i not supported\n", platform
);
2485 if (!get_localizedstrings_count(*strings
) && candidate_mac
!= -1)
2486 has_english
|= opentype_decode_namerecord(table
, candidate_mac
, *strings
);
2487 if (!get_localizedstrings_count(*strings
) && candidate_unicode
!= -1)
2488 has_english
|= opentype_decode_namerecord(table
, candidate_unicode
, *strings
);
2489 if (!has_english
&& candidate_mac_en
!= -1)
2490 opentype_decode_namerecord(table
, candidate_mac_en
, *strings
);
2492 if (!get_localizedstrings_count(*strings
))
2494 IDWriteLocalizedStrings_Release(*strings
);
2499 sort_localizedstrings(*strings
);
2501 return *strings
? S_OK
: E_FAIL
;
2504 static WCHAR
*meta_get_lng_name(WCHAR
*str
, WCHAR
**ctx
)
2508 if (!str
) str
= *ctx
;
2509 while (*str
&& wcschr(L
", ", *str
)) str
++;
2510 if (!*str
) return NULL
;
2512 while (*str
&& !wcschr(L
", ", *str
)) str
++;
2513 if (*str
) *str
++ = 0;
2519 static HRESULT
opentype_get_font_strings_from_meta(const struct file_stream_desc
*stream_desc
,
2520 DWRITE_INFORMATIONAL_STRING_ID id
, IDWriteLocalizedStrings
**ret
)
2522 const struct meta_data_map
*maps
;
2523 IDWriteLocalizedStrings
*strings
;
2524 struct dwrite_fonttable meta
;
2525 DWORD version
, i
, count
, tag
;
2532 case DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG
:
2535 case DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
:
2539 WARN("Unexpected id %d.\n", id
);
2543 if (FAILED(hr
= create_localizedstrings(&strings
)))
2546 opentype_get_font_table(stream_desc
, MS_META_TAG
, &meta
);
2550 version
= table_read_be_dword(&meta
, 0);
2553 WARN("Unexpected meta table version %ld.\n", version
);
2557 count
= table_read_be_dword(&meta
, FIELD_OFFSET(struct meta_header
, data_maps_count
));
2558 if (!(maps
= table_read_ensure(&meta
, FIELD_OFFSET(struct meta_header
, maps
),
2559 count
* sizeof(struct meta_data_map
))))
2562 for (i
= 0; i
< count
; ++i
)
2566 if (maps
[i
].tag
== tag
&& maps
[i
].length
)
2568 DWORD length
= GET_BE_DWORD(maps
[i
].length
), j
;
2570 if ((data
= table_read_ensure(&meta
, GET_BE_DWORD(maps
[i
].offset
), length
)))
2572 WCHAR
*ptrW
, *ctx
, *token
;
2574 if (!(ptrW
= malloc((length
+ 1) * sizeof(WCHAR
))))
2580 /* Data is stored in comma separated list, ASCII range only. */
2581 for (j
= 0; j
< length
; ++j
)
2585 token
= meta_get_lng_name(ptrW
, &ctx
);
2589 add_localizedstring(strings
, L
"", token
);
2590 token
= meta_get_lng_name(NULL
, &ctx
);
2598 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, meta
.context
);
2601 if (IDWriteLocalizedStrings_GetCount(strings
))
2604 IDWriteLocalizedStrings_Release(strings
);
2609 HRESULT
opentype_get_font_info_strings(const struct file_stream_desc
*stream_desc
, DWRITE_INFORMATIONAL_STRING_ID id
,
2610 IDWriteLocalizedStrings
**strings
)
2612 struct dwrite_fonttable name
;
2616 case DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG
:
2617 case DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
:
2618 opentype_get_font_strings_from_meta(stream_desc
, id
, strings
);
2621 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name
);
2622 opentype_get_font_strings_from_id(&name
, dwriteid_to_opentypeid
[id
], strings
);
2624 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name
.context
);
2630 HRESULT
opentype_get_font_familyname(const struct file_stream_desc
*stream_desc
, DWRITE_FONT_FAMILY_MODEL family_model
,
2631 IDWriteLocalizedStrings
**names
)
2633 static const unsigned int wws_candidates
[] =
2635 OPENTYPE_STRING_WWS_FAMILY_NAME
,
2636 OPENTYPE_STRING_TYPOGRAPHIC_FAMILY_NAME
,
2637 OPENTYPE_STRING_FAMILY_NAME
,
2640 static const unsigned int typographic_candidates
[] =
2642 OPENTYPE_STRING_TYPOGRAPHIC_FAMILY_NAME
,
2643 OPENTYPE_STRING_WWS_FAMILY_NAME
,
2644 OPENTYPE_STRING_FAMILY_NAME
,
2647 struct dwrite_fonttable os2
, name
;
2648 const unsigned int *id
;
2652 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
2653 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name
);
2657 if (family_model
== DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC
)
2659 id
= typographic_candidates
;
2663 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
2664 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
2666 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
2667 /* If Preferred Family doesn't conform to WWS model try WWS name. */
2668 try_wws_name
= os2
.data
&& !(table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, fsSelection
)) & OS2_FSSELECTION_WWS
);
2670 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
2672 id
= wws_candidates
;
2673 if (!try_wws_name
) id
++;
2678 if (SUCCEEDED(hr
= opentype_get_font_strings_from_id(&name
, *id
, names
)))
2684 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name
.context
);
2689 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
2690 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
2691 HRESULT
opentype_get_font_facename(struct file_stream_desc
*stream_desc
, WCHAR
*lfname
, IDWriteLocalizedStrings
**names
)
2693 struct dwrite_fonttable os2
, name
;
2694 IDWriteLocalizedStrings
*lfnames
;
2698 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, &os2
);
2699 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name
);
2703 /* if Preferred Family doesn't conform to WWS model try WWS name */
2704 fsselection
= os2
.data
? table_read_be_word(&os2
, FIELD_OFFSET(struct tt_os2
, fsSelection
)) : 0;
2705 if (os2
.data
&& !(fsselection
& OS2_FSSELECTION_WWS
))
2706 hr
= opentype_get_font_strings_from_id(&name
, OPENTYPE_STRING_WWS_SUBFAMILY_NAME
, names
);
2711 hr
= opentype_get_font_strings_from_id(&name
, OPENTYPE_STRING_TYPOGRAPHIC_SUBFAMILY_NAME
, names
);
2713 hr
= opentype_get_font_strings_from_id(&name
, OPENTYPE_STRING_SUBFAMILY_NAME
, names
);
2715 /* User locale is preferred, with fallback to en-us. */
2717 if (SUCCEEDED(opentype_get_font_strings_from_id(&name
, OPENTYPE_STRING_FAMILY_NAME
, &lfnames
)))
2719 WCHAR localeW
[LOCALE_NAME_MAX_LENGTH
];
2724 if (GetSystemDefaultLocaleName(localeW
, ARRAY_SIZE(localeW
)))
2725 IDWriteLocalizedStrings_FindLocaleName(lfnames
, localeW
, &index
, &exists
);
2728 IDWriteLocalizedStrings_FindLocaleName(lfnames
, L
"en-us", &index
, &exists
);
2734 IDWriteLocalizedStrings_GetStringLength(lfnames
, index
, &length
);
2735 nameW
= malloc((length
+ 1) * sizeof(WCHAR
));
2739 IDWriteLocalizedStrings_GetString(lfnames
, index
, nameW
, length
+ 1);
2740 lstrcpynW(lfname
, nameW
, LF_FACESIZE
);
2745 IDWriteLocalizedStrings_Release(lfnames
);
2749 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2
.context
);
2751 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name
.context
);
2756 static const struct ot_langsys
*opentype_get_langsys(const struct ot_gsubgpos_table
*table
, unsigned int script_index
,
2757 unsigned int language_index
, unsigned int *feature_count
)
2759 unsigned int table_offset
, langsys_offset
;
2760 const struct ot_langsys
*langsys
= NULL
;
2764 if (!table
->table
.data
|| script_index
== ~0u)
2767 /* ScriptTable offset. */
2768 table_offset
= table_read_be_word(&table
->table
, table
->script_list
+ FIELD_OFFSET(struct ot_script_list
, scripts
) +
2769 script_index
* sizeof(struct ot_script_record
) + FIELD_OFFSET(struct ot_script_record
, script
));
2773 if (language_index
== ~0u)
2774 langsys_offset
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
);
2776 langsys_offset
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
+
2777 FIELD_OFFSET(struct ot_script
, langsys
) + language_index
* sizeof(struct ot_langsys_record
) +
2778 FIELD_OFFSET(struct ot_langsys_record
, langsys
));
2779 langsys_offset
+= table
->script_list
+ table_offset
;
2781 *feature_count
= table_read_be_word(&table
->table
, langsys_offset
+ FIELD_OFFSET(struct ot_langsys
, feature_count
));
2783 langsys
= table_read_ensure(&table
->table
, langsys_offset
, FIELD_OFFSET(struct ot_langsys
, feature_index
[*feature_count
]));
2790 void opentype_get_typographic_features(struct ot_gsubgpos_table
*table
, unsigned int script_index
,
2791 unsigned int language_index
, struct tag_array
*t
)
2793 unsigned int i
, total_feature_count
, script_feature_count
;
2794 const struct ot_feature_list
*feature_list
;
2795 const struct ot_langsys
*langsys
= NULL
;
2797 langsys
= opentype_get_langsys(table
, script_index
, language_index
, &script_feature_count
);
2799 total_feature_count
= table_read_be_word(&table
->table
, table
->feature_list
);
2800 if (!total_feature_count
)
2803 feature_list
= table_read_ensure(&table
->table
, table
->feature_list
,
2804 FIELD_OFFSET(struct ot_feature_list
, features
[total_feature_count
]));
2808 for (i
= 0; i
< script_feature_count
; ++i
)
2810 unsigned int feature_index
= GET_BE_WORD(langsys
->feature_index
[i
]);
2811 if (feature_index
>= total_feature_count
)
2814 if (!dwrite_array_reserve((void **)&t
->tags
, &t
->capacity
, t
->count
+ 1, sizeof(*t
->tags
)))
2817 t
->tags
[t
->count
++] = feature_list
->features
[feature_index
].tag
;
2821 static unsigned int find_vdmx_group(const struct vdmx_header
*hdr
)
2824 const struct vdmx_ratio
*ratios
= (struct vdmx_ratio
*)(hdr
+ 1);
2825 BYTE dev_x_ratio
= 1, dev_y_ratio
= 1;
2826 unsigned int group_offset
= 0;
2828 num_ratios
= GET_BE_WORD(hdr
->num_ratios
);
2830 for (i
= 0; i
< num_ratios
; i
++) {
2832 if (!ratios
[i
].bCharSet
) continue;
2834 if ((ratios
[i
].xRatio
== 0 && ratios
[i
].yStartRatio
== 0 &&
2835 ratios
[i
].yEndRatio
== 0) ||
2836 (ratios
[i
].xRatio
== dev_x_ratio
&& ratios
[i
].yStartRatio
<= dev_y_ratio
&&
2837 ratios
[i
].yEndRatio
>= dev_y_ratio
))
2839 group_offset
= GET_BE_WORD(*((WORD
*)(ratios
+ num_ratios
) + i
));
2844 return group_offset
;
2847 BOOL
opentype_get_vdmx_size(const struct dwrite_fonttable
*vdmx
, INT emsize
, UINT16
*ascent
, UINT16
*descent
)
2849 unsigned int num_ratios
, num_recs
, group_offset
, i
;
2850 const struct vdmx_header
*header
;
2851 const struct vdmx_group
*group
;
2856 num_ratios
= table_read_be_word(vdmx
, FIELD_OFFSET(struct vdmx_header
, num_ratios
));
2857 num_recs
= table_read_be_word(vdmx
, FIELD_OFFSET(struct vdmx_header
, num_recs
));
2859 header
= table_read_ensure(vdmx
, 0, sizeof(*header
) + num_ratios
* sizeof(struct vdmx_ratio
) +
2860 num_recs
* sizeof(*group
));
2865 group_offset
= find_vdmx_group(header
);
2869 num_recs
= table_read_be_word(vdmx
, group_offset
);
2870 group
= table_read_ensure(vdmx
, group_offset
, FIELD_OFFSET(struct vdmx_group
, entries
[num_recs
]));
2875 if (emsize
< group
->startsz
|| emsize
>= group
->endsz
)
2878 for (i
= 0; i
< num_recs
; ++i
)
2880 WORD ppem
= GET_BE_WORD(group
->entries
[i
].yPelHeight
);
2881 if (ppem
> emsize
) {
2882 FIXME("interpolate %d\n", emsize
);
2886 if (ppem
== emsize
) {
2887 *ascent
= (SHORT
)GET_BE_WORD(group
->entries
[i
].yMax
);
2888 *descent
= -(SHORT
)GET_BE_WORD(group
->entries
[i
].yMin
);
2896 unsigned int opentype_get_gasp_flags(const struct dwrite_fonttable
*gasp
, float emsize
)
2898 unsigned int version
, num_ranges
, i
;
2899 const struct gasp_header
*table
;
2905 num_ranges
= table_read_be_word(gasp
, FIELD_OFFSET(struct gasp_header
, num_ranges
));
2907 table
= table_read_ensure(gasp
, 0, FIELD_OFFSET(struct gasp_header
, ranges
[num_ranges
]));
2911 version
= GET_BE_WORD(table
->version
);
2914 ERR("Unsupported gasp table format version %u.\n", version
);
2918 for (i
= 0; i
< num_ranges
; ++i
)
2920 flags
= GET_BE_WORD(table
->ranges
[i
].flags
);
2921 if (emsize
<= GET_BE_WORD(table
->ranges
[i
].max_ppem
)) break;
2928 unsigned int opentype_get_cpal_palettecount(const struct dwrite_fonttable
*cpal
)
2930 return table_read_be_word(cpal
, FIELD_OFFSET(struct cpal_header_0
, num_palettes
));
2933 unsigned int opentype_get_cpal_paletteentrycount(const struct dwrite_fonttable
*cpal
)
2935 return table_read_be_word(cpal
, FIELD_OFFSET(struct cpal_header_0
, num_palette_entries
));
2938 HRESULT
opentype_get_cpal_entries(const struct dwrite_fonttable
*cpal
, unsigned int palette
,
2939 unsigned int first_entry_index
, unsigned int entry_count
, DWRITE_COLOR_F
*entries
)
2941 unsigned int num_palettes
, num_palette_entries
, i
;
2942 const struct cpal_color_record
*records
;
2943 const struct cpal_header_0
*header
;
2950 } *colors
= (void *)entries
;
2952 header
= table_read_ensure(cpal
, 0, sizeof(*header
));
2954 if (!cpal
->exists
|| !header
)
2955 return DWRITE_E_NOCOLOR
;
2957 num_palettes
= GET_BE_WORD(header
->num_palettes
);
2958 if (palette
>= num_palettes
)
2959 return DWRITE_E_NOCOLOR
;
2961 header
= table_read_ensure(cpal
, 0, FIELD_OFFSET(struct cpal_header_0
, color_record_indices
[palette
]));
2963 return DWRITE_E_NOCOLOR
;
2965 num_palette_entries
= GET_BE_WORD(header
->num_palette_entries
);
2966 if (first_entry_index
+ entry_count
> num_palette_entries
)
2967 return E_INVALIDARG
;
2969 records
= table_read_ensure(cpal
, GET_BE_DWORD(header
->offset_first_color_record
),
2970 sizeof(*records
) * GET_BE_WORD(header
->num_color_records
));
2972 return DWRITE_E_NOCOLOR
;
2974 first_entry_index
+= GET_BE_WORD(header
->color_record_indices
[palette
]);
2976 for (i
= 0; i
< entry_count
; ++i
)
2978 colors
[i
].r
= records
[first_entry_index
+ i
].red
/ 255.0f
;
2979 colors
[i
].g
= records
[first_entry_index
+ i
].green
/ 255.0f
;
2980 colors
[i
].b
= records
[first_entry_index
+ i
].blue
/ 255.0f
;
2981 colors
[i
].a
= records
[first_entry_index
+ i
].alpha
/ 255.0f
;
2987 static int __cdecl
colr_compare_gid(const void *g
, const void *r
)
2989 const struct colr_baseglyph_record
*record
= r
;
2990 UINT16 glyph
= *(UINT16
*)g
, GID
= GET_BE_WORD(record
->glyph
);
2995 else if (glyph
< GID
)
3001 HRESULT
opentype_get_colr_glyph(const struct dwrite_fonttable
*colr
, UINT16 glyph
, struct dwrite_colorglyph
*ret
)
3003 unsigned int num_baseglyph_records
, offset_baseglyph_records
;
3004 const struct colr_baseglyph_record
*record
;
3005 const struct colr_layer_record
*layer
;
3006 const struct colr_header
*header
;
3008 memset(ret
, 0, sizeof(*ret
));
3010 ret
->palette_index
= 0xffff;
3012 header
= table_read_ensure(colr
, 0, sizeof(*header
));
3016 num_baseglyph_records
= GET_BE_WORD(header
->num_baseglyph_records
);
3017 offset_baseglyph_records
= GET_BE_DWORD(header
->offset_baseglyph_records
);
3018 if (!table_read_ensure(colr
, offset_baseglyph_records
, num_baseglyph_records
* sizeof(*record
)))
3023 record
= bsearch(&glyph
, colr
->data
+ offset_baseglyph_records
, num_baseglyph_records
,
3024 sizeof(*record
), colr_compare_gid
);
3028 ret
->first_layer
= GET_BE_WORD(record
->first_layer_index
);
3029 ret
->num_layers
= GET_BE_WORD(record
->num_layers
);
3031 if ((layer
= table_read_ensure(colr
, GET_BE_DWORD(header
->offset_layer_records
),
3032 (ret
->first_layer
+ ret
->layer
) * sizeof(*layer
))))
3034 layer
+= ret
->first_layer
+ ret
->layer
;
3035 ret
->glyph
= GET_BE_WORD(layer
->glyph
);
3036 ret
->palette_index
= GET_BE_WORD(layer
->palette_index
);
3042 void opentype_colr_next_glyph(const struct dwrite_fonttable
*colr
, struct dwrite_colorglyph
*glyph
)
3044 const struct colr_layer_record
*layer
;
3045 const struct colr_header
*header
;
3047 /* iterated all the way through */
3048 if (glyph
->layer
== glyph
->num_layers
)
3051 if (!(header
= table_read_ensure(colr
, 0, sizeof(*header
))))
3056 if ((layer
= table_read_ensure(colr
, GET_BE_DWORD(header
->offset_layer_records
),
3057 (glyph
->first_layer
+ glyph
->layer
) * sizeof(*layer
))))
3059 layer
+= glyph
->first_layer
+ glyph
->layer
;
3060 glyph
->glyph
= GET_BE_WORD(layer
->glyph
);
3061 glyph
->palette_index
= GET_BE_WORD(layer
->palette_index
);
3065 static BOOL
opentype_has_font_table(IDWriteFontFace5
*fontface
, UINT32 tag
)
3067 BOOL exists
= FALSE
;
3073 hr
= IDWriteFontFace5_TryGetFontTable(fontface
, tag
, &data
, &size
, &context
, &exists
);
3078 IDWriteFontFace5_ReleaseFontTable(fontface
, context
);
3083 static unsigned int opentype_get_sbix_formats(IDWriteFontFace5
*fontface
)
3085 unsigned int num_strikes
, num_glyphs
, i
, j
, ret
= 0;
3086 const struct sbix_header
*sbix_header
;
3087 struct dwrite_fonttable table
;
3089 memset(&table
, 0, sizeof(table
));
3090 table
.exists
= TRUE
;
3092 if (!get_fontface_table(fontface
, MS_MAXP_TAG
, &table
))
3095 num_glyphs
= table_read_be_word(&table
, FIELD_OFFSET(struct maxp
, num_glyphs
));
3097 IDWriteFontFace5_ReleaseFontTable(fontface
, table
.context
);
3099 memset(&table
, 0, sizeof(table
));
3100 table
.exists
= TRUE
;
3102 if (!get_fontface_table(fontface
, MS_SBIX_TAG
, &table
))
3105 num_strikes
= table_read_be_dword(&table
, FIELD_OFFSET(struct sbix_header
, num_strikes
));
3106 sbix_header
= table_read_ensure(&table
, 0, FIELD_OFFSET(struct sbix_header
, strike_offset
[num_strikes
]));
3110 for (i
= 0; i
< num_strikes
; ++i
)
3112 unsigned int strike_offset
= GET_BE_DWORD(sbix_header
->strike_offset
[i
]);
3113 const struct sbix_strike
*strike
= table_read_ensure(&table
, strike_offset
,
3114 FIELD_OFFSET(struct sbix_strike
, glyphdata_offsets
[num_glyphs
+ 1]));
3119 for (j
= 0; j
< num_glyphs
; j
++)
3121 unsigned int offset
= GET_BE_DWORD(strike
->glyphdata_offsets
[j
]);
3122 unsigned int next_offset
= GET_BE_DWORD(strike
->glyphdata_offsets
[j
+ 1]);
3123 const struct sbix_glyph_data
*glyph_data
;
3125 if (offset
== next_offset
)
3128 glyph_data
= table_read_ensure(&table
, strike_offset
+ offset
, sizeof(*glyph_data
));
3132 switch (glyph_data
->graphic_type
)
3135 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_PNG
;
3138 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_JPEG
;
3141 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_TIFF
;
3144 FIXME("unexpected bitmap format %s\n", debugstr_tag(GET_BE_DWORD(glyph_data
->graphic_type
)));
3150 IDWriteFontFace5_ReleaseFontTable(fontface
, table
.context
);
3155 static unsigned int opentype_get_cblc_formats(IDWriteFontFace5
*fontface
)
3157 const unsigned int format_mask
= DWRITE_GLYPH_IMAGE_FORMATS_PNG
|
3158 DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8
;
3159 const struct cblc_bitmapsize_table
*sizes
;
3160 struct dwrite_fonttable cblc
= { 0 };
3161 unsigned int num_sizes
, i
, ret
= 0;
3162 const struct cblc_header
*header
;
3165 if (!get_fontface_table(fontface
, MS_CBLC_TAG
, &cblc
))
3168 num_sizes
= table_read_be_dword(&cblc
, FIELD_OFFSET(struct cblc_header
, num_sizes
));
3169 sizes
= table_read_ensure(&cblc
, sizeof(*header
), num_sizes
* sizeof(*sizes
));
3173 for (i
= 0; i
< num_sizes
; ++i
)
3175 BYTE bpp
= sizes
[i
].bit_depth
;
3177 if ((ret
& format_mask
) == format_mask
)
3180 if (bpp
== 1 || bpp
== 2 || bpp
== 4 || bpp
== 8)
3181 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_PNG
;
3183 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8
;
3187 IDWriteFontFace5_ReleaseFontTable(fontface
, cblc
.context
);
3192 UINT32
opentype_get_glyph_image_formats(IDWriteFontFace5
*fontface
)
3194 UINT32 ret
= DWRITE_GLYPH_IMAGE_FORMATS_NONE
;
3196 if (opentype_has_font_table(fontface
, MS_GLYF_TAG
))
3197 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE
;
3199 if (opentype_has_font_table(fontface
, MS_CFF__TAG
) ||
3200 opentype_has_font_table(fontface
, MS_CFF2_TAG
))
3201 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_CFF
;
3203 if (opentype_has_font_table(fontface
, MS_COLR_TAG
))
3204 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_COLR
;
3206 if (opentype_has_font_table(fontface
, MS_SVG__TAG
))
3207 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_SVG
;
3209 if (opentype_has_font_table(fontface
, MS_SBIX_TAG
))
3210 ret
|= opentype_get_sbix_formats(fontface
);
3212 if (opentype_has_font_table(fontface
, MS_CBLC_TAG
))
3213 ret
|= opentype_get_cblc_formats(fontface
);
3218 DWRITE_CONTAINER_TYPE
opentype_analyze_container_type(void const *data
, UINT32 data_size
)
3222 if (data_size
< sizeof(DWORD
))
3223 return DWRITE_CONTAINER_TYPE_UNKNOWN
;
3225 /* Both WOFF and WOFF2 start with 4 bytes signature. */
3226 signature
= *(DWORD
*)data
;
3231 return DWRITE_CONTAINER_TYPE_WOFF
;
3233 return DWRITE_CONTAINER_TYPE_WOFF2
;
3235 return DWRITE_CONTAINER_TYPE_UNKNOWN
;
3239 void opentype_layout_scriptshaping_cache_init(struct scriptshaping_cache
*cache
)
3241 cache
->font
->grab_font_table(cache
->context
, MS_GSUB_TAG
, &cache
->gsub
.table
.data
, &cache
->gsub
.table
.size
,
3242 &cache
->gsub
.table
.context
);
3244 if (cache
->gsub
.table
.data
)
3246 cache
->gsub
.script_list
= table_read_be_word(&cache
->gsub
.table
, FIELD_OFFSET(struct gpos_gsub_header
, script_list
));
3247 cache
->gsub
.feature_list
= table_read_be_word(&cache
->gsub
.table
, FIELD_OFFSET(struct gpos_gsub_header
, feature_list
));
3248 cache
->gsub
.lookup_list
= table_read_be_word(&cache
->gsub
.table
, FIELD_OFFSET(struct gpos_gsub_header
, lookup_list
));
3251 cache
->font
->grab_font_table(cache
->context
, MS_GPOS_TAG
, &cache
->gpos
.table
.data
, &cache
->gpos
.table
.size
,
3252 &cache
->gpos
.table
.context
);
3254 if (cache
->gpos
.table
.data
)
3256 cache
->gpos
.script_list
= table_read_be_word(&cache
->gpos
.table
,
3257 FIELD_OFFSET(struct gpos_gsub_header
, script_list
));
3258 cache
->gpos
.feature_list
= table_read_be_word(&cache
->gpos
.table
,
3259 FIELD_OFFSET(struct gpos_gsub_header
, feature_list
));
3260 cache
->gpos
.lookup_list
= table_read_be_word(&cache
->gpos
.table
,
3261 FIELD_OFFSET(struct gpos_gsub_header
, lookup_list
));
3264 cache
->font
->grab_font_table(cache
->context
, MS_GDEF_TAG
, &cache
->gdef
.table
.data
, &cache
->gdef
.table
.size
,
3265 &cache
->gdef
.table
.context
);
3267 if (cache
->gdef
.table
.data
)
3269 unsigned int version
= table_read_be_dword(&cache
->gdef
.table
, 0);
3271 cache
->gdef
.classdef
= table_read_be_word(&cache
->gdef
.table
, FIELD_OFFSET(struct gdef_header
, classdef
));
3272 cache
->gdef
.markattachclassdef
= table_read_be_word(&cache
->gdef
.table
,
3273 FIELD_OFFSET(struct gdef_header
, markattach_classdef
));
3274 if (version
>= 0x00010002)
3275 cache
->gdef
.markglyphsetdef
= table_read_be_word(&cache
->gdef
.table
,
3276 FIELD_OFFSET(struct gdef_header
, markglyphsetdef
));
3280 unsigned int opentype_layout_find_script(const struct scriptshaping_cache
*cache
, unsigned int kind
, DWORD script
,
3281 unsigned int *script_index
)
3283 const struct ot_gsubgpos_table
*table
= kind
== MS_GSUB_TAG
? &cache
->gsub
: &cache
->gpos
;
3284 UINT16 script_count
;
3287 *script_index
= ~0u;
3289 script_count
= table_read_be_word(&table
->table
, table
->script_list
);
3293 for (i
= 0; i
< script_count
; i
++)
3295 unsigned int tag
= table_read_dword(&table
->table
, table
->script_list
+ FIELD_OFFSET(struct ot_script_list
, scripts
) +
3296 i
* sizeof(struct ot_script_record
));
3310 unsigned int opentype_layout_find_language(const struct scriptshaping_cache
*cache
, unsigned int kind
, DWORD language
,
3311 unsigned int script_index
, unsigned int *language_index
)
3313 const struct ot_gsubgpos_table
*table
= kind
== MS_GSUB_TAG
? &cache
->gsub
: &cache
->gpos
;
3314 UINT16 table_offset
, lang_count
;
3317 *language_index
= ~0u;
3319 table_offset
= table_read_be_word(&table
->table
, table
->script_list
+ FIELD_OFFSET(struct ot_script_list
, scripts
) +
3320 script_index
* sizeof(struct ot_script_record
) + FIELD_OFFSET(struct ot_script_record
, script
));
3324 lang_count
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
+
3325 FIELD_OFFSET(struct ot_script
, langsys_count
));
3326 for (i
= 0; i
< lang_count
; i
++)
3328 unsigned int tag
= table_read_dword(&table
->table
, table
->script_list
+ table_offset
+
3329 FIELD_OFFSET(struct ot_script
, langsys
) + i
* sizeof(struct ot_langsys_record
));
3331 if (tag
== language
)
3333 *language_index
= i
;
3338 /* Try 'defaultLangSys' if it's set. */
3339 if (table_read_be_word(&table
->table
, table
->script_list
+ table_offset
))
3345 static int __cdecl
gdef_class_compare_format2(const void *g
, const void *r
)
3347 const struct ot_gdef_class_range
*range
= r
;
3348 UINT16 glyph
= *(UINT16
*)g
;
3350 if (glyph
< GET_BE_WORD(range
->start_glyph
))
3352 else if (glyph
> GET_BE_WORD(range
->end_glyph
))
3358 static unsigned int opentype_layout_get_glyph_class(const struct dwrite_fonttable
*table
,
3359 unsigned int offset
, UINT16 glyph
)
3361 WORD format
= table_read_be_word(table
, offset
), count
;
3362 unsigned int glyph_class
= GDEF_CLASS_UNCLASSIFIED
;
3366 const struct ot_gdef_classdef_format1
*format1
;
3368 count
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gdef_classdef_format1
, glyph_count
));
3369 format1
= table_read_ensure(table
, offset
, FIELD_OFFSET(struct ot_gdef_classdef_format1
, classes
[count
]));
3372 WORD start_glyph
= GET_BE_WORD(format1
->start_glyph
);
3373 if (glyph
>= start_glyph
&& (glyph
- start_glyph
) < count
)
3375 glyph_class
= GET_BE_WORD(format1
->classes
[glyph
- start_glyph
]);
3376 if (glyph_class
> GDEF_CLASS_MAX
)
3377 glyph_class
= GDEF_CLASS_UNCLASSIFIED
;
3381 else if (format
== 2)
3383 const struct ot_gdef_classdef_format2
*format2
;
3385 count
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gdef_classdef_format2
, range_count
));
3386 format2
= table_read_ensure(table
, offset
, FIELD_OFFSET(struct ot_gdef_classdef_format2
, ranges
[count
]));
3389 const struct ot_gdef_class_range
*range
= bsearch(&glyph
, format2
->ranges
, count
,
3390 sizeof(struct ot_gdef_class_range
), gdef_class_compare_format2
);
3391 glyph_class
= range
&& glyph
<= GET_BE_WORD(range
->end_glyph
) ?
3392 GET_BE_WORD(range
->glyph_class
) : GDEF_CLASS_UNCLASSIFIED
;
3393 if (glyph_class
> GDEF_CLASS_MAX
)
3394 glyph_class
= GDEF_CLASS_UNCLASSIFIED
;
3398 WARN("Unknown GDEF format %u.\n", format
);
3403 static unsigned int opentype_set_glyph_props(struct scriptshaping_context
*context
, unsigned int idx
)
3405 struct scriptshaping_cache
*cache
= context
->cache
;
3406 unsigned int glyph_class
= 0, props
;
3408 if (cache
->gdef
.classdef
)
3410 glyph_class
= opentype_layout_get_glyph_class(&cache
->gdef
.table
, cache
->gdef
.classdef
,
3411 context
->u
.buffer
.glyphs
[idx
]);
3414 switch (glyph_class
)
3416 case GDEF_CLASS_BASE
:
3417 props
= GLYPH_PROP_BASE
;
3419 case GDEF_CLASS_LIGATURE
:
3420 props
= GLYPH_PROP_LIGATURE
;
3422 case GDEF_CLASS_MARK
:
3423 props
= GLYPH_PROP_MARK
;
3424 if (cache
->gdef
.markattachclassdef
)
3426 glyph_class
= opentype_layout_get_glyph_class(&cache
->gdef
.table
, cache
->gdef
.markattachclassdef
,
3427 context
->u
.buffer
.glyphs
[idx
]);
3428 props
|= glyph_class
<< 8;
3435 context
->glyph_infos
[idx
].props
= props
;
3440 static void opentype_set_subst_glyph_props(struct scriptshaping_context
*context
, unsigned int idx
)
3442 unsigned int glyph_props
= opentype_set_glyph_props(context
, idx
) & LOOKUP_FLAG_IGNORE_MASK
;
3443 context
->u
.subst
.glyph_props
[idx
].isDiacritic
= !!(glyph_props
== GLYPH_PROP_MARK
);
3444 context
->u
.subst
.glyph_props
[idx
].isZeroWidthSpace
= !!(glyph_props
== GLYPH_PROP_MARK
);
3447 struct coverage_compare_format1_context
3450 const UINT16
*table_base
;
3451 unsigned int *coverage_index
;
3454 static int __cdecl
coverage_compare_format1(const void *left
, const void *right
)
3456 const struct coverage_compare_format1_context
*context
= left
;
3457 UINT16 glyph
= GET_BE_WORD(*(UINT16
*)right
);
3460 ret
= context
->glyph
- glyph
;
3462 *context
->coverage_index
= (UINT16
*)right
- context
->table_base
;
3467 static int __cdecl
coverage_compare_format2(const void *g
, const void *r
)
3469 const struct ot_coverage_range
*range
= r
;
3470 UINT16 glyph
= *(UINT16
*)g
;
3472 if (glyph
< GET_BE_WORD(range
->start_glyph
))
3474 else if (glyph
> GET_BE_WORD(range
->end_glyph
))
3480 static unsigned int opentype_layout_is_glyph_covered(const struct dwrite_fonttable
*table
, unsigned int coverage
,
3483 WORD format
= table_read_be_word(table
, coverage
), count
;
3485 count
= table_read_be_word(table
, coverage
+ 2);
3489 const struct ot_coverage_format1
*format1
= table_read_ensure(table
, coverage
,
3490 FIELD_OFFSET(struct ot_coverage_format1
, glyphs
[count
]));
3491 struct coverage_compare_format1_context context
;
3492 unsigned int coverage_index
= GLYPH_NOT_COVERED
;
3496 context
.glyph
= glyph
;
3497 context
.table_base
= format1
->glyphs
;
3498 context
.coverage_index
= &coverage_index
;
3500 bsearch(&context
, format1
->glyphs
, count
, sizeof(glyph
), coverage_compare_format1
);
3503 return coverage_index
;
3505 else if (format
== 2)
3507 const struct ot_coverage_format2
*format2
= table_read_ensure(table
, coverage
,
3508 FIELD_OFFSET(struct ot_coverage_format2
, ranges
[count
]));
3511 const struct ot_coverage_range
*range
= bsearch(&glyph
, format2
->ranges
, count
,
3512 sizeof(struct ot_coverage_range
), coverage_compare_format2
);
3513 return range
&& glyph
<= GET_BE_WORD(range
->end_glyph
) ?
3514 GET_BE_WORD(range
->startcoverage_index
) + glyph
- GET_BE_WORD(range
->start_glyph
) :
3519 WARN("Unknown coverage format %u.\n", format
);
3524 static inline unsigned int dwrite_popcount(unsigned int x
)
3526 #if defined(__MINGW32__)
3527 return __builtin_popcount(x
);
3529 x
-= x
>> 1 & 0x55555555;
3530 x
= (x
& 0x33333333) + (x
>> 2 & 0x33333333);
3531 return ((x
+ (x
>> 4)) & 0x0f0f0f0f) * 0x01010101 >> 24;
3535 static float opentype_scale_gpos_be_value(WORD value
, float emsize
, UINT16 upem
)
3537 return (short)GET_BE_WORD(value
) * emsize
/ upem
;
3540 static int opentype_layout_gpos_get_dev_value(const struct scriptshaping_context
*context
, unsigned int offset
)
3542 const struct dwrite_fonttable
*table
= &context
->table
->table
;
3543 unsigned int start_size
, end_size
, format
, value_word
;
3544 unsigned int index
, ppem
, mask
;
3550 start_size
= table_read_be_word(table
, offset
);
3551 end_size
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gpos_device_table
, end_size
));
3553 ppem
= context
->emsize
;
3554 if (ppem
< start_size
|| ppem
> end_size
)
3557 format
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gpos_device_table
, format
));
3559 if (format
< 1 || format
> 3)
3562 index
= ppem
- start_size
;
3564 value_word
= table_read_be_word(table
, offset
+ FIELD_OFFSET(struct ot_gpos_device_table
, values
[index
>> (4 - format
)]));
3565 mask
= 0xffff >> (16 - (1 << format
));
3567 value
= (value_word
>> ((index
% (4 - format
)) * (1 << format
))) & mask
;
3569 if ((unsigned int)value
>= ((mask
+ 1) >> 1))
3575 static void opentype_layout_apply_gpos_value(struct scriptshaping_context
*context
, unsigned int table_offset
,
3576 WORD value_format
, const WORD
*values
, unsigned int glyph
)
3578 const struct scriptshaping_cache
*cache
= context
->cache
;
3579 DWRITE_GLYPH_OFFSET
*offset
= &context
->offsets
[glyph
];
3580 float *advance
= &context
->advances
[glyph
];
3585 if (value_format
& GPOS_VALUE_X_PLACEMENT
)
3587 offset
->advanceOffset
+= opentype_scale_gpos_be_value(*values
, context
->emsize
, cache
->upem
);
3590 if (value_format
& GPOS_VALUE_Y_PLACEMENT
)
3592 offset
->ascenderOffset
+= opentype_scale_gpos_be_value(*values
, context
->emsize
, cache
->upem
);
3595 if (value_format
& GPOS_VALUE_X_ADVANCE
)
3597 *advance
+= opentype_scale_gpos_be_value(*values
, context
->emsize
, cache
->upem
);
3600 if (value_format
& GPOS_VALUE_Y_ADVANCE
)
3604 if (value_format
& GPOS_VALUE_X_PLACEMENT_DEVICE
)
3606 offset
->advanceOffset
+= opentype_layout_gpos_get_dev_value(context
, table_offset
+ GET_BE_WORD(*values
));
3609 if (value_format
& GPOS_VALUE_Y_PLACEMENT_DEVICE
)
3611 offset
->ascenderOffset
+= opentype_layout_gpos_get_dev_value(context
, table_offset
+ GET_BE_WORD(*values
));
3614 if (value_format
& GPOS_VALUE_X_ADVANCE_DEVICE
)
3616 *advance
+= opentype_layout_gpos_get_dev_value(context
, table_offset
+ GET_BE_WORD(*values
));
3619 if (value_format
& GPOS_VALUE_Y_ADVANCE_DEVICE
)
3627 unsigned short index
;
3628 unsigned short type
;
3629 unsigned short subtable_count
;
3633 unsigned int offset
;
3634 unsigned int auto_zwnj
: 1;
3635 unsigned int auto_zwj
: 1;
3638 static unsigned int opentype_layout_is_subst_context(const struct scriptshaping_context
*context
)
3640 return context
->table
== &context
->cache
->gsub
;
3643 static unsigned int opentype_layout_is_pos_context(const struct scriptshaping_context
*context
)
3645 return context
->table
== &context
->cache
->gpos
;
3648 static unsigned int opentype_layout_get_gsubgpos_subtable(const struct scriptshaping_context
*context
,
3649 const struct lookup
*lookup
, unsigned int subtable
, unsigned int *lookup_type
)
3651 unsigned int subtable_offset
= table_read_be_word(&context
->table
->table
, lookup
->offset
+
3652 FIELD_OFFSET(struct ot_lookup_table
, subtable
[subtable
]));
3653 const struct ot_gsubgpos_extension_format1
*format1
;
3655 subtable_offset
+= lookup
->offset
;
3657 if ((opentype_layout_is_subst_context(context
) && lookup
->type
!= GSUB_LOOKUP_EXTENSION_SUBST
) ||
3658 (opentype_layout_is_pos_context(context
) && lookup
->type
!= GPOS_LOOKUP_EXTENSION_POSITION
))
3660 *lookup_type
= lookup
->type
;
3661 return subtable_offset
;
3666 if (!(format1
= table_read_ensure(&context
->table
->table
, subtable_offset
, sizeof(*format1
))))
3669 if (GET_BE_WORD(format1
->format
) != 1)
3671 WARN("Unexpected extension table format %#x.\n", format1
->format
);
3675 *lookup_type
= GET_BE_WORD(format1
->lookup_type
);
3676 return subtable_offset
+ GET_BE_DWORD(format1
->extension_offset
);
3681 unsigned int offset
;
3682 unsigned int subtable_count
;
3688 /* First two to fit matching callback result. */
3694 struct match_context
;
3697 const struct match_context
*mc
;
3698 unsigned int subtable_offset
;
3701 typedef BOOL (*p_match_func
)(UINT16 glyph
, UINT16 glyph_data
, const struct match_data
*match_data
);
3703 struct match_context
3705 struct scriptshaping_context
*context
;
3706 unsigned int backtrack_offset
;
3707 unsigned int input_offset
;
3708 unsigned int lookahead_offset
;
3709 p_match_func match_func
;
3710 const struct lookup
*lookup
;
3713 struct glyph_iterator
3715 struct scriptshaping_context
*context
;
3720 p_match_func match_func
;
3721 const UINT16
*glyph_data
;
3722 const struct match_data
*match_data
;
3723 unsigned int ignore_zwnj
;
3724 unsigned int ignore_zwj
;
3727 static void glyph_iterator_init(struct scriptshaping_context
*context
, unsigned int flags
, unsigned int pos
,
3728 unsigned int len
, struct glyph_iterator
*iter
)
3730 iter
->context
= context
;
3731 iter
->flags
= flags
;
3735 iter
->match_func
= NULL
;
3736 iter
->match_data
= NULL
;
3737 iter
->glyph_data
= NULL
;
3738 /* Context matching iterators will get these fixed up. */
3739 iter
->ignore_zwnj
= !!opentype_layout_is_pos_context(context
);
3740 iter
->ignore_zwj
= context
->auto_zwj
;
3743 struct ot_gdef_mark_glyph_sets
3750 static BOOL
opentype_match_glyph_func(UINT16 glyph
, UINT16 glyph_data
, const struct match_data
*data
)
3752 return glyph
== glyph_data
;
3755 static BOOL
opentype_match_class_func(UINT16 glyph
, UINT16 glyph_data
, const struct match_data
*data
)
3757 const struct match_context
*mc
= data
->mc
;
3758 UINT16 glyph_class
= opentype_layout_get_glyph_class(&mc
->context
->table
->table
, data
->subtable_offset
, glyph
);
3759 return glyph_class
== glyph_data
;
3762 static BOOL
opentype_match_coverage_func(UINT16 glyph
, UINT16 glyph_data
, const struct match_data
*data
)
3764 const struct match_context
*mc
= data
->mc
;
3765 return opentype_layout_is_glyph_covered(&mc
->context
->table
->table
, data
->subtable_offset
+ glyph_data
, glyph
)
3766 != GLYPH_NOT_COVERED
;
3769 static BOOL
opentype_layout_mark_set_covers(const struct scriptshaping_cache
*cache
, unsigned int set_index
,
3772 unsigned int format
, offset
= cache
->gdef
.markglyphsetdef
, coverage_offset
, count
;
3777 format
= table_read_be_word(&cache
->gdef
.table
, offset
);
3781 count
= table_read_be_word(&cache
->gdef
.table
, offset
+ FIELD_OFFSET(struct ot_gdef_markglyphsets
, count
));
3782 if (!count
|| set_index
>= count
)
3785 coverage_offset
= table_read_be_dword(&cache
->gdef
.table
, offset
+
3786 FIELD_OFFSET(struct ot_gdef_markglyphsets
, offsets
[set_index
]));
3787 return opentype_layout_is_glyph_covered(&cache
->gdef
.table
, offset
+ coverage_offset
, glyph
) != GLYPH_NOT_COVERED
;
3790 WARN("Unexpected MarkGlyphSets format %#x.\n", format
);
3795 static BOOL
lookup_is_glyph_match(const struct scriptshaping_context
*context
, unsigned int idx
, unsigned int match_props
)
3797 unsigned int glyph_props
= context
->glyph_infos
[idx
].props
;
3798 UINT16 glyph
= context
->u
.buffer
.glyphs
[idx
];
3800 if (glyph_props
& match_props
& LOOKUP_FLAG_IGNORE_MASK
)
3803 if (!(glyph_props
& GLYPH_PROP_MARK
))
3806 if (match_props
& LOOKUP_FLAG_USE_MARK_FILTERING_SET
)
3807 return opentype_layout_mark_set_covers(context
->cache
, match_props
>> 16, glyph
);
3809 if (match_props
& LOOKUP_FLAG_MARK_ATTACHMENT_TYPE
)
3810 return (match_props
& LOOKUP_FLAG_MARK_ATTACHMENT_TYPE
) == (glyph_props
& LOOKUP_FLAG_MARK_ATTACHMENT_TYPE
);
3815 static enum iterator_match
glyph_iterator_may_skip(const struct glyph_iterator
*iter
)
3817 unsigned int glyph_props
= iter
->context
->glyph_infos
[iter
->pos
].props
& (GLYPH_PROP_IGNORABLE
| GLYPH_PROP_HIDDEN
);
3819 if (!lookup_is_glyph_match(iter
->context
, iter
->pos
, iter
->flags
))
3822 if (glyph_props
== GLYPH_PROP_IGNORABLE
&& !iter
->context
->u
.buffer
.glyph_props
[iter
->pos
].components
&&
3823 (iter
->ignore_zwnj
|| !(iter
->context
->glyph_infos
[iter
->pos
].props
& GLYPH_PROP_ZWNJ
)) &&
3824 (iter
->ignore_zwj
|| !(iter
->context
->glyph_infos
[iter
->pos
].props
& GLYPH_PROP_ZWJ
)))
3832 static enum iterator_match
glyph_iterator_may_match(const struct glyph_iterator
*iter
)
3834 if (!(iter
->mask
& iter
->context
->glyph_infos
[iter
->pos
].mask
))
3837 /* Glyph data is used for input, backtrack, and lookahead arrays, swap it here instead of doing that
3838 in all matching functions. */
3839 if (iter
->match_func
)
3840 return !!iter
->match_func(iter
->context
->u
.buffer
.glyphs
[iter
->pos
], GET_BE_WORD(*iter
->glyph_data
), iter
->match_data
);
3845 static BOOL
glyph_iterator_next(struct glyph_iterator
*iter
)
3847 enum iterator_match skip
, match
;
3849 while (iter
->pos
+ iter
->len
< iter
->context
->glyph_count
)
3853 skip
= glyph_iterator_may_skip(iter
);
3854 if (skip
== ITER_YES
)
3857 match
= glyph_iterator_may_match(iter
);
3858 if (match
== ITER_YES
|| (match
== ITER_MAYBE
&& skip
== ITER_NO
))
3861 if (iter
->glyph_data
)
3866 if (skip
== ITER_NO
)
3873 static BOOL
glyph_iterator_prev(struct glyph_iterator
*iter
)
3875 enum iterator_match skip
, match
;
3877 while (iter
->pos
> iter
->len
- 1)
3881 skip
= glyph_iterator_may_skip(iter
);
3882 if (skip
== ITER_YES
)
3885 match
= glyph_iterator_may_match(iter
);
3886 if (match
== ITER_YES
|| (match
== ITER_MAYBE
&& skip
== ITER_NO
))
3889 if (iter
->glyph_data
)
3894 if (skip
== ITER_NO
)
3901 static BOOL
opentype_layout_apply_gpos_single_adjustment(struct scriptshaping_context
*context
,
3902 const struct lookup
*lookup
, unsigned int subtable_offset
)
3904 const struct dwrite_fonttable
*table
= &context
->table
->table
;
3905 UINT16 format
, value_format
, value_len
, coverage
, glyph
;
3907 unsigned int coverage_index
;
3909 format
= table_read_be_word(table
, subtable_offset
);
3911 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_singlepos_format1
, coverage
));
3912 value_format
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_singlepos_format1
, value_format
));
3913 value_len
= dwrite_popcount(value_format
);
3915 glyph
= context
->u
.pos
.glyphs
[context
->cur
];
3919 const struct ot_gpos_singlepos_format1
*format1
= table_read_ensure(table
, subtable_offset
,
3920 FIELD_OFFSET(struct ot_gpos_singlepos_format1
, value
[value_len
]));
3922 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
3923 if (coverage_index
== GLYPH_NOT_COVERED
)
3926 opentype_layout_apply_gpos_value(context
, subtable_offset
, value_format
, format1
->value
, context
->cur
);
3928 else if (format
== 2)
3930 WORD value_count
= table_read_be_word(table
, subtable_offset
+
3931 FIELD_OFFSET(struct ot_gpos_singlepos_format2
, value_count
));
3932 const struct ot_gpos_singlepos_format2
*format2
= table_read_ensure(table
, subtable_offset
,
3933 FIELD_OFFSET(struct ot_gpos_singlepos_format2
, values
) + value_count
* value_len
* sizeof(WORD
));
3935 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
3936 if (coverage_index
== GLYPH_NOT_COVERED
|| coverage_index
>= value_count
)
3939 opentype_layout_apply_gpos_value(context
, subtable_offset
, value_format
, &format2
->values
[coverage_index
* value_len
],
3944 WARN("Unknown single adjustment format %u.\n", format
);
3953 static int __cdecl
gpos_pair_adjustment_compare_format1(const void *g
, const void *r
)
3955 const struct ot_gpos_pairvalue
*pairvalue
= r
;
3956 UINT16 second_glyph
= GET_BE_WORD(pairvalue
->second_glyph
);
3957 return *(UINT16
*)g
- second_glyph
;
3960 static BOOL
opentype_layout_apply_gpos_pair_adjustment(struct scriptshaping_context
*context
,
3961 const struct lookup
*lookup
, unsigned int subtable_offset
)
3963 const struct dwrite_fonttable
*table
= &context
->table
->table
;
3964 unsigned int first_glyph
, second_glyph
;
3965 struct glyph_iterator iter_pair
;
3966 WORD format
, coverage
;
3968 WORD value_format1
, value_format2
, value_len1
, value_len2
;
3969 unsigned int coverage_index
;
3971 glyph_iterator_init(context
, lookup
->flags
, context
->cur
, 1, &iter_pair
);
3972 if (!glyph_iterator_next(&iter_pair
))
3975 if (context
->is_rtl
)
3977 first_glyph
= iter_pair
.pos
;
3978 second_glyph
= context
->cur
;
3982 first_glyph
= context
->cur
;
3983 second_glyph
= iter_pair
.pos
;
3986 format
= table_read_be_word(table
, subtable_offset
);
3988 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_pairpos_format1
, coverage
));
3992 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, context
->u
.pos
.glyphs
[first_glyph
]);
3993 if (coverage_index
== GLYPH_NOT_COVERED
)
3998 const struct ot_gpos_pairpos_format1
*format1
;
3999 WORD pairset_count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_pairpos_format1
,
4001 unsigned int pairvalue_len
, pairset_offset
;
4002 const struct ot_gpos_pairset
*pairset
;
4003 const WORD
*pairvalue
;
4004 WORD pairvalue_count
;
4006 if (!pairset_count
|| coverage_index
>= pairset_count
)
4009 format1
= table_read_ensure(table
, subtable_offset
, FIELD_OFFSET(struct ot_gpos_pairpos_format1
, pairsets
[pairset_count
]));
4013 /* Ordered paired values. */
4014 pairvalue_count
= table_read_be_word(table
, subtable_offset
+ GET_BE_WORD(format1
->pairsets
[coverage_index
]));
4015 if (!pairvalue_count
)
4018 /* Structure length is variable, but does not change across the subtable. */
4019 value_format1
= GET_BE_WORD(format1
->value_format1
) & 0xff;
4020 value_format2
= GET_BE_WORD(format1
->value_format2
) & 0xff;
4022 value_len1
= dwrite_popcount(value_format1
);
4023 value_len2
= dwrite_popcount(value_format2
);
4024 pairvalue_len
= FIELD_OFFSET(struct ot_gpos_pairvalue
, data
) + value_len1
* sizeof(WORD
) +
4025 value_len2
* sizeof(WORD
);
4027 pairset_offset
= subtable_offset
+ GET_BE_WORD(format1
->pairsets
[coverage_index
]);
4028 pairset
= table_read_ensure(table
, pairset_offset
, pairvalue_len
* pairvalue_count
);
4032 pairvalue
= bsearch(&context
->u
.pos
.glyphs
[second_glyph
], pairset
->pairvalues
, pairvalue_count
,
4033 pairvalue_len
, gpos_pair_adjustment_compare_format1
);
4037 pairvalue
+= 1; /* Skip SecondGlyph. */
4038 opentype_layout_apply_gpos_value(context
, pairset_offset
, value_format1
, pairvalue
, first_glyph
);
4039 opentype_layout_apply_gpos_value(context
, pairset_offset
, value_format2
, pairvalue
+ value_len1
,
4042 context
->cur
= iter_pair
.pos
;
4046 else if (format
== 2)
4048 const struct ot_gpos_pairpos_format2
*format2
;
4049 WORD class1_count
, class2_count
;
4050 unsigned int class1
, class2
;
4051 const WCHAR
*values
;
4053 value_format1
= table_read_be_word(table
, subtable_offset
+
4054 FIELD_OFFSET(struct ot_gpos_pairpos_format2
, value_format1
)) & 0xff;
4055 value_format2
= table_read_be_word(table
, subtable_offset
+
4056 FIELD_OFFSET(struct ot_gpos_pairpos_format2
, value_format2
)) & 0xff;
4058 class1_count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_pairpos_format2
, class1_count
));
4059 class2_count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_pairpos_format2
, class2_count
));
4061 value_len1
= dwrite_popcount(value_format1
);
4062 value_len2
= dwrite_popcount(value_format2
);
4064 format2
= table_read_ensure(table
, subtable_offset
, FIELD_OFFSET(struct ot_gpos_pairpos_format2
,
4065 values
[class1_count
* class2_count
* (value_len1
+ value_len2
)]));
4069 class1
= opentype_layout_get_glyph_class(table
, subtable_offset
+ GET_BE_WORD(format2
->class_def1
),
4070 context
->u
.pos
.glyphs
[first_glyph
]);
4071 class2
= opentype_layout_get_glyph_class(table
, subtable_offset
+ GET_BE_WORD(format2
->class_def2
),
4072 context
->u
.pos
.glyphs
[second_glyph
]);
4074 if (!(class1
< class1_count
&& class2
< class2_count
))
4077 values
= &format2
->values
[(class1
* class2_count
+ class2
) * (value_len1
+ value_len2
)];
4078 opentype_layout_apply_gpos_value(context
, subtable_offset
, value_format1
, values
, first_glyph
);
4079 opentype_layout_apply_gpos_value(context
, subtable_offset
, value_format2
, values
+ value_len1
,
4082 context
->cur
= iter_pair
.pos
;
4088 WARN("Unknown pair adjustment format %u.\n", format
);
4095 static void opentype_layout_gpos_get_anchor(const struct scriptshaping_context
*context
, unsigned int anchor_offset
,
4096 unsigned int glyph_index
, float *x
, float *y
)
4098 const struct scriptshaping_cache
*cache
= context
->cache
;
4099 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4101 WORD format
= table_read_be_word(table
, anchor_offset
);
4107 const struct ot_gpos_anchor_format1
*format1
= table_read_ensure(table
, anchor_offset
, sizeof(*format1
));
4111 *x
= opentype_scale_gpos_be_value(format1
->x_coord
, context
->emsize
, cache
->upem
);
4112 *y
= opentype_scale_gpos_be_value(format1
->y_coord
, context
->emsize
, cache
->upem
);
4115 else if (format
== 2)
4117 const struct ot_gpos_anchor_format2
*format2
= table_read_ensure(table
, anchor_offset
, sizeof(*format2
));
4121 if (context
->measuring_mode
!= DWRITE_MEASURING_MODE_NATURAL
)
4122 FIXME("Use outline anchor point for glyph %u.\n", context
->u
.pos
.glyphs
[glyph_index
]);
4124 *x
= opentype_scale_gpos_be_value(format2
->x_coord
, context
->emsize
, cache
->upem
);
4125 *y
= opentype_scale_gpos_be_value(format2
->y_coord
, context
->emsize
, cache
->upem
);
4128 else if (format
== 3)
4130 const struct ot_gpos_anchor_format3
*format3
= table_read_ensure(table
, anchor_offset
, sizeof(*format3
));
4134 *x
= opentype_scale_gpos_be_value(format3
->x_coord
, context
->emsize
, cache
->upem
);
4135 *y
= opentype_scale_gpos_be_value(format3
->y_coord
, context
->emsize
, cache
->upem
);
4137 if (context
->measuring_mode
!= DWRITE_MEASURING_MODE_NATURAL
)
4139 if (format3
->x_dev_offset
)
4140 *x
+= opentype_layout_gpos_get_dev_value(context
, anchor_offset
+ GET_BE_WORD(format3
->x_dev_offset
));
4141 if (format3
->y_dev_offset
)
4142 *y
+= opentype_layout_gpos_get_dev_value(context
, anchor_offset
+ GET_BE_WORD(format3
->y_dev_offset
));
4147 WARN("Unknown anchor format %u.\n", format
);
4150 static void opentype_set_glyph_attach_type(struct scriptshaping_context
*context
, unsigned int idx
,
4151 enum attach_type attach_type
)
4153 context
->glyph_infos
[idx
].props
&= ~GLYPH_PROP_ATTACH_TYPE_MASK
;
4154 context
->glyph_infos
[idx
].props
|= attach_type
<< 16;
4157 static enum attach_type
opentype_get_glyph_attach_type(const struct scriptshaping_context
*context
, unsigned int idx
)
4159 return (context
->glyph_infos
[idx
].props
>> 16) & 0xff;
4162 static void opentype_reverse_cursive_offset(struct scriptshaping_context
*context
, unsigned int i
,
4163 unsigned int new_parent
)
4165 enum attach_type type
= opentype_get_glyph_attach_type(context
, i
);
4166 int chain
= context
->glyph_infos
[i
].attach_chain
;
4169 if (!chain
|| type
!= GLYPH_ATTACH_CURSIVE
)
4172 context
->glyph_infos
[i
].attach_chain
= 0;
4175 if (j
== new_parent
)
4178 opentype_reverse_cursive_offset(context
, j
, new_parent
);
4180 /* FIXME: handle vertical flow direction */
4181 context
->offsets
[j
].ascenderOffset
= -context
->offsets
[i
].ascenderOffset
;
4183 context
->glyph_infos
[j
].attach_chain
= -chain
;
4184 opentype_set_glyph_attach_type(context
, j
, type
);
4187 static BOOL
opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_context
*context
,
4188 const struct lookup
*lookup
, unsigned int subtable_offset
)
4190 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4191 UINT16 format
, glyph
;
4193 format
= table_read_be_word(table
, subtable_offset
);
4194 glyph
= context
->u
.pos
.glyphs
[context
->cur
];
4198 WORD coverage_offset
= table_read_be_word(table
, subtable_offset
+
4199 FIELD_OFFSET(struct ot_gpos_cursive_format1
, coverage
));
4200 unsigned int glyph_index
, entry_count
, entry_anchor
, exit_anchor
, child
, parent
;
4201 float entry_x
, entry_y
, exit_x
, exit_y
, delta
;
4202 struct glyph_iterator prev_iter
;
4205 if (!coverage_offset
)
4208 entry_count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gpos_cursive_format1
, count
));
4210 glyph_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage_offset
, glyph
);
4211 if (glyph_index
== GLYPH_NOT_COVERED
|| glyph_index
>= entry_count
)
4214 entry_anchor
= table_read_be_word(table
, subtable_offset
+
4215 FIELD_OFFSET(struct ot_gpos_cursive_format1
, anchors
[glyph_index
* 2]));
4219 glyph_iterator_init(context
, lookup
->flags
, context
->cur
, 1, &prev_iter
);
4220 if (!glyph_iterator_prev(&prev_iter
))
4223 glyph_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage_offset
,
4224 context
->u
.pos
.glyphs
[prev_iter
.pos
]);
4225 if (glyph_index
== GLYPH_NOT_COVERED
|| glyph_index
>= entry_count
)
4228 exit_anchor
= table_read_be_word(table
, subtable_offset
+
4229 FIELD_OFFSET(struct ot_gpos_cursive_format1
, anchors
[glyph_index
* 2 + 1]));
4233 opentype_layout_gpos_get_anchor(context
, subtable_offset
+ exit_anchor
, prev_iter
.pos
, &exit_x
, &exit_y
);
4234 opentype_layout_gpos_get_anchor(context
, subtable_offset
+ entry_anchor
, context
->cur
, &entry_x
, &entry_y
);
4236 if (context
->is_rtl
)
4238 delta
= exit_x
+ context
->offsets
[prev_iter
.pos
].advanceOffset
;
4239 context
->advances
[prev_iter
.pos
] -= delta
;
4240 context
->advances
[context
->cur
] = entry_x
+ context
->offsets
[context
->cur
].advanceOffset
;
4241 context
->offsets
[prev_iter
.pos
].advanceOffset
-= delta
;
4245 delta
= entry_x
+ context
->offsets
[context
->cur
].advanceOffset
;
4246 context
->advances
[prev_iter
.pos
] = exit_x
+ context
->offsets
[prev_iter
.pos
].advanceOffset
;
4247 context
->advances
[context
->cur
] -= delta
;
4248 context
->offsets
[context
->cur
].advanceOffset
-= delta
;
4251 if (lookup
->flags
& LOOKUP_FLAG_RTL
)
4253 y_offset
= entry_y
- exit_y
;
4254 child
= prev_iter
.pos
;
4255 parent
= context
->cur
;
4259 y_offset
= exit_y
- entry_y
;
4260 child
= context
->cur
;
4261 parent
= prev_iter
.pos
;
4264 opentype_reverse_cursive_offset(context
, child
, parent
);
4266 context
->offsets
[child
].ascenderOffset
= y_offset
;
4268 opentype_set_glyph_attach_type(context
, child
, GLYPH_ATTACH_CURSIVE
);
4269 context
->glyph_infos
[child
].attach_chain
= (int)parent
- (int)child
;
4270 context
->has_gpos_attachment
= 1;
4272 if (context
->glyph_infos
[parent
].attach_chain
== -context
->glyph_infos
[child
].attach_chain
)
4273 context
->glyph_infos
[parent
].attach_chain
= 0;
4279 WARN("Unknown cursive attachment format %u.\n", format
);
4286 static BOOL
opentype_layout_apply_mark_array(struct scriptshaping_context
*context
, unsigned int subtable_offset
,
4287 unsigned int mark_array
, unsigned int mark_index
, unsigned int glyph_index
, unsigned int anchors_matrix
,
4288 unsigned int class_count
, unsigned int glyph_pos
)
4290 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4291 unsigned int mark_class
, mark_count
, glyph_count
;
4292 const struct ot_gpos_mark_record
*record
;
4293 float mark_x
, mark_y
, base_x
, base_y
;
4294 const UINT16
*anchors
;
4296 mark_count
= table_read_be_word(table
, subtable_offset
+ mark_array
);
4297 if (mark_index
>= mark_count
) return FALSE
;
4299 if (!(record
= table_read_ensure(table
, subtable_offset
+ mark_array
+
4300 FIELD_OFFSET(struct ot_gpos_mark_array
, records
[mark_index
]), sizeof(*record
))))
4305 mark_class
= GET_BE_WORD(record
->mark_class
);
4306 if (mark_class
>= class_count
) return FALSE
;
4308 glyph_count
= table_read_be_word(table
, subtable_offset
+ anchors_matrix
);
4309 if (glyph_index
>= glyph_count
) return FALSE
;
4311 /* Anchors data is stored as two dimensional array [glyph_count][class_count], starting with row count field. */
4312 anchors
= table_read_ensure(table
, subtable_offset
+ anchors_matrix
+ 2, glyph_count
* class_count
* sizeof(*anchors
));
4313 if (!anchors
) return FALSE
;
4315 opentype_layout_gpos_get_anchor(context
, subtable_offset
+ mark_array
+ GET_BE_WORD(record
->mark_anchor
),
4316 context
->cur
, &mark_x
, &mark_y
);
4317 opentype_layout_gpos_get_anchor(context
, subtable_offset
+ anchors_matrix
+
4318 GET_BE_WORD(anchors
[glyph_index
* class_count
+ mark_class
]), glyph_pos
, &base_x
, &base_y
);
4320 if (context
->is_rtl
)
4321 context
->offsets
[context
->cur
].advanceOffset
= mark_x
- base_x
;
4323 context
->offsets
[context
->cur
].advanceOffset
= base_x
- mark_x
;
4324 context
->offsets
[context
->cur
].ascenderOffset
= base_y
- mark_y
;
4325 opentype_set_glyph_attach_type(context
, context
->cur
, GLYPH_ATTACH_MARK
);
4326 context
->glyph_infos
[context
->cur
].attach_chain
= (int)glyph_pos
- (int)context
->cur
;
4327 context
->has_gpos_attachment
= 1;
4334 static BOOL
opentype_layout_apply_gpos_mark_to_base_attachment(struct scriptshaping_context
*context
,
4335 const struct lookup
*lookup
, unsigned int subtable_offset
)
4337 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4340 format
= table_read_be_word(table
, subtable_offset
);
4344 const struct ot_gpos_mark_to_base_format1
*format1
;
4345 unsigned int base_index
, mark_index
;
4346 struct glyph_iterator base_iter
;
4348 if (!(format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
)))) return FALSE
;
4350 mark_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->mark_coverage
),
4351 context
->u
.pos
.glyphs
[context
->cur
]);
4352 if (mark_index
== GLYPH_NOT_COVERED
) return FALSE
;
4354 /* Look back for first base glyph. */
4355 glyph_iterator_init(context
, LOOKUP_FLAG_IGNORE_MARKS
, context
->cur
, 1, &base_iter
);
4356 if (!glyph_iterator_prev(&base_iter
))
4359 base_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->base_coverage
),
4360 context
->u
.pos
.glyphs
[base_iter
.pos
]);
4361 if (base_index
== GLYPH_NOT_COVERED
) return FALSE
;
4363 return opentype_layout_apply_mark_array(context
, subtable_offset
, GET_BE_WORD(format1
->mark_array
), mark_index
,
4364 base_index
, GET_BE_WORD(format1
->base_array
), GET_BE_WORD(format1
->mark_class_count
), base_iter
.pos
);
4368 WARN("Unknown mark-to-base format %u.\n", format
);
4375 static const UINT16
* table_read_array_be_word(const struct dwrite_fonttable
*table
, unsigned int offset
,
4376 unsigned int index
, UINT16
*data
)
4378 unsigned int count
= table_read_be_word(table
, offset
);
4379 const UINT16
*array
;
4381 if (index
!= ~0u && index
>= count
) return NULL
;
4382 if (!(array
= table_read_ensure(table
, offset
+ 2, count
* sizeof(*array
)))) return FALSE
;
4383 *data
= index
== ~0u ? count
: GET_BE_WORD(array
[index
]);
4387 static BOOL
opentype_layout_apply_gpos_mark_to_lig_attachment(struct scriptshaping_context
*context
,
4388 const struct lookup
*lookup
, unsigned int subtable_offset
)
4390 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4393 format
= table_read_be_word(table
, subtable_offset
);
4397 unsigned int mark_index
, lig_index
, comp_index
, class_count
, comp_count
;
4398 const struct ot_gpos_mark_to_lig_format1
*format1
;
4399 struct glyph_iterator lig_iter
;
4400 unsigned int lig_array
;
4403 if (!(format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
)))) return FALSE
;
4405 mark_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->mark_coverage
),
4406 context
->u
.pos
.glyphs
[context
->cur
]);
4407 if (mark_index
== GLYPH_NOT_COVERED
) return FALSE
;
4409 glyph_iterator_init(context
, LOOKUP_FLAG_IGNORE_MARKS
, context
->cur
, 1, &lig_iter
);
4410 if (!glyph_iterator_prev(&lig_iter
))
4413 lig_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->lig_coverage
),
4414 context
->u
.pos
.glyphs
[lig_iter
.pos
]);
4415 if (lig_index
== GLYPH_NOT_COVERED
) return FALSE
;
4417 class_count
= GET_BE_WORD(format1
->mark_class_count
);
4419 lig_array
= GET_BE_WORD(format1
->lig_array
);
4421 if (!table_read_array_be_word(table
, subtable_offset
+ lig_array
, lig_index
, &lig_attach
)) return FALSE
;
4423 comp_count
= table_read_be_word(table
, subtable_offset
+ lig_array
+ lig_attach
);
4424 if (!comp_count
) return FALSE
;
4426 comp_index
= context
->u
.buffer
.glyph_props
[lig_iter
.pos
].components
-
4427 context
->u
.buffer
.glyph_props
[context
->cur
].lig_component
- 1;
4428 if (comp_index
>= comp_count
) return FALSE
;
4430 return opentype_layout_apply_mark_array(context
, subtable_offset
, GET_BE_WORD(format1
->mark_array
), mark_index
,
4431 comp_index
, lig_array
+ lig_attach
, class_count
, lig_iter
.pos
);
4434 WARN("Unknown mark-to-ligature format %u.\n", format
);
4439 static BOOL
opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshaping_context
*context
,
4440 const struct lookup
*lookup
, unsigned int subtable_offset
)
4442 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4445 format
= table_read_be_word(table
, subtable_offset
);
4449 const struct ot_gpos_mark_to_mark_format1
*format1
;
4450 unsigned int mark1_index
, mark2_index
;
4451 struct glyph_iterator mark_iter
;
4453 if (!(format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
)))) return FALSE
;
4455 mark1_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->mark1_coverage
),
4456 context
->u
.pos
.glyphs
[context
->cur
]);
4457 if (mark1_index
== GLYPH_NOT_COVERED
) return FALSE
;
4459 glyph_iterator_init(context
, lookup
->flags
& ~LOOKUP_FLAG_IGNORE_MASK
, context
->cur
, 1, &mark_iter
);
4460 if (!glyph_iterator_prev(&mark_iter
))
4463 if (!context
->u
.pos
.glyph_props
[mark_iter
.pos
].isDiacritic
)
4466 mark2_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(format1
->mark2_coverage
),
4467 context
->u
.pos
.glyphs
[mark_iter
.pos
]);
4468 if (mark2_index
== GLYPH_NOT_COVERED
) return FALSE
;
4470 return opentype_layout_apply_mark_array(context
, subtable_offset
, GET_BE_WORD(format1
->mark1_array
), mark1_index
,
4471 mark2_index
, GET_BE_WORD(format1
->mark2_array
), GET_BE_WORD(format1
->mark_class_count
), mark_iter
.pos
);
4475 WARN("Unknown mark-to-mark format %u.\n", format
);
4482 static BOOL
opentype_layout_apply_context(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4483 unsigned int subtable_offset
);
4484 static BOOL
opentype_layout_apply_chain_context(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4485 unsigned int subtable_offset
);
4487 static BOOL
opentype_layout_apply_gpos_lookup(struct scriptshaping_context
*context
, const struct lookup
*lookup
)
4489 unsigned int i
, lookup_type
;
4492 for (i
= 0; i
< lookup
->subtable_count
; ++i
)
4494 unsigned int subtable_offset
= opentype_layout_get_gsubgpos_subtable(context
, lookup
, i
, &lookup_type
);
4496 switch (lookup_type
)
4498 case GPOS_LOOKUP_SINGLE_ADJUSTMENT
:
4499 ret
= opentype_layout_apply_gpos_single_adjustment(context
, lookup
, subtable_offset
);
4501 case GPOS_LOOKUP_PAIR_ADJUSTMENT
:
4502 ret
= opentype_layout_apply_gpos_pair_adjustment(context
, lookup
, subtable_offset
);
4504 case GPOS_LOOKUP_CURSIVE_ATTACHMENT
:
4505 ret
= opentype_layout_apply_gpos_cursive_attachment(context
, lookup
, subtable_offset
);
4507 case GPOS_LOOKUP_MARK_TO_BASE_ATTACHMENT
:
4508 ret
= opentype_layout_apply_gpos_mark_to_base_attachment(context
, lookup
, subtable_offset
);
4510 case GPOS_LOOKUP_MARK_TO_LIGATURE_ATTACHMENT
:
4511 ret
= opentype_layout_apply_gpos_mark_to_lig_attachment(context
, lookup
, subtable_offset
);
4513 case GPOS_LOOKUP_MARK_TO_MARK_ATTACHMENT
:
4514 ret
= opentype_layout_apply_gpos_mark_to_mark_attachment(context
, lookup
, subtable_offset
);
4516 case GPOS_LOOKUP_CONTEXTUAL_POSITION
:
4517 ret
= opentype_layout_apply_context(context
, lookup
, subtable_offset
);
4519 case GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION
:
4520 ret
= opentype_layout_apply_chain_context(context
, lookup
, subtable_offset
);
4522 case GPOS_LOOKUP_EXTENSION_POSITION
:
4523 WARN("Recursive extension lookup.\n");
4526 WARN("Unknown lookup type %u.\n", lookup_type
);
4538 struct lookup
*lookups
;
4543 static int __cdecl
lookups_sorting_compare(const void *a
, const void *b
)
4545 const struct lookup
*left
= (const struct lookup
*)a
;
4546 const struct lookup
*right
= (const struct lookup
*)b
;
4547 return left
->index
< right
->index
? -1 : left
->index
> right
->index
? 1 : 0;
4550 static BOOL
opentype_layout_init_lookup(const struct ot_gsubgpos_table
*table
, unsigned short lookup_index
,
4551 const struct shaping_feature
*feature
, struct lookup
*lookup
)
4553 unsigned short subtable_count
, lookup_type
, mark_filtering_set
;
4554 const struct ot_lookup_table
*lookup_table
;
4555 unsigned int offset
, flags
;
4557 if (!(offset
= table_read_be_word(&table
->table
, table
->lookup_list
+
4558 FIELD_OFFSET(struct ot_lookup_list
, lookup
[lookup_index
]))))
4563 offset
+= table
->lookup_list
;
4565 if (!(lookup_table
= table_read_ensure(&table
->table
, offset
, sizeof(*lookup_table
))))
4568 if (!(subtable_count
= GET_BE_WORD(lookup_table
->subtable_count
)))
4571 lookup_type
= GET_BE_WORD(lookup_table
->lookup_type
);
4572 flags
= GET_BE_WORD(lookup_table
->flags
);
4574 if (flags
& LOOKUP_FLAG_USE_MARK_FILTERING_SET
)
4576 mark_filtering_set
= table_read_be_word(&table
->table
, offset
+
4577 FIELD_OFFSET(struct ot_lookup_table
, subtable
[subtable_count
]));
4578 flags
|= mark_filtering_set
<< 16;
4581 lookup
->index
= lookup_index
;
4582 lookup
->type
= lookup_type
;
4583 lookup
->flags
= flags
;
4584 lookup
->subtable_count
= subtable_count
;
4585 lookup
->offset
= offset
;
4588 lookup
->mask
= feature
->mask
;
4589 lookup
->auto_zwnj
= !(feature
->flags
& FEATURE_MANUAL_ZWNJ
);
4590 lookup
->auto_zwj
= !(feature
->flags
& FEATURE_MANUAL_ZWJ
);
4596 static void opentype_layout_add_lookups(const struct ot_feature_list
*feature_list
, UINT16 total_lookup_count
,
4597 const struct ot_gsubgpos_table
*table
, struct shaping_feature
*feature
, struct lookups
*lookups
)
4599 UINT16 feature_offset
, lookup_count
;
4602 /* Feature wasn't found */
4603 if (feature
->index
== 0xffff)
4606 feature_offset
= GET_BE_WORD(feature_list
->features
[feature
->index
].offset
);
4608 lookup_count
= table_read_be_word(&table
->table
, table
->feature_list
+ feature_offset
+
4609 FIELD_OFFSET(struct ot_feature
, lookup_count
));
4613 if (!dwrite_array_reserve((void **)&lookups
->lookups
, &lookups
->capacity
, lookups
->count
+ lookup_count
,
4614 sizeof(*lookups
->lookups
)))
4619 for (i
= 0; i
< lookup_count
; ++i
)
4621 UINT16 lookup_index
= table_read_be_word(&table
->table
, table
->feature_list
+ feature_offset
+
4622 FIELD_OFFSET(struct ot_feature
, lookuplist_index
[i
]));
4624 if (lookup_index
>= total_lookup_count
)
4627 if (opentype_layout_init_lookup(table
, lookup_index
, feature
, &lookups
->lookups
[lookups
->count
]))
4632 static void opentype_layout_collect_lookups(struct scriptshaping_context
*context
, unsigned int script_index
,
4633 unsigned int language_index
, struct shaping_features
*features
, const struct ot_gsubgpos_table
*table
,
4634 struct lookups
*lookups
)
4636 unsigned int last_num_lookups
= 0, stage
, script_feature_count
= 0;
4637 UINT16 total_feature_count
, total_lookup_count
;
4638 struct shaping_feature required_feature
= { 0 };
4639 const struct ot_feature_list
*feature_list
;
4640 const struct ot_langsys
*langsys
= NULL
;
4641 struct shaping_feature
*feature
;
4642 unsigned int i
, j
, next_bit
;
4643 unsigned int global_bit_shift
= 1;
4644 unsigned int global_bit_mask
= 2;
4645 UINT16 feature_index
;
4647 if (!table
->table
.data
)
4650 if (script_index
!= ~0u)
4652 unsigned int table_offset
, langsys_offset
;
4654 /* ScriptTable offset. */
4655 table_offset
= table_read_be_word(&table
->table
, table
->script_list
+ FIELD_OFFSET(struct ot_script_list
, scripts
) +
4656 script_index
* sizeof(struct ot_script_record
) + FIELD_OFFSET(struct ot_script_record
, script
));
4660 if (language_index
== ~0u)
4661 langsys_offset
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
);
4663 langsys_offset
= table_read_be_word(&table
->table
, table
->script_list
+ table_offset
+
4664 FIELD_OFFSET(struct ot_script
, langsys
) + language_index
* sizeof(struct ot_langsys_record
) +
4665 FIELD_OFFSET(struct ot_langsys_record
, langsys
));
4666 langsys_offset
+= table
->script_list
+ table_offset
;
4668 script_feature_count
= table_read_be_word(&table
->table
, langsys_offset
+ FIELD_OFFSET(struct ot_langsys
, feature_count
));
4669 if (script_feature_count
)
4670 langsys
= table_read_ensure(&table
->table
, langsys_offset
,
4671 FIELD_OFFSET(struct ot_langsys
, feature_index
[script_feature_count
]));
4673 script_feature_count
= 0;
4676 total_feature_count
= table_read_be_word(&table
->table
, table
->feature_list
);
4677 if (!total_feature_count
)
4680 total_lookup_count
= table_read_be_word(&table
->table
, table
->lookup_list
);
4681 if (!total_lookup_count
)
4684 feature_list
= table_read_ensure(&table
->table
, table
->feature_list
,
4685 FIELD_OFFSET(struct ot_feature_list
, features
[total_feature_count
]));
4689 /* Required feature. */
4690 required_feature
.index
= langsys
? GET_BE_WORD(langsys
->required_feature_index
) : 0xffff;
4691 if (required_feature
.index
< total_feature_count
)
4692 required_feature
.tag
= feature_list
->features
[required_feature
.index
].tag
;
4693 required_feature
.mask
= global_bit_mask
;
4695 context
->global_mask
= global_bit_mask
;
4696 next_bit
= global_bit_shift
+ 1;
4697 for (i
= 0; i
< features
->count
; ++i
)
4702 feature
= &features
->features
[i
];
4704 feature
->index
= 0xffff;
4706 if ((feature
->flags
& FEATURE_GLOBAL
) && feature
->max_value
== 1)
4710 BitScanReverse(&bits_needed
, min(feature
->max_value
, 256));
4714 if (!feature
->max_value
|| next_bit
+ bits_needed
> 8 * sizeof (feature
->mask
))
4717 if (required_feature
.tag
== feature
->tag
)
4718 required_feature
.stage
= feature
->stage
;
4720 for (j
= 0; j
< script_feature_count
; ++j
)
4722 feature_index
= GET_BE_WORD(langsys
->feature_index
[j
]);
4723 if (feature_index
>= total_feature_count
)
4725 if ((found
= feature_list
->features
[feature_index
].tag
== feature
->tag
))
4727 feature
->index
= feature_index
;
4732 if (!found
&& (features
->features
[i
].flags
& FEATURE_GLOBAL_SEARCH
))
4734 for (j
= 0; j
< total_feature_count
; ++j
)
4736 if ((found
= (feature_list
->features
[j
].tag
== feature
->tag
)))
4744 if (!found
&& !(features
->features
[i
].flags
& FEATURE_HAS_FALLBACK
))
4747 if (feature
->flags
& FEATURE_GLOBAL
&& feature
->max_value
== 1)
4749 feature
->shift
= global_bit_shift
;
4750 feature
->mask
= global_bit_mask
;
4754 feature
->shift
= next_bit
;
4755 feature
->mask
= (1 << (next_bit
+ bits_needed
)) - (1 << next_bit
);
4756 next_bit
+= bits_needed
;
4757 context
->global_mask
|= (feature
->default_value
<< feature
->shift
) & feature
->mask
;
4760 feature
->flags
|= FEATURE_NEEDS_FALLBACK
;
4763 for (stage
= 0; stage
<= features
->stage
; ++stage
)
4765 if (required_feature
.index
!= 0xffff && required_feature
.stage
== stage
)
4766 opentype_layout_add_lookups(feature_list
, total_lookup_count
, table
, &required_feature
, lookups
);
4768 for (i
= 0; i
< features
->count
; ++i
)
4770 if (features
->features
[i
].stage
== stage
)
4771 opentype_layout_add_lookups(feature_list
, total_lookup_count
, table
, &features
->features
[i
], lookups
);
4774 /* Sort and merge lookups for current stage. */
4775 if (last_num_lookups
< lookups
->count
)
4777 qsort(lookups
->lookups
+ last_num_lookups
, lookups
->count
- last_num_lookups
, sizeof(*lookups
->lookups
),
4778 lookups_sorting_compare
);
4780 j
= last_num_lookups
;
4781 for (i
= j
+ 1; i
< lookups
->count
; ++i
)
4783 if (lookups
->lookups
[i
].index
!= lookups
->lookups
[j
].index
)
4785 lookups
->lookups
[++j
] = lookups
->lookups
[i
];
4789 lookups
->lookups
[j
].mask
|= lookups
->lookups
[i
].mask
;
4790 lookups
->lookups
[j
].auto_zwnj
&= lookups
->lookups
[i
].auto_zwnj
;
4791 lookups
->lookups
[j
].auto_zwj
&= lookups
->lookups
[i
].auto_zwj
;
4794 lookups
->count
= j
+ 1;
4797 last_num_lookups
= lookups
->count
;
4798 features
->stages
[stage
].last_lookup
= last_num_lookups
;
4802 static int __cdecl
feature_search_compare(const void *a
, const void* b
)
4804 unsigned int tag
= *(unsigned int *)a
;
4805 const struct shaping_feature
*feature
= b
;
4807 return tag
< feature
->tag
? -1 : tag
> feature
->tag
? 1 : 0;
4810 static unsigned int shaping_features_get_mask(const struct shaping_features
*features
, unsigned int tag
, unsigned int *shift
)
4812 struct shaping_feature
*feature
;
4814 feature
= bsearch(&tag
, features
->features
, features
->count
, sizeof(*features
->features
), feature_search_compare
);
4816 if (!feature
|| feature
->index
== 0xffff)
4819 if (shift
) *shift
= feature
->shift
;
4820 return feature
->mask
;
4823 unsigned int shape_get_feature_1_mask(const struct shaping_features
*features
, unsigned int tag
)
4825 unsigned int shift
, mask
= shaping_features_get_mask(features
, tag
, &shift
);
4826 return (1 << shift
) & mask
;
4829 static void opentype_layout_get_glyph_range_for_text(struct scriptshaping_context
*context
, unsigned int start_char
,
4830 unsigned int end_char
, unsigned int *start_glyph
, unsigned int *end_glyph
)
4832 *start_glyph
= context
->u
.buffer
.clustermap
[start_char
];
4833 if (end_char
>= context
->length
- 1)
4834 *end_glyph
= context
->glyph_count
- 1;
4836 *end_glyph
= context
->u
.buffer
.clustermap
[end_char
] - 1;
4839 static void opentype_layout_set_glyph_masks(struct scriptshaping_context
*context
, const struct shaping_features
*features
)
4841 const DWRITE_TYPOGRAPHIC_FEATURES
**user_features
= context
->user_features
.features
;
4842 unsigned int f
, r
, g
, start_char
, mask
, shift
, value
;
4844 for (g
= 0; g
< context
->glyph_count
; ++g
)
4845 context
->glyph_infos
[g
].mask
= context
->global_mask
;
4847 if (opentype_layout_is_subst_context(context
) && context
->shaper
->setup_masks
)
4848 context
->shaper
->setup_masks(context
, features
);
4850 for (r
= 0, start_char
= 0; r
< context
->user_features
.range_count
; ++r
)
4852 unsigned int start_glyph
, end_glyph
;
4854 if (start_char
>= context
->length
)
4857 if (!context
->user_features
.range_lengths
[r
])
4860 opentype_layout_get_glyph_range_for_text(context
, start_char
, start_char
+ context
->user_features
.range_lengths
[r
],
4861 &start_glyph
, &end_glyph
);
4862 start_char
+= context
->user_features
.range_lengths
[r
];
4864 if (start_glyph
> end_glyph
|| end_glyph
>= context
->glyph_count
)
4867 for (f
= 0; f
< user_features
[r
]->featureCount
; ++f
)
4869 mask
= shaping_features_get_mask(features
, user_features
[r
]->features
[f
].nameTag
, &shift
);
4873 value
= (user_features
[r
]->features
[f
].parameter
<< shift
) & mask
;
4875 for (g
= start_glyph
; g
<= end_glyph
; ++g
)
4876 context
->glyph_infos
[g
].mask
= (context
->glyph_infos
[g
].mask
& ~mask
) | value
;
4881 static void opentype_layout_apply_gpos_context_lookup(struct scriptshaping_context
*context
, unsigned int lookup_index
)
4883 struct lookup lookup
= { 0 };
4884 if (opentype_layout_init_lookup(context
->table
, lookup_index
, NULL
, &lookup
))
4885 opentype_layout_apply_gpos_lookup(context
, &lookup
);
4888 static void opentype_propagate_attachment_offsets(struct scriptshaping_context
*context
, unsigned int i
)
4890 enum attach_type type
= opentype_get_glyph_attach_type(context
, i
);
4891 int chain
= context
->glyph_infos
[i
].attach_chain
;
4897 context
->glyph_infos
[i
].attach_chain
= 0;
4900 if (j
>= context
->glyph_count
)
4903 opentype_propagate_attachment_offsets(context
, j
);
4905 if (type
== GLYPH_ATTACH_CURSIVE
)
4907 /* FIXME: handle vertical direction. */
4908 context
->offsets
[i
].ascenderOffset
+= context
->offsets
[j
].ascenderOffset
;
4910 else if (type
== GLYPH_ATTACH_MARK
)
4912 context
->offsets
[i
].advanceOffset
+= context
->offsets
[j
].advanceOffset
;
4913 context
->offsets
[i
].ascenderOffset
+= context
->offsets
[j
].ascenderOffset
;
4915 /* FIXME: handle vertical adjustment. */
4916 if (context
->is_rtl
)
4918 for (k
= j
+ 1; k
< i
+ 1; ++k
)
4920 context
->offsets
[i
].advanceOffset
+= context
->advances
[k
];
4925 for (k
= j
; k
< i
; k
++)
4927 context
->offsets
[i
].advanceOffset
-= context
->advances
[k
];
4933 void opentype_layout_apply_gpos_features(struct scriptshaping_context
*context
, unsigned int script_index
,
4934 unsigned int language_index
, struct shaping_features
*features
)
4936 struct lookups lookups
= { 0 };
4940 context
->nesting_level_left
= SHAPE_MAX_NESTING_LEVEL
;
4941 context
->u
.buffer
.apply_context_lookup
= opentype_layout_apply_gpos_context_lookup
;
4942 opentype_layout_collect_lookups(context
, script_index
, language_index
, features
, &context
->cache
->gpos
, &lookups
);
4944 for (i
= 0; i
< context
->glyph_count
; ++i
)
4945 opentype_set_glyph_props(context
, i
);
4946 opentype_layout_set_glyph_masks(context
, features
);
4948 for (i
= 0; i
< lookups
.count
; ++i
)
4950 const struct lookup
*lookup
= &lookups
.lookups
[i
];
4953 context
->lookup_mask
= lookup
->mask
;
4954 context
->auto_zwnj
= lookup
->auto_zwnj
;
4955 context
->auto_zwj
= lookup
->auto_zwj
;
4957 while (context
->cur
< context
->glyph_count
)
4961 if ((context
->glyph_infos
[context
->cur
].mask
& lookup
->mask
) &&
4962 lookup_is_glyph_match(context
, context
->cur
, lookup
->flags
))
4964 ret
= opentype_layout_apply_gpos_lookup(context
, lookup
);
4972 free(lookups
.lookups
);
4974 if (context
->has_gpos_attachment
)
4976 for (i
= 0; i
< context
->glyph_count
; ++i
)
4977 opentype_propagate_attachment_offsets(context
, i
);
4981 static void opentype_layout_replace_glyph(struct scriptshaping_context
*context
, UINT16 glyph
)
4983 UINT16 orig_glyph
= context
->u
.subst
.glyphs
[context
->cur
];
4984 if (glyph
!= orig_glyph
)
4986 context
->u
.subst
.glyphs
[context
->cur
] = glyph
;
4987 opentype_set_subst_glyph_props(context
, context
->cur
);
4991 static BOOL
opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
4992 unsigned int subtable_offset
)
4994 const struct dwrite_fonttable
*table
= &context
->table
->table
;
4995 UINT16 format
, coverage
, orig_glyph
, glyph
;
4996 unsigned int coverage_index
;
4998 orig_glyph
= glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5000 format
= table_read_be_word(table
, subtable_offset
);
5002 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format1
, coverage
));
5006 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5007 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
5009 glyph
= orig_glyph
+ table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format1
, delta
));
5011 else if (format
== 2)
5013 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5014 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
5016 if (!table_read_array_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format2
, count
),
5017 coverage_index
, &glyph
))
5024 WARN("Unknown single substitution format %u.\n", format
);
5028 opentype_layout_replace_glyph(context
, glyph
);
5034 static BOOL
opentype_layout_gsub_ensure_buffer(struct scriptshaping_context
*context
, unsigned int count
)
5036 DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
;
5037 struct shaping_glyph_info
*glyph_infos
;
5038 unsigned int new_capacity
;
5042 if (context
->u
.subst
.capacity
>= count
)
5045 new_capacity
= context
->u
.subst
.capacity
* 2;
5047 if ((glyphs
= realloc(context
->u
.subst
.glyphs
, new_capacity
* sizeof(*glyphs
))))
5048 context
->u
.subst
.glyphs
= glyphs
;
5049 if ((glyph_props
= realloc(context
->u
.subst
.glyph_props
, new_capacity
* sizeof(*glyph_props
))))
5050 context
->u
.subst
.glyph_props
= glyph_props
;
5051 if ((glyph_infos
= realloc(context
->glyph_infos
, new_capacity
* sizeof(*glyph_infos
))))
5052 context
->glyph_infos
= glyph_infos
;
5054 if ((ret
= (glyphs
&& glyph_props
&& glyph_infos
)))
5055 context
->u
.subst
.capacity
= new_capacity
;
5060 static BOOL
opentype_layout_apply_gsub_mult_substitution(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
5061 unsigned int subtable_offset
)
5063 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5064 UINT16 format
, coverage
, glyph
, glyph_count
;
5065 unsigned int i
, idx
, coverage_index
;
5066 const UINT16
*glyphs
;
5069 glyph
= context
->u
.subst
.glyphs
[idx
];
5071 format
= table_read_be_word(table
, subtable_offset
);
5073 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_multsubst_format1
, coverage
));
5079 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5080 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
5082 if (!table_read_array_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_multsubst_format1
, seq_count
),
5083 coverage_index
, &seq_offset
))
5088 if (!(glyphs
= table_read_array_be_word(table
, subtable_offset
+ seq_offset
, ~0u, &glyph_count
))) return FALSE
;
5090 if (glyph_count
== 1)
5092 /* Equivalent of single substitution. */
5093 opentype_layout_replace_glyph(context
, GET_BE_WORD(glyphs
[0]));
5096 else if (glyph_count
== 0)
5102 unsigned int shift_len
, src_idx
, dest_idx
, mask
;
5104 /* Current glyph is also replaced. */
5107 if (!(opentype_layout_gsub_ensure_buffer(context
, context
->glyph_count
+ glyph_count
)))
5110 shift_len
= context
->cur
+ 1 < context
->glyph_count
? context
->glyph_count
- context
->cur
- 1 : 0;
5114 src_idx
= context
->cur
+ 1;
5115 dest_idx
= src_idx
+ glyph_count
;
5117 memmove(&context
->u
.subst
.glyphs
[dest_idx
], &context
->u
.subst
.glyphs
[src_idx
],
5118 shift_len
* sizeof(*context
->u
.subst
.glyphs
));
5119 memmove(&context
->u
.subst
.glyph_props
[dest_idx
], &context
->u
.subst
.glyph_props
[src_idx
],
5120 shift_len
* sizeof(*context
->u
.subst
.glyph_props
));
5121 memmove(&context
->glyph_infos
[dest_idx
], &context
->glyph_infos
[src_idx
],
5122 shift_len
* sizeof(*context
->glyph_infos
));
5125 mask
= context
->glyph_infos
[context
->cur
].mask
;
5126 for (i
= 0, idx
= context
->cur
; i
<= glyph_count
; ++i
)
5128 glyph
= GET_BE_WORD(glyphs
[i
]);
5129 context
->u
.subst
.glyphs
[idx
+ i
] = glyph
;
5132 context
->u
.subst
.glyph_props
[idx
+ i
].isClusterStart
= 0;
5133 context
->u
.buffer
.glyph_props
[idx
+ i
].components
= 0;
5134 context
->glyph_infos
[idx
+ i
].start_text_idx
= 0;
5136 opentype_set_subst_glyph_props(context
, idx
+ i
);
5137 /* Inherit feature mask from original matched glyph. */
5138 context
->glyph_infos
[idx
+ i
].mask
= mask
;
5141 context
->cur
+= glyph_count
+ 1;
5142 context
->glyph_count
+= glyph_count
;
5147 WARN("Unknown multiple substitution format %u.\n", format
);
5154 static BOOL
opentype_layout_apply_gsub_alt_substitution(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
5155 unsigned int subtable_offset
)
5157 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5158 unsigned int idx
, coverage_index
;
5159 UINT16 format
, coverage
, glyph
;
5162 glyph
= context
->u
.subst
.glyphs
[idx
];
5164 format
= table_read_be_word(table
, subtable_offset
);
5168 const struct ot_gsub_altsubst_format1
*format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
));
5170 unsigned int alt_index
;
5173 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_altsubst_format1
, coverage
));
5175 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5176 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
5178 if (!table_read_array_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_altsubst_format1
, count
),
5179 coverage_index
, &set_offset
))
5182 /* Argument is 1-based. */
5183 BitScanForward(&shift
, context
->lookup_mask
);
5184 alt_index
= (context
->lookup_mask
& context
->glyph_infos
[idx
].mask
) >> shift
;
5185 if (!alt_index
) return FALSE
;
5187 if (!table_read_array_be_word(table
, subtable_offset
+ set_offset
, alt_index
- 1, &glyph
)) return FALSE
;
5191 WARN("Unexpected alternate substitution format %d.\n", format
);
5195 opentype_layout_replace_glyph(context
, glyph
);
5201 static BOOL
opentype_layout_context_match_input(const struct match_context
*mc
, unsigned int count
, const UINT16
*input
,
5202 unsigned int *end_offset
, unsigned int *match_positions
)
5204 struct match_data match_data
= { .mc
= mc
, .subtable_offset
= mc
->input_offset
};
5205 struct scriptshaping_context
*context
= mc
->context
;
5206 struct glyph_iterator iter
;
5209 if (count
> GLYPH_CONTEXT_MAX_LENGTH
)
5212 match_positions
[0] = context
->cur
;
5214 glyph_iterator_init(context
, mc
->lookup
->flags
, context
->cur
, count
- 1, &iter
);
5215 iter
.mask
= context
->lookup_mask
;
5216 iter
.match_func
= mc
->match_func
;
5217 iter
.match_data
= &match_data
;
5218 iter
.glyph_data
= input
;
5220 for (i
= 1; i
< count
; ++i
)
5222 if (!glyph_iterator_next(&iter
))
5225 match_positions
[i
] = iter
.pos
;
5228 *end_offset
= iter
.pos
- context
->cur
+ 1;
5233 /* Marks text segment as unsafe to break between [start, end) glyphs. */
5234 void opentype_layout_unsafe_to_break(struct scriptshaping_context
*context
, unsigned int start
,
5239 while (start
&& !context
->u
.buffer
.glyph_props
[start
].isClusterStart
)
5242 while (--end
&& !context
->u
.buffer
.glyph_props
[end
].isClusterStart
)
5247 context
->u
.buffer
.text_props
[context
->glyph_infos
[start
].start_text_idx
].canBreakShapingAfter
= 0;
5251 for (i
= context
->glyph_infos
[start
].start_text_idx
; i
< context
->glyph_infos
[end
].start_text_idx
; ++i
)
5253 context
->u
.buffer
.text_props
[i
].canBreakShapingAfter
= 0;
5257 static void opentype_layout_delete_glyph(struct scriptshaping_context
*context
, unsigned int idx
)
5259 unsigned int shift_len
;
5261 shift_len
= context
->glyph_count
- context
->cur
- 1;
5265 memmove(&context
->u
.buffer
.glyphs
[idx
], &context
->u
.buffer
.glyphs
[idx
+ 1],
5266 shift_len
* sizeof(*context
->u
.buffer
.glyphs
));
5267 memmove(&context
->u
.buffer
.glyph_props
[idx
], &context
->u
.buffer
.glyph_props
[idx
+ 1],
5268 shift_len
* sizeof(*context
->u
.buffer
.glyph_props
));
5269 memmove(&context
->glyph_infos
[idx
], &context
->glyph_infos
[idx
+ 1], shift_len
* sizeof(*context
->glyph_infos
));
5272 context
->glyph_count
--;
5275 static BOOL
opentype_layout_apply_ligature(struct scriptshaping_context
*context
, unsigned int offset
,
5276 const struct lookup
*lookup
)
5278 struct match_context mc
= { .context
= context
, .lookup
= lookup
, .match_func
= opentype_match_glyph_func
};
5279 const struct dwrite_fonttable
*gsub
= &context
->table
->table
;
5280 unsigned int match_positions
[GLYPH_CONTEXT_MAX_LENGTH
];
5281 unsigned int i
, j
, comp_count
, match_length
= 0;
5282 const struct ot_gsub_lig
*lig
;
5285 comp_count
= table_read_be_word(gsub
, offset
+ FIELD_OFFSET(struct ot_gsub_lig
, comp_count
));
5290 lig
= table_read_ensure(gsub
, offset
, FIELD_OFFSET(struct ot_gsub_lig
, components
[comp_count
-1]));
5294 lig_glyph
= GET_BE_WORD(lig
->lig_glyph
);
5296 if (comp_count
== 1)
5298 opentype_layout_replace_glyph(context
, lig_glyph
);
5303 if (!opentype_layout_context_match_input(&mc
, comp_count
, lig
->components
, &match_length
, match_positions
))
5306 opentype_layout_replace_glyph(context
, lig_glyph
);
5307 context
->u
.buffer
.glyph_props
[context
->cur
].components
= comp_count
;
5309 /* Positioning against a ligature implies keeping track of ligature component
5310 glyph should be attached to. Update per-glyph property for interleaving glyphs,
5311 0 means attaching to last component, n - attaching to n-th glyph before last. */
5312 for (i
= 1; i
< comp_count
; ++i
)
5314 j
= match_positions
[i
- 1] + 1;
5315 while (j
< match_positions
[i
])
5317 context
->u
.buffer
.glyph_props
[j
++].lig_component
= comp_count
- i
;
5320 opentype_layout_unsafe_to_break(context
, match_positions
[0], match_positions
[comp_count
- 1] + 1);
5322 /* Delete ligated glyphs, backwards to preserve index. */
5323 for (i
= 1; i
< comp_count
; ++i
)
5325 opentype_layout_delete_glyph(context
, match_positions
[comp_count
- i
]);
5328 /* Skip whole matched sequence, accounting for deleted glyphs. */
5329 context
->cur
+= match_length
- (comp_count
- 1);
5334 static BOOL
opentype_layout_apply_gsub_lig_substitution(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
5335 unsigned int subtable_offset
)
5337 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5338 UINT16 format
, coverage
, glyph
, lig_set_offset
;
5339 unsigned int coverage_index
;
5341 glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5343 format
= table_read_be_word(table
, subtable_offset
);
5347 const struct ot_gsub_ligsubst_format1
*format1
= table_read_ensure(table
, subtable_offset
, sizeof(*format1
));
5349 const UINT16
*offsets
;
5352 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_ligsubst_format1
, coverage
));
5354 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5355 if (coverage_index
== GLYPH_NOT_COVERED
) return FALSE
;
5357 if (!table_read_array_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_ligsubst_format1
, lig_set_count
),
5358 coverage_index
, &lig_set_offset
))
5361 if (!(offsets
= table_read_array_be_word(table
, subtable_offset
+ lig_set_offset
, ~0u, &lig_count
)))
5364 /* First applicable ligature is used. */
5365 for (i
= 0; i
< lig_count
; ++i
)
5367 if (opentype_layout_apply_ligature(context
, subtable_offset
+ lig_set_offset
+ GET_BE_WORD(offsets
[i
]), lookup
))
5372 WARN("Unexpected ligature substitution format %d.\n", format
);
5377 static BOOL
opentype_layout_context_match_backtrack(const struct match_context
*mc
, unsigned int count
,
5378 const UINT16
*backtrack
, unsigned int *match_start
)
5380 struct match_data match_data
= { .mc
= mc
, .subtable_offset
= mc
->backtrack_offset
};
5381 struct scriptshaping_context
*context
= mc
->context
;
5382 struct glyph_iterator iter
;
5385 glyph_iterator_init(context
, mc
->lookup
->flags
, context
->cur
, count
, &iter
);
5386 iter
.match_func
= mc
->match_func
;
5387 iter
.match_data
= &match_data
;
5388 iter
.glyph_data
= backtrack
;
5389 iter
.ignore_zwnj
|= context
->auto_zwnj
;
5390 iter
.ignore_zwj
= 1;
5392 for (i
= 0; i
< count
; ++i
)
5394 if (!glyph_iterator_prev(&iter
))
5398 *match_start
= iter
.pos
;
5403 static BOOL
opentype_layout_context_match_lookahead(const struct match_context
*mc
, unsigned int count
,
5404 const UINT16
*lookahead
, unsigned int offset
, unsigned int *end_index
)
5406 struct match_data match_data
= { .mc
= mc
, .subtable_offset
= mc
->lookahead_offset
};
5407 struct scriptshaping_context
*context
= mc
->context
;
5408 struct glyph_iterator iter
;
5411 glyph_iterator_init(context
, mc
->lookup
->flags
, context
->cur
+ offset
- 1, count
, &iter
);
5412 iter
.match_func
= mc
->match_func
;
5413 iter
.match_data
= &match_data
;
5414 iter
.glyph_data
= lookahead
;
5415 iter
.ignore_zwnj
|= context
->auto_zwnj
;
5416 iter
.ignore_zwj
= 1;
5418 for (i
= 0; i
< count
; ++i
)
5420 if (!glyph_iterator_next(&iter
))
5424 *end_index
= iter
.pos
;
5429 static BOOL
opentype_layout_context_apply_lookup(struct scriptshaping_context
*context
, unsigned int count
,
5430 unsigned int *match_positions
, unsigned int lookup_count
, const UINT16
*lookup_records
, unsigned int match_length
)
5435 if (!context
->nesting_level_left
)
5438 end
= context
->cur
+ match_length
;
5440 for (i
= 0; i
< lookup_count
; ++i
)
5442 unsigned int idx
= GET_BE_WORD(lookup_records
[i
]);
5443 unsigned int orig_len
, lookup_index
, next
;
5448 context
->cur
= match_positions
[idx
];
5450 orig_len
= context
->glyph_count
;
5452 lookup_index
= GET_BE_WORD(lookup_records
[i
+1]);
5454 --context
->nesting_level_left
;
5455 context
->u
.buffer
.apply_context_lookup(context
, lookup_index
);
5456 ++context
->nesting_level_left
;
5458 delta
= context
->glyph_count
- orig_len
;
5463 if (end
<= (int)match_positions
[idx
])
5465 end
= match_positions
[idx
];
5473 if (delta
+ count
> GLYPH_CONTEXT_MAX_LENGTH
)
5478 delta
= max(delta
, (int)next
- (int)count
);
5482 memmove(match_positions
+ next
+ delta
, match_positions
+ next
,
5483 (count
- next
) * sizeof (*match_positions
));
5487 for (j
= idx
+ 1; j
< next
; j
++)
5488 match_positions
[j
] = match_positions
[j
- 1] + 1;
5490 for (; next
< count
; next
++)
5491 match_positions
[next
] += delta
;
5499 static BOOL
opentype_layout_apply_chain_context_match(unsigned int backtrack_count
, const UINT16
*backtrack
,
5500 unsigned int input_count
, const UINT16
*input
, unsigned int lookahead_count
, const UINT16
*lookahead
,
5501 unsigned int lookup_count
, const UINT16
*lookup_records
, const struct match_context
*mc
)
5503 unsigned int start_index
= 0, match_length
= 0, end_index
= 0;
5504 unsigned int match_positions
[GLYPH_CONTEXT_MAX_LENGTH
];
5506 return opentype_layout_context_match_input(mc
, input_count
, input
, &match_length
, match_positions
) &&
5507 opentype_layout_context_match_backtrack(mc
, backtrack_count
, backtrack
, &start_index
) &&
5508 opentype_layout_context_match_lookahead(mc
, lookahead_count
, lookahead
, input_count
, &end_index
) &&
5509 opentype_layout_context_apply_lookup(mc
->context
, input_count
, match_positions
, lookup_count
, lookup_records
, match_length
);
5512 static BOOL
opentype_layout_apply_chain_rule_set(const struct match_context
*mc
, unsigned int offset
)
5514 unsigned int backtrack_count
, input_count
, lookahead_count
, lookup_count
;
5515 const struct dwrite_fonttable
*table
= &mc
->context
->table
->table
;
5516 const UINT16
*backtrack
, *lookahead
, *input
, *lookup_records
;
5517 const struct ot_gsubgpos_ruleset
*ruleset
;
5518 unsigned int i
, count
;
5520 count
= table_read_be_word(table
, offset
);
5521 ruleset
= table_read_ensure(table
, offset
, count
* sizeof(ruleset
->offsets
));
5523 for (i
= 0; i
< count
; ++i
)
5525 unsigned int rule_offset
= offset
+ GET_BE_WORD(ruleset
->offsets
[i
]);
5527 backtrack_count
= table_read_be_word(table
, rule_offset
);
5529 backtrack
= table_read_ensure(table
, rule_offset
, backtrack_count
* sizeof(*backtrack
));
5530 rule_offset
+= backtrack_count
* sizeof(*backtrack
);
5532 if (!(input_count
= table_read_be_word(table
, rule_offset
)))
5536 input
= table_read_ensure(table
, rule_offset
, (input_count
- 1) * sizeof(*input
));
5537 rule_offset
+= (input_count
- 1) * sizeof(*input
);
5539 lookahead_count
= table_read_be_word(table
, rule_offset
);
5541 lookahead
= table_read_ensure(table
, rule_offset
, lookahead_count
* sizeof(*lookahead
));
5542 rule_offset
+= lookahead_count
* sizeof(*lookahead
);
5544 lookup_count
= table_read_be_word(table
, rule_offset
);
5546 lookup_records
= table_read_ensure(table
, rule_offset
, lookup_count
* 2 * sizeof(*lookup_records
));
5548 /* First applicable rule is used. */
5549 if (opentype_layout_apply_chain_context_match(backtrack_count
, backtrack
, input_count
, input
, lookahead_count
,
5550 lookahead
, lookup_count
, lookup_records
, mc
))
5559 static BOOL
opentype_layout_apply_context_match(unsigned int input_count
, const UINT16
*input
, unsigned int lookup_count
,
5560 const UINT16
*lookup_records
, const struct match_context
*mc
)
5562 unsigned int match_positions
[GLYPH_CONTEXT_MAX_LENGTH
];
5563 unsigned int match_length
= 0;
5565 return opentype_layout_context_match_input(mc
, input_count
, input
, &match_length
, match_positions
) &&
5566 opentype_layout_context_apply_lookup(mc
->context
, input_count
, match_positions
, lookup_count
,
5567 lookup_records
, match_length
);
5570 static BOOL
opentype_layout_apply_rule_set(const struct match_context
*mc
, unsigned int offset
)
5572 unsigned int input_count
, lookup_count
;
5573 const struct dwrite_fonttable
*table
= &mc
->context
->table
->table
;
5574 const UINT16
*input
, *lookup_records
;
5575 const struct ot_gsubgpos_ruleset
*ruleset
;
5576 unsigned int i
, count
;
5578 count
= table_read_be_word(table
, offset
);
5579 ruleset
= table_read_ensure(table
, offset
, count
* sizeof(ruleset
->offsets
));
5581 for (i
= 0; i
< count
; ++i
)
5583 unsigned int rule_offset
= offset
+ GET_BE_WORD(ruleset
->offsets
[i
]);
5585 if (!(input_count
= table_read_be_word(table
, rule_offset
)))
5589 if (!(lookup_count
= table_read_be_word(table
, rule_offset
)))
5593 if (!(input
= table_read_ensure(table
, rule_offset
, (input_count
- 1) * sizeof(*input
))))
5595 rule_offset
+= (input_count
- 1) * sizeof(*input
);
5597 if (!(lookup_records
= table_read_ensure(table
, rule_offset
, lookup_count
* 2 * sizeof(*lookup_records
))))
5600 /* First applicable rule is used. */
5601 if (opentype_layout_apply_context_match(input_count
, input
, lookup_count
, lookup_records
, mc
))
5608 static BOOL
opentype_layout_apply_context(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
5609 unsigned int subtable_offset
)
5611 struct match_context mc
= { .context
= context
, .lookup
= lookup
};
5612 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5613 unsigned int coverage_index
= GLYPH_NOT_COVERED
, count
, offset
;
5614 UINT16 glyph
, format
, coverage
;
5617 glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5619 format
= table_read_be_word(table
, subtable_offset
);
5623 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
, coverage
));
5625 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5626 if (coverage_index
== GLYPH_NOT_COVERED
)
5629 count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
, ruleset_count
));
5630 if (coverage_index
>= count
)
5633 offset
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
,
5634 rulesets
[coverage_index
]));
5635 offset
+= subtable_offset
;
5637 mc
.match_func
= opentype_match_glyph_func
;
5639 ret
= opentype_layout_apply_rule_set(&mc
, offset
);
5641 else if (format
== 2)
5643 unsigned int input_classdef
, rule_set_idx
;
5645 offset
= subtable_offset
+ 2 /* format */;
5647 coverage
= table_read_be_word(table
, offset
);
5650 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5651 if (coverage_index
== GLYPH_NOT_COVERED
)
5654 input_classdef
= table_read_be_word(table
, offset
) + subtable_offset
;
5657 count
= table_read_be_word(table
, offset
);
5660 rule_set_idx
= opentype_layout_get_glyph_class(table
, input_classdef
, glyph
);
5661 if (rule_set_idx
>= count
)
5664 offset
= table_read_be_word(table
, offset
+ rule_set_idx
* 2);
5665 offset
+= subtable_offset
;
5667 mc
.input_offset
= input_classdef
;
5668 mc
.match_func
= opentype_match_class_func
;
5670 ret
= opentype_layout_apply_rule_set(&mc
, offset
);
5672 else if (format
== 3)
5674 unsigned int input_count
, lookup_count
;
5675 const UINT16
*input
, *lookup_records
;
5677 offset
= subtable_offset
+ 2 /* format */;
5679 input_count
= table_read_be_word(table
, offset
);
5685 lookup_count
= table_read_be_word(table
, offset
);
5688 if (!(input
= table_read_ensure(table
, offset
, sizeof(*input
) * input_count
)))
5690 offset
+= sizeof(*input
) * input_count
;
5692 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(input
[0]), glyph
);
5693 if (coverage_index
== GLYPH_NOT_COVERED
)
5696 lookup_records
= table_read_ensure(table
, offset
, lookup_count
* 2 * sizeof(*lookup_records
));
5698 mc
.input_offset
= subtable_offset
;
5699 mc
.match_func
= opentype_match_coverage_func
;
5701 ret
= opentype_layout_apply_context_match(input_count
, input
+ 1, lookup_count
, lookup_records
, &mc
);
5704 WARN("Unknown contextual substitution format %u.\n", format
);
5709 static BOOL
opentype_layout_apply_chain_context(struct scriptshaping_context
*context
, const struct lookup
*lookup
,
5710 unsigned int subtable_offset
)
5712 struct match_context mc
= { .context
= context
, .lookup
= lookup
};
5713 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5714 unsigned int coverage_index
= GLYPH_NOT_COVERED
, count
, offset
;
5715 UINT16 glyph
, format
, coverage
;
5718 glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5720 format
= table_read_be_word(table
, subtable_offset
);
5724 coverage
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
, coverage
));
5726 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5727 if (coverage_index
== GLYPH_NOT_COVERED
)
5730 count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
, ruleset_count
));
5731 if (coverage_index
>= count
)
5734 offset
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsubgpos_context_format1
,
5735 rulesets
[coverage_index
]));
5736 offset
+= subtable_offset
;
5738 mc
.match_func
= opentype_match_glyph_func
;
5740 ret
= opentype_layout_apply_chain_rule_set(&mc
, offset
);
5742 else if (format
== 2)
5744 unsigned int backtrack_classdef
, input_classdef
, lookahead_classdef
, rule_set_idx
;
5746 offset
= subtable_offset
+ 2 /* format */;
5748 coverage
= table_read_be_word(table
, offset
);
5751 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5752 if (coverage_index
== GLYPH_NOT_COVERED
)
5755 backtrack_classdef
= table_read_be_word(table
, offset
) + subtable_offset
;
5758 input_classdef
= table_read_be_word(table
, offset
) + subtable_offset
;
5761 lookahead_classdef
= table_read_be_word(table
, offset
) + subtable_offset
;
5764 count
= table_read_be_word(table
, offset
);
5767 rule_set_idx
= opentype_layout_get_glyph_class(table
, input_classdef
, glyph
);
5768 if (rule_set_idx
>= count
)
5771 offset
= table_read_be_word(table
, offset
+ rule_set_idx
* 2);
5772 offset
+= subtable_offset
;
5774 mc
.backtrack_offset
= backtrack_classdef
;
5775 mc
.input_offset
= input_classdef
;
5776 mc
.lookahead_offset
= lookahead_classdef
;
5777 mc
.match_func
= opentype_match_class_func
;
5779 ret
= opentype_layout_apply_chain_rule_set(&mc
, offset
);
5781 else if (format
== 3)
5783 unsigned int backtrack_count
, input_count
, lookahead_count
, lookup_count
;
5784 const UINT16
*backtrack
, *lookahead
, *input
, *lookup_records
;
5786 offset
= subtable_offset
+ 2 /* format */;
5788 backtrack_count
= table_read_be_word(table
, offset
);
5790 backtrack
= table_read_ensure(table
, offset
, backtrack_count
* sizeof(*backtrack
));
5791 offset
+= backtrack_count
* sizeof(*backtrack
);
5793 input_count
= table_read_be_word(table
, offset
);
5795 input
= table_read_ensure(table
, offset
, input_count
* sizeof(*input
));
5796 offset
+= input_count
* sizeof(*input
);
5798 lookahead_count
= table_read_be_word(table
, offset
);
5800 lookahead
= table_read_ensure(table
, offset
, lookahead_count
* sizeof(*lookahead
));
5801 offset
+= lookahead_count
* sizeof(*lookahead
);
5803 lookup_count
= table_read_be_word(table
, offset
);
5805 lookup_records
= table_read_ensure(table
, offset
, lookup_count
* 2 * sizeof(*lookup_records
));
5808 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(input
[0]), glyph
);
5810 if (coverage_index
== GLYPH_NOT_COVERED
)
5813 mc
.backtrack_offset
= subtable_offset
;
5814 mc
.input_offset
= subtable_offset
;
5815 mc
.lookahead_offset
= subtable_offset
;
5816 mc
.match_func
= opentype_match_coverage_func
;
5818 ret
= opentype_layout_apply_chain_context_match(backtrack_count
, backtrack
, input_count
, input
+ 1, lookahead_count
,
5819 lookahead
, lookup_count
, lookup_records
, &mc
);
5822 WARN("Unknown chaining contextual substitution format %u.\n", format
);
5827 static BOOL
opentype_layout_apply_gsub_reverse_chain_context_substitution(struct scriptshaping_context
*context
,
5828 const struct lookup
*lookup
, unsigned int subtable_offset
)
5830 const struct dwrite_fonttable
*table
= &context
->table
->table
;
5831 unsigned int offset
= subtable_offset
;
5832 UINT16 glyph
, format
;
5834 if (context
->nesting_level_left
!= SHAPE_MAX_NESTING_LEVEL
)
5837 glyph
= context
->u
.subst
.glyphs
[context
->cur
];
5839 format
= table_read_be_word(table
, offset
);
5844 struct match_context mc
= { .context
= context
, .lookup
= lookup
};
5845 unsigned int start_index
= 0, end_index
= 0, backtrack_count
, lookahead_count
;
5846 unsigned int coverage
, coverage_index
;
5847 const UINT16
*backtrack
, *lookahead
;
5849 coverage
= table_read_be_word(table
, offset
);
5852 coverage_index
= opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
);
5853 if (coverage_index
== GLYPH_NOT_COVERED
)
5856 backtrack_count
= table_read_be_word(table
, offset
);
5859 backtrack
= table_read_ensure(table
, offset
, sizeof(*backtrack
) * backtrack_count
);
5860 offset
+= sizeof(*backtrack
) * backtrack_count
;
5862 lookahead_count
= table_read_be_word(table
, offset
);
5865 lookahead
= table_read_ensure(table
, offset
, sizeof(*lookahead
) * lookahead_count
);
5866 offset
+= sizeof(*lookahead
) * lookahead_count
;
5868 mc
.match_func
= opentype_match_coverage_func
;
5869 mc
.backtrack_offset
= subtable_offset
;
5870 mc
.lookahead_offset
= subtable_offset
;
5872 if (opentype_layout_context_match_backtrack(&mc
, backtrack_count
, backtrack
, &start_index
) &&
5873 opentype_layout_context_match_lookahead(&mc
, lookahead_count
, lookahead
, 1, &end_index
))
5875 unsigned int glyph_count
= table_read_be_word(table
, offset
);
5876 if (coverage_index
>= glyph_count
)
5880 glyph
= table_read_be_word(table
, offset
+ coverage_index
* sizeof(glyph
));
5881 opentype_layout_replace_glyph(context
, glyph
);
5887 WARN("Unknown reverse chaining contextual substitution format %u.\n", format
);
5892 static BOOL
opentype_layout_apply_gsub_lookup(struct scriptshaping_context
*context
, const struct lookup
*lookup
)
5894 unsigned int i
, lookup_type
;
5897 for (i
= 0; i
< lookup
->subtable_count
; ++i
)
5899 unsigned int subtable_offset
= opentype_layout_get_gsubgpos_subtable(context
, lookup
, i
, &lookup_type
);
5901 switch (lookup_type
)
5903 case GSUB_LOOKUP_SINGLE_SUBST
:
5904 ret
= opentype_layout_apply_gsub_single_substitution(context
, lookup
, subtable_offset
);
5906 case GSUB_LOOKUP_MULTIPLE_SUBST
:
5907 ret
= opentype_layout_apply_gsub_mult_substitution(context
, lookup
, subtable_offset
);
5909 case GSUB_LOOKUP_ALTERNATE_SUBST
:
5910 ret
= opentype_layout_apply_gsub_alt_substitution(context
, lookup
, subtable_offset
);
5912 case GSUB_LOOKUP_LIGATURE_SUBST
:
5913 ret
= opentype_layout_apply_gsub_lig_substitution(context
, lookup
, subtable_offset
);
5915 case GSUB_LOOKUP_CONTEXTUAL_SUBST
:
5916 ret
= opentype_layout_apply_context(context
, lookup
, subtable_offset
);
5918 case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST
:
5919 ret
= opentype_layout_apply_chain_context(context
, lookup
, subtable_offset
);
5921 case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST
:
5922 ret
= opentype_layout_apply_gsub_reverse_chain_context_substitution(context
, lookup
, subtable_offset
);
5924 case GSUB_LOOKUP_EXTENSION_SUBST
:
5925 WARN("Invalid lookup type for extension substitution %#x.\n", lookup_type
);
5928 WARN("Unknown lookup type %u.\n", lookup_type
);
5938 static unsigned int unicode_get_mirrored_char(unsigned int codepoint
)
5940 extern const WCHAR wine_mirror_map
[] DECLSPEC_HIDDEN
;
5942 /* TODO: check if mirroring for higher planes makes sense at all */
5943 if (codepoint
> 0xffff) return codepoint
;
5944 mirror
= get_table_entry_16(wine_mirror_map
, codepoint
);
5945 return mirror
? mirror
: codepoint
;
5949 * 034F # Mn COMBINING GRAPHEME JOINER
5950 * 061C # Cf ARABIC LETTER MARK
5951 * 180B..180D # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
5952 * 180E # Cf MONGOLIAN VOWEL SEPARATOR
5953 * 200B..200F # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
5954 * FEFF # Cf ZERO WIDTH NO-BREAK SPACE
5956 static unsigned int opentype_is_zero_width(unsigned int codepoint
)
5958 return codepoint
== 0x34f || codepoint
== 0x61c || codepoint
== 0xfeff ||
5959 (codepoint
>= 0x180b && codepoint
<= 0x180e) || (codepoint
>= 0x200b && codepoint
<= 0x200f);
5963 * 00AD # Cf SOFT HYPHEN
5964 * 034F # Mn COMBINING GRAPHEME JOINER
5965 * 061C # Cf ARABIC LETTER MARK
5966 * 115F..1160 # Lo [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER
5967 * 17B4..17B5 # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
5968 * 180B..180D # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
5969 * 180E # Cf MONGOLIAN VOWEL SEPARATOR
5970 * 200B..200F # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
5971 * 202A..202E # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
5972 * 2060..2064 # Cf [5] WORD JOINER..INVISIBLE PLUS
5973 * 2065 # Cn <reserved-2065>
5974 * 2066..206F # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
5975 * 3164 # Lo HANGUL FILLER
5976 * FE00..FE0F # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
5977 * FEFF # Cf ZERO WIDTH NO-BREAK SPACE
5978 * FFA0 # Lo HALFWIDTH HANGUL FILLER
5979 * FFF0..FFF8 # Cn [9] <reserved-FFF0>..<reserved-FFF8>
5980 * 1BCA0..1BCA3 # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
5981 * 1D173..1D17A # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
5982 * E0000 # Cn <reserved-E0000>
5983 * E0001 # Cf LANGUAGE TAG
5984 * E0002..E001F # Cn [30] <reserved-E0002>..<reserved-E001F>
5985 * E0020..E007F # Cf [96] TAG SPACE..CANCEL TAG
5986 * E0080..E00FF # Cn [128] <reserved-E0080>..<reserved-E00FF>
5987 * E0100..E01EF # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
5988 * E01F0..E0FFF # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
5990 static unsigned int opentype_is_default_ignorable(unsigned int codepoint
)
5992 if (codepoint
< 0x80) return 0;
5993 return codepoint
== 0xad ||
5994 codepoint
== 0x34f ||
5995 codepoint
== 0x61c ||
5996 (codepoint
>= 0x17b4 && codepoint
<= 0x17b5) ||
5997 (codepoint
>= 0x180b && codepoint
<= 0x180e) ||
5998 (codepoint
>= 0x200b && codepoint
<= 0x200f) ||
5999 (codepoint
>= 0x202a && codepoint
<= 0x202e) ||
6000 (codepoint
>= 0x2060 && codepoint
<= 0x206f) ||
6001 (codepoint
>= 0xfe00 && codepoint
<= 0xfe0f) ||
6002 codepoint
== 0xfeff ||
6003 (codepoint
>= 0xfff0 && codepoint
<= 0xfff8) ||
6004 (codepoint
>= 0x1d173 && codepoint
<= 0x1d17a) ||
6005 (codepoint
>= 0xe0000 && codepoint
<= 0xe0fff);
6008 static unsigned int opentype_is_diacritic(unsigned int codepoint
)
6010 WCHAR ch
= codepoint
;
6012 /* Ignore higher planes for now. */
6013 if (codepoint
> 0xffff) return 0;
6014 GetStringTypeW(CT_CTYPE3
, &ch
, 1, &type
);
6015 return !!(type
& C3_DIACRITIC
);
6018 static void opentype_get_nominal_glyphs(struct scriptshaping_context
*context
, const struct shaping_features
*features
)
6020 unsigned int rtlm_mask
= shaping_features_get_mask(features
, DWRITE_MAKE_OPENTYPE_TAG('r','t','l','m'), NULL
);
6021 const struct shaping_font_ops
*font
= context
->cache
->font
;
6022 unsigned int i
, g
, c
, codepoint
, cluster_start_idx
= 0;
6023 UINT16
*clustermap
= context
->u
.subst
.clustermap
;
6024 const WCHAR
*text
= context
->text
;
6027 memset(context
->u
.subst
.glyph_props
, 0, context
->u
.subst
.max_glyph_count
* sizeof(*context
->u
.subst
.glyph_props
));
6028 memset(context
->u
.buffer
.text_props
, 0, context
->length
* sizeof(*context
->u
.buffer
.text_props
));
6030 for (i
= 0; i
< context
->length
; ++i
)
6032 g
= context
->glyph_count
;
6034 if ((bmp
= !(IS_HIGH_SURROGATE(text
[i
]) && (i
< context
->length
- 1) && IS_LOW_SURROGATE(text
[i
+ 1]))))
6036 codepoint
= text
[i
];
6040 codepoint
= 0x10000 + ((text
[i
] - 0xd800) << 10) + (text
[i
+ 1] - 0xdc00);
6043 if (context
->is_rtl
)
6045 c
= unicode_get_mirrored_char(codepoint
);
6046 if (c
!= codepoint
&& font
->has_glyph(context
->cache
->context
, c
))
6049 context
->glyph_infos
[i
].mask
|= rtlm_mask
;
6052 /* Glyph availability is not tested for a replacement digit. */
6053 if (*context
->u
.subst
.digits
&& codepoint
>= '0' && codepoint
<= '9')
6054 codepoint
= context
->u
.subst
.digits
[codepoint
- '0'];
6056 context
->glyph_infos
[g
].codepoint
= codepoint
;
6057 context
->u
.buffer
.glyphs
[g
] = font
->get_glyph(context
->cache
->context
, codepoint
);
6058 context
->u
.buffer
.glyph_props
[g
].justification
= SCRIPT_JUSTIFY_CHARACTER
;
6059 opentype_set_subst_glyph_props(context
, g
);
6060 if (opentype_is_default_ignorable(codepoint
))
6062 context
->glyph_infos
[g
].props
|= GLYPH_PROP_IGNORABLE
;
6063 if (codepoint
== 0x200d)
6064 context
->glyph_infos
[g
].props
|= GLYPH_PROP_ZWJ
;
6065 else if (codepoint
== 0x200c)
6066 context
->glyph_infos
[g
].props
|= GLYPH_PROP_ZWNJ
;
6067 /* Mongolian FVSs, TAGs, COMBINING GRAPHEME JOINER */
6068 else if ((codepoint
>= 0x180b && codepoint
<= 0x180d) ||
6069 (codepoint
>= 0xe0020 && codepoint
<= 0xe007f) ||
6072 context
->glyph_infos
[g
].props
|= GLYPH_PROP_HIDDEN
;
6076 /* Group diacritics with preceding base. Glyph class is ignored here. */
6077 if (!g
|| !opentype_is_diacritic(codepoint
))
6079 context
->u
.buffer
.glyph_props
[g
].isClusterStart
= 1;
6080 context
->glyph_infos
[g
].start_text_idx
= i
;
6081 cluster_start_idx
= g
;
6083 if (opentype_is_zero_width(codepoint
))
6084 context
->u
.buffer
.glyph_props
[g
].isZeroWidthSpace
= 1;
6086 context
->u
.buffer
.glyph_props
[g
].components
= 1;
6087 context
->glyph_count
++;
6089 /* Set initial cluster map here, it's used for setting user features masks. */
6090 clustermap
[i
] = cluster_start_idx
;
6092 context
->u
.buffer
.text_props
[i
].canBreakShapingAfter
= 1;
6095 clustermap
[i
+ 1] = cluster_start_idx
;
6096 context
->u
.buffer
.text_props
[i
+ 1].canBreakShapingAfter
= 1;
6102 static BOOL
opentype_is_gsub_lookup_reversed(const struct scriptshaping_context
*context
, const struct lookup
*lookup
)
6104 unsigned int lookup_type
;
6106 opentype_layout_get_gsubgpos_subtable(context
, lookup
, 0, &lookup_type
);
6107 return lookup_type
== GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST
;
6110 static void opentype_layout_apply_gsub_context_lookup(struct scriptshaping_context
*context
, unsigned int lookup_index
)
6112 struct lookup lookup
= { 0 };
6113 if (opentype_layout_init_lookup(context
->table
, lookup_index
, NULL
, &lookup
))
6114 opentype_layout_apply_gsub_lookup(context
, &lookup
);
6117 void opentype_layout_apply_gsub_features(struct scriptshaping_context
*context
, unsigned int script_index
,
6118 unsigned int language_index
, struct shaping_features
*features
)
6120 struct lookups lookups
= { 0 };
6121 unsigned int i
= 0, j
, start_idx
;
6124 context
->nesting_level_left
= SHAPE_MAX_NESTING_LEVEL
;
6125 context
->u
.buffer
.apply_context_lookup
= opentype_layout_apply_gsub_context_lookup
;
6126 opentype_layout_collect_lookups(context
, script_index
, language_index
, features
, context
->table
, &lookups
);
6128 opentype_get_nominal_glyphs(context
, features
);
6129 opentype_layout_set_glyph_masks(context
, features
);
6131 for (j
= 0; j
<= features
->stage
; ++j
)
6133 for (; i
< features
->stages
[j
].last_lookup
; ++i
)
6135 const struct lookup
*lookup
= &lookups
.lookups
[i
];
6137 context
->lookup_mask
= lookup
->mask
;
6138 context
->auto_zwnj
= lookup
->auto_zwnj
;
6139 context
->auto_zwj
= lookup
->auto_zwj
;
6141 if (!opentype_is_gsub_lookup_reversed(context
, lookup
))
6144 while (context
->cur
< context
->glyph_count
)
6148 if ((context
->glyph_infos
[context
->cur
].mask
& lookup
->mask
) &&
6149 lookup_is_glyph_match(context
, context
->cur
, lookup
->flags
))
6151 ret
= opentype_layout_apply_gsub_lookup(context
, lookup
);
6160 context
->cur
= context
->glyph_count
- 1;
6164 if ((context
->glyph_infos
[context
->cur
].mask
& lookup
->mask
) &&
6165 lookup_is_glyph_match(context
, context
->cur
, lookup
->flags
))
6167 opentype_layout_apply_gsub_lookup(context
, lookup
);
6170 if (context
->cur
== 0) break;
6176 if (features
->stages
[j
].func
)
6177 features
->stages
[j
].func(context
, features
);
6180 /* For every glyph range of [<last>.isClusterStart, <next>.isClusterStart) set corresponding
6181 text span to start_idx. */
6183 for (i
= 1; i
< context
->glyph_count
; ++i
)
6185 if (context
->u
.buffer
.glyph_props
[i
].isClusterStart
)
6187 unsigned int start_text
, end_text
;
6189 start_text
= context
->glyph_infos
[start_idx
].start_text_idx
;
6190 end_text
= context
->glyph_infos
[i
].start_text_idx
;
6192 for (j
= start_text
; j
< end_text
; ++j
)
6193 context
->u
.buffer
.clustermap
[j
] = start_idx
;
6199 /* Fill the tail. */
6200 for (j
= context
->glyph_infos
[start_idx
].start_text_idx
; j
< context
->length
; ++j
)
6201 context
->u
.buffer
.clustermap
[j
] = start_idx
;
6203 free(lookups
.lookups
);
6206 static BOOL
opentype_layout_contextual_lookup_is_glyph_covered(struct scriptshaping_context
*context
, UINT16 glyph
,
6207 unsigned int subtable_offset
, unsigned int coverage
, unsigned int format
)
6209 const struct dwrite_fonttable
*table
= &context
->table
->table
;
6210 const UINT16
*offsets
;
6213 if (format
== 1 || format
== 2)
6215 if (opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
) != GLYPH_NOT_COVERED
)
6218 else if (format
== 3)
6220 count
= table_read_be_word(table
, subtable_offset
+ 2);
6221 if (!count
|| !(offsets
= table_read_ensure(table
, subtable_offset
+ 6, count
* sizeof(*offsets
))))
6224 if (opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(offsets
[0]), glyph
) != GLYPH_NOT_COVERED
)
6231 static BOOL
opentype_layout_chain_contextual_lookup_is_glyph_covered(struct scriptshaping_context
*context
, UINT16 glyph
,
6232 unsigned int subtable_offset
, unsigned int coverage
, unsigned int format
)
6234 const struct dwrite_fonttable
*table
= &context
->table
->table
;
6235 unsigned int count
, backtrack_count
;
6236 const UINT16
*offsets
;
6238 if (format
== 1 || format
== 2)
6240 if (opentype_layout_is_glyph_covered(table
, subtable_offset
+ coverage
, glyph
) != GLYPH_NOT_COVERED
)
6243 else if (format
== 3)
6245 backtrack_count
= table_read_be_word(table
, subtable_offset
+ 2);
6247 count
= table_read_be_word(table
, subtable_offset
+ 4 + backtrack_count
* sizeof(*offsets
));
6249 if (!count
|| !(offsets
= table_read_ensure(table
, subtable_offset
+ 6 + backtrack_count
* sizeof(*offsets
),
6250 count
* sizeof(*offsets
))))
6253 if (opentype_layout_is_glyph_covered(table
, subtable_offset
+ GET_BE_WORD(offsets
[0]), glyph
) != GLYPH_NOT_COVERED
)
6260 static BOOL
opentype_layout_gsub_lookup_is_glyph_covered(struct scriptshaping_context
*context
, UINT16 glyph
,
6261 const struct lookup
*lookup
)
6263 const struct dwrite_fonttable
*gsub
= &context
->table
->table
;
6264 static const unsigned short gsub_formats
[] =
6267 1, /* SingleSubst */
6268 1, /* MultipleSubst */
6269 1, /* AlternateSubst */
6270 1, /* LigatureSubst */
6271 3, /* ContextSubst */
6272 3, /* ChainContextSubst */
6273 0, /* Extension, unused */
6274 1, /* ReverseChainSubst */
6276 unsigned int i
, coverage
, lookup_type
, format
;
6278 for (i
= 0; i
< lookup
->subtable_count
; ++i
)
6280 unsigned int subtable_offset
= opentype_layout_get_gsubgpos_subtable(context
, lookup
, i
, &lookup_type
);
6282 format
= table_read_be_word(gsub
, subtable_offset
);
6284 if (!format
|| format
> ARRAY_SIZE(gsub_formats
) || format
> gsub_formats
[lookup_type
])
6287 coverage
= table_read_be_word(gsub
, subtable_offset
+ 2);
6289 switch (lookup_type
)
6291 case GSUB_LOOKUP_SINGLE_SUBST
:
6292 case GSUB_LOOKUP_MULTIPLE_SUBST
:
6293 case GSUB_LOOKUP_ALTERNATE_SUBST
:
6294 case GSUB_LOOKUP_LIGATURE_SUBST
:
6295 case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST
:
6297 if (opentype_layout_is_glyph_covered(gsub
, subtable_offset
+ coverage
, glyph
) != GLYPH_NOT_COVERED
)
6302 case GSUB_LOOKUP_CONTEXTUAL_SUBST
:
6304 if (opentype_layout_contextual_lookup_is_glyph_covered(context
, glyph
, subtable_offset
, coverage
, format
))
6309 case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST
:
6311 if (opentype_layout_chain_contextual_lookup_is_glyph_covered(context
, glyph
, subtable_offset
, coverage
, format
))
6317 WARN("Unknown lookup type %u.\n", lookup_type
);
6324 static BOOL
opentype_layout_gpos_lookup_is_glyph_covered(struct scriptshaping_context
*context
, UINT16 glyph
,
6325 const struct lookup
*lookup
)
6327 const struct dwrite_fonttable
*gpos
= &context
->table
->table
;
6328 static const unsigned short gpos_formats
[] =
6334 1, /* MarkBasePos */
6336 1, /* MarkMarkPos */
6338 3, /* ChainContextPos */
6339 0, /* Extension, unused */
6341 unsigned int i
, coverage
, lookup_type
, format
;
6343 for (i
= 0; i
< lookup
->subtable_count
; ++i
)
6345 unsigned int subtable_offset
= opentype_layout_get_gsubgpos_subtable(context
, lookup
, i
, &lookup_type
);
6347 format
= table_read_be_word(gpos
, subtable_offset
);
6349 if (!format
|| format
> ARRAY_SIZE(gpos_formats
) || format
> gpos_formats
[lookup_type
])
6352 coverage
= table_read_be_word(gpos
, subtable_offset
+ 2);
6354 switch (lookup_type
)
6356 case GPOS_LOOKUP_SINGLE_ADJUSTMENT
:
6357 case GPOS_LOOKUP_PAIR_ADJUSTMENT
:
6358 case GPOS_LOOKUP_CURSIVE_ATTACHMENT
:
6359 case GPOS_LOOKUP_MARK_TO_BASE_ATTACHMENT
:
6360 case GPOS_LOOKUP_MARK_TO_LIGATURE_ATTACHMENT
:
6361 case GPOS_LOOKUP_MARK_TO_MARK_ATTACHMENT
:
6363 if (opentype_layout_is_glyph_covered(gpos
, subtable_offset
+ coverage
, glyph
) != GLYPH_NOT_COVERED
)
6368 case GPOS_LOOKUP_CONTEXTUAL_POSITION
:
6370 if (opentype_layout_contextual_lookup_is_glyph_covered(context
, glyph
, subtable_offset
, coverage
, format
))
6375 case GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION
:
6377 if (opentype_layout_chain_contextual_lookup_is_glyph_covered(context
, glyph
, subtable_offset
, coverage
, format
))
6383 WARN("Unknown lookup type %u.\n", lookup_type
);
6390 typedef BOOL (*p_lookup_is_glyph_covered_func
)(struct scriptshaping_context
*context
, UINT16 glyph
, const struct lookup
*lookup
);
6392 BOOL
opentype_layout_check_feature(struct scriptshaping_context
*context
, unsigned int script_index
,
6393 unsigned int language_index
, struct shaping_feature
*feature
, unsigned int glyph_count
,
6394 const UINT16
*glyphs
, UINT8
*feature_applies
)
6396 p_lookup_is_glyph_covered_func func_is_covered
;
6397 struct shaping_features features
= { 0 };
6398 struct lookups lookups
= { 0 };
6399 BOOL ret
= FALSE
, is_covered
;
6400 unsigned int i
, j
, applies
;
6402 features
.features
= feature
;
6405 for (i
= 0; i
< context
->glyph_count
; ++i
)
6406 opentype_set_glyph_props(context
, i
);
6408 opentype_layout_collect_lookups(context
, script_index
, language_index
, &features
, context
->table
, &lookups
);
6410 func_is_covered
= opentype_layout_is_subst_context(context
) ? opentype_layout_gsub_lookup_is_glyph_covered
:
6411 opentype_layout_gpos_lookup_is_glyph_covered
;
6413 for (i
= 0; i
< lookups
.count
; ++i
)
6415 struct lookup
*lookup
= &lookups
.lookups
[i
];
6418 for (j
= 0; j
< context
->glyph_count
; ++j
)
6420 if (lookup_is_glyph_match(context
, j
, lookup
->flags
))
6422 if ((is_covered
= func_is_covered(context
, glyphs
[i
], lookup
)))
6424 feature_applies
[j
] |= is_covered
;
6428 if ((ret
= (applies
== context
->glyph_count
)))
6432 free(lookups
.lookups
);
6437 BOOL
opentype_has_vertical_variants(struct dwrite_fontface
*fontface
)
6439 unsigned int i
, j
, count
= 0, lookup_type
, subtable_offset
;
6440 struct shaping_features features
= { 0 };
6441 struct shaping_feature vert_feature
= { 0 };
6442 struct scriptshaping_context context
= { 0 };
6443 struct lookups lookups
= { 0 };
6446 if (fontface
->flags
& (FONTFACE_VERTICAL_VARIANTS
| FONTFACE_NO_VERTICAL_VARIANTS
))
6447 return !!(fontface
->flags
& FONTFACE_VERTICAL_VARIANTS
);
6449 context
.cache
= fontface_get_shaping_cache(fontface
);
6450 context
.table
= &context
.cache
->gsub
;
6452 vert_feature
.tag
= DWRITE_MAKE_OPENTYPE_TAG('v','e','r','t');
6453 vert_feature
.flags
= FEATURE_GLOBAL
| FEATURE_GLOBAL_SEARCH
;
6454 vert_feature
.max_value
= 1;
6455 vert_feature
.default_value
= 1;
6457 features
.features
= &vert_feature
;
6458 features
.count
= features
.capacity
= 1;
6460 opentype_layout_collect_lookups(&context
, ~0u, ~0u, &features
, context
.table
, &lookups
);
6462 for (i
= 0; i
< lookups
.count
&& !count
; ++i
)
6464 const struct dwrite_fonttable
*table
= &context
.table
->table
;
6465 const struct lookup
*lookup
= &lookups
.lookups
[i
];
6467 for (j
= 0; j
< lookup
->subtable_count
&& !count
; ++j
)
6469 subtable_offset
= opentype_layout_get_gsubgpos_subtable(&context
, lookup
, j
, &lookup_type
);
6471 if (lookup_type
!= GSUB_LOOKUP_SINGLE_SUBST
)
6474 format
= table_read_be_word(table
, subtable_offset
);
6480 else if (format
== 2)
6482 count
= table_read_be_word(table
, subtable_offset
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format2
, count
));
6485 WARN("Unrecognized single substitution format %u.\n", format
);
6489 free(lookups
.lookups
);
6492 fontface
->flags
|= FONTFACE_VERTICAL_VARIANTS
;
6494 fontface
->flags
|= FONTFACE_NO_VERTICAL_VARIANTS
;
6496 return !!(fontface
->flags
& FONTFACE_VERTICAL_VARIANTS
);
6499 HRESULT
opentype_get_vertical_glyph_variants(struct dwrite_fontface
*fontface
, unsigned int glyph_count
,
6500 const UINT16
*nominal_glyphs
, UINT16
*glyphs
)
6502 struct shaping_features features
= { 0 };
6503 struct shaping_feature vert_feature
= { 0 };
6504 struct scriptshaping_context context
= { 0 };
6505 struct lookups lookups
= { 0 };
6508 memcpy(glyphs
, nominal_glyphs
, glyph_count
* sizeof(*glyphs
));
6510 if (!opentype_has_vertical_variants(fontface
))
6513 context
.cache
= fontface_get_shaping_cache(fontface
);
6514 context
.u
.subst
.glyphs
= glyphs
;
6515 context
.u
.subst
.glyph_props
= calloc(glyph_count
, sizeof(*context
.u
.subst
.glyph_props
));
6516 context
.u
.subst
.max_glyph_count
= glyph_count
;
6517 context
.u
.subst
.capacity
= glyph_count
;
6518 context
.glyph_infos
= calloc(glyph_count
, sizeof(*context
.glyph_infos
));
6519 context
.table
= &context
.cache
->gsub
;
6521 vert_feature
.tag
= DWRITE_MAKE_OPENTYPE_TAG('v','e','r','t');
6522 vert_feature
.flags
= FEATURE_GLOBAL
| FEATURE_GLOBAL_SEARCH
;
6523 vert_feature
.max_value
= 1;
6524 vert_feature
.default_value
= 1;
6526 features
.features
= &vert_feature
;
6527 features
.count
= features
.capacity
= 1;
6529 opentype_layout_collect_lookups(&context
, ~0u, ~0u, &features
, context
.table
, &lookups
);
6530 opentype_layout_set_glyph_masks(&context
, &features
);
6532 for (i
= 0; i
< lookups
.count
; ++i
)
6534 const struct lookup
*lookup
= &lookups
.lookups
[i
];
6537 while (context
.cur
< context
.glyph_count
)
6541 if (lookup_is_glyph_match(&context
, context
.cur
, lookup
->flags
))
6542 ret
= opentype_layout_apply_gsub_lookup(&context
, lookup
);
6549 free(context
.u
.subst
.glyph_props
);
6550 free(context
.glyph_infos
);
6551 free(lookups
.lookups
);
6556 BOOL
opentype_has_kerning_pairs(struct dwrite_fontface
*fontface
)
6558 const struct kern_subtable_header
*subtable
;
6559 struct file_stream_desc stream_desc
;
6560 const struct kern_header
*header
;
6561 unsigned int offset
, count
, i
;
6563 if (fontface
->flags
& (FONTFACE_KERNING_PAIRS
| FONTFACE_NO_KERNING_PAIRS
))
6564 return !!(fontface
->flags
& FONTFACE_KERNING_PAIRS
);
6566 fontface
->flags
|= FONTFACE_NO_KERNING_PAIRS
;
6568 stream_desc
.stream
= fontface
->stream
;
6569 stream_desc
.face_type
= fontface
->type
;
6570 stream_desc
.face_index
= fontface
->index
;
6572 opentype_get_font_table(&stream_desc
, MS_KERN_TAG
, &fontface
->kern
);
6573 if (fontface
->kern
.exists
)
6575 if ((header
= table_read_ensure(&fontface
->kern
, 0, sizeof(*header
))))
6577 count
= GET_BE_WORD(header
->table_count
);
6578 offset
= sizeof(*header
);
6580 /* FreeType limits table count this way. */
6581 count
= min(count
, 32);
6583 /* Check for presence of format 0 subtable with horizontal coverage. */
6584 for (i
= 0; i
< count
; ++i
)
6586 if (!(subtable
= table_read_ensure(&fontface
->kern
, offset
, sizeof(*subtable
))))
6589 if (subtable
->version
== 0 && GET_BE_WORD(subtable
->coverage
) & 1)
6591 fontface
->flags
&= ~FONTFACE_NO_KERNING_PAIRS
;
6592 fontface
->flags
|= FONTFACE_KERNING_PAIRS
;
6596 offset
+= GET_BE_WORD(subtable
->length
);
6601 if (fontface
->flags
& FONTFACE_NO_KERNING_PAIRS
&& fontface
->kern
.data
)
6602 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
.stream
, fontface
->kern
.context
);
6604 return !!(fontface
->flags
& FONTFACE_KERNING_PAIRS
);
6607 struct kern_format0_compare_key
6613 static int __cdecl
kern_format0_compare(const void *a
, const void *b
)
6615 const struct kern_format0_compare_key
*key
= a
;
6616 const WORD
*data
= b
;
6617 UINT16 left
= GET_BE_WORD(data
[0]), right
= GET_BE_WORD(data
[1]);
6620 if ((ret
= (int)key
->left
- (int)left
)) return ret
;
6621 if ((ret
= (int)key
->right
- (int)right
)) return ret
;
6625 HRESULT
opentype_get_kerning_pairs(struct dwrite_fontface
*fontface
, unsigned int count
,
6626 const UINT16
*glyphs
, INT32
*values
)
6628 const struct kern_subtable_header
*subtable
;
6629 unsigned int i
, s
, offset
, pair_count
, subtable_count
;
6630 struct kern_format0_compare_key key
;
6631 const struct kern_header
*header
;
6634 if (!opentype_has_kerning_pairs(fontface
))
6636 memset(values
, 0, count
* sizeof(*values
));
6640 subtable_count
= table_read_be_word(&fontface
->kern
, 2);
6641 subtable_count
= min(subtable_count
, 32);
6643 for (i
= 0; i
< count
- 1; ++i
)
6645 offset
= sizeof(*header
);
6647 key
.left
= glyphs
[i
];
6648 key
.right
= glyphs
[i
+ 1];
6651 for (s
= 0; s
< subtable_count
; ++s
)
6653 if (!(subtable
= table_read_ensure(&fontface
->kern
, offset
, sizeof(*subtable
))))
6656 if (subtable
->version
== 0 && GET_BE_WORD(subtable
->coverage
) & 1)
6658 if ((data
= table_read_ensure(&fontface
->kern
, offset
, GET_BE_WORD(subtable
->length
))))
6660 /* Skip subtable header */
6662 pair_count
= GET_BE_WORD(*data
);
6664 /* Move to pair data */
6665 if ((data
= table_read_ensure(&fontface
->kern
, offset
+ 7 * sizeof(*data
),
6666 pair_count
* 3 * sizeof(*data
))))
6668 if ((data
= bsearch(&key
, data
, pair_count
, 3 * sizeof(*data
), kern_format0_compare
)))
6670 values
[i
] = (short)GET_BE_WORD(data
[2]);
6677 offset
+= GET_BE_WORD(subtable
->length
);
6680 values
[count
- 1] = 0;
6685 static void opentype_font_var_add_static_axis(struct dwrite_var_axis
**axis
, unsigned int *axis_count
,
6686 unsigned int tag
, float value
)
6688 struct dwrite_var_axis
*entry
= &(*axis
)[(*axis_count
)++];
6690 entry
->min_value
= entry
->max_value
= entry
->default_value
= value
;
6691 entry
->attributes
= 0;
6694 HRESULT
opentype_get_font_var_axis(const struct file_stream_desc
*stream_desc
, struct dwrite_var_axis
**axis
,
6695 unsigned int *axis_count
)
6697 static const float width_axis_values
[] =
6699 0.0f
, /* DWRITE_FONT_STRETCH_UNDEFINED */
6700 50.0f
, /* DWRITE_FONT_STRETCH_ULTRA_CONDENSED */
6701 62.5f
, /* DWRITE_FONT_STRETCH_EXTRA_CONDENSED */
6702 75.0f
, /* DWRITE_FONT_STRETCH_CONDENSED */
6703 87.5f
, /* DWRITE_FONT_STRETCH_SEMI_CONDENSED */
6704 100.0f
, /* DWRITE_FONT_STRETCH_NORMAL */
6705 112.5f
, /* DWRITE_FONT_STRETCH_SEMI_EXPANDED */
6706 125.0f
, /* DWRITE_FONT_STRETCH_EXPANDED */
6707 150.0f
, /* DWRITE_FONT_STRETCH_EXTRA_EXPANDED */
6708 200.0f
, /* DWRITE_FONT_STRETCH_ULTRA_EXPANDED */
6710 BOOL has_wght
= FALSE
, has_wdth
= FALSE
, has_slnt
= FALSE
, has_ital
= FALSE
;
6711 const struct var_axis_record
*records
;
6712 const struct fvar_header
*header
;
6713 unsigned int i
, count
, tag
, size
;
6714 struct dwrite_font_props props
;
6715 struct dwrite_fonttable fvar
;
6721 opentype_get_font_table(stream_desc
, MS_FVAR_TAG
, &fvar
);
6723 if (!(header
= table_read_ensure(&fvar
, 0, sizeof(*header
)))) goto done
;
6724 if (!(GET_BE_WORD(header
->major_version
) == 1 && GET_BE_WORD(header
->minor_version
) == 0))
6726 WARN("Unexpected fvar version.\n");
6730 count
= GET_BE_WORD(header
->axis_count
);
6731 size
= GET_BE_WORD(header
->axis_size
);
6733 if (!count
|| size
!= sizeof(*records
)) goto done
;
6734 if (!(records
= table_read_ensure(&fvar
, GET_BE_WORD(header
->axes_array_offset
), size
* count
))) goto done
;
6736 if (!(*axis
= calloc(count
+ 4, sizeof(**axis
))))
6742 for (i
= 0; i
< count
; ++i
)
6744 (*axis
)[i
].tag
= tag
= records
[i
].tag
;
6745 (*axis
)[i
].default_value
= GET_BE_FIXED(records
[i
].default_value
);
6746 (*axis
)[i
].min_value
= GET_BE_FIXED(records
[i
].min_value
);
6747 (*axis
)[i
].max_value
= GET_BE_FIXED(records
[i
].max_value
);
6748 if (GET_BE_WORD(records
[i
].flags
& 0x1))
6749 (*axis
)[i
].attributes
|= DWRITE_FONT_AXIS_ATTRIBUTES_HIDDEN
;
6750 /* FIXME: set DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE */
6752 if (tag
== DWRITE_FONT_AXIS_TAG_WEIGHT
) has_wght
= TRUE
;
6753 if (tag
== DWRITE_FONT_AXIS_TAG_WIDTH
) has_wdth
= TRUE
;
6754 if (tag
== DWRITE_FONT_AXIS_TAG_SLANT
) has_slnt
= TRUE
;
6755 if (tag
== DWRITE_FONT_AXIS_TAG_ITALIC
) has_ital
= TRUE
;
6758 if (!has_wght
|| !has_wdth
|| !has_slnt
|| !has_ital
)
6760 opentype_get_font_properties(stream_desc
, &props
);
6761 if (!has_wght
) opentype_font_var_add_static_axis(axis
, &count
, DWRITE_FONT_AXIS_TAG_WEIGHT
, props
.weight
);
6762 if (!has_ital
) opentype_font_var_add_static_axis(axis
, &count
, DWRITE_FONT_AXIS_TAG_ITALIC
,
6763 props
.style
== DWRITE_FONT_STYLE_ITALIC
? 1.0f
: 0.0f
);
6764 if (!has_wdth
) opentype_font_var_add_static_axis(axis
, &count
, DWRITE_FONT_AXIS_TAG_WIDTH
,
6765 width_axis_values
[props
.stretch
]);
6766 if (!has_slnt
) opentype_font_var_add_static_axis(axis
, &count
, DWRITE_FONT_AXIS_TAG_SLANT
, props
.slant_angle
);
6769 *axis_count
= count
;
6773 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, fvar
.context
);