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
24 #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_GPOS_TAG DWRITE_MAKE_OPENTYPE_TAG('G','P','O','S')
36 #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B')
37 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
38 #define MS_GLYF_TAG DWRITE_MAKE_OPENTYPE_TAG('g','l','y','f')
39 #define MS_CFF__TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F',' ')
40 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
41 #define MS_SVG__TAG DWRITE_MAKE_OPENTYPE_TAG('S','V','G',' ')
42 #define MS_SBIX_TAG DWRITE_MAKE_OPENTYPE_TAG('s','b','i','x')
43 #define MS_MAXP_TAG DWRITE_MAKE_OPENTYPE_TAG('m','a','x','p')
46 #define MS_PNG__TAG DWRITE_MAKE_OPENTYPE_TAG('p','n','g',' ')
47 #define MS_JPG__TAG DWRITE_MAKE_OPENTYPE_TAG('j','p','g',' ')
48 #define MS_TIFF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','i','f','f')
50 #ifdef WORDS_BIGENDIAN
51 #define GET_BE_WORD(x) (x)
52 #define GET_BE_DWORD(x) (x)
54 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
55 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
84 } CMAP_EncodingRecord
;
89 CMAP_EncodingRecord tables
[1];
96 } CMAP_SegmentedCoverage_group
;
104 CMAP_SegmentedCoverage_group groups
[1];
105 } CMAP_SegmentedCoverage
;
116 } CMAP_SegmentMapping_0
;
118 enum OPENTYPE_CMAP_TABLE_FORMAT
120 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
= 4,
121 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
= 12
124 /* PANOSE is 10 bytes in size, need to pack the structure properly */
125 #include "pshpack2.h"
142 USHORT lowestRecPPEM
;
143 SHORT direction_hint
;
145 SHORT glyphdata_format
;
148 enum TT_HEAD_MACSTYLE
150 TT_HEAD_MACSTYLE_BOLD
= 1 << 0,
151 TT_HEAD_MACSTYLE_ITALIC
= 1 << 1,
152 TT_HEAD_MACSTYLE_UNDERLINE
= 1 << 2,
153 TT_HEAD_MACSTYLE_OUTLINE
= 1 << 3,
154 TT_HEAD_MACSTYLE_SHADOW
= 1 << 4,
155 TT_HEAD_MACSTYLE_CONDENSED
= 1 << 5,
156 TT_HEAD_MACSTYLE_EXTENDED
= 1 << 6,
163 SHORT underlinePosition
;
164 SHORT underlineThickness
;
176 USHORT usWeightClass
;
179 SHORT ySubscriptXSize
;
180 SHORT ySubscriptYSize
;
181 SHORT ySubscriptXOffset
;
182 SHORT ySubscriptYOffset
;
183 SHORT ySuperscriptXSize
;
184 SHORT ySuperscriptYSize
;
185 SHORT ySuperscriptXOffset
;
186 SHORT ySuperscriptYOffset
;
187 SHORT yStrikeoutSize
;
188 SHORT yStrikeoutPosition
;
191 ULONG ulUnicodeRange1
;
192 ULONG ulUnicodeRange2
;
193 ULONG ulUnicodeRange3
;
194 ULONG ulUnicodeRange4
;
197 USHORT usFirstCharIndex
;
198 USHORT usLastCharIndex
;
199 /* According to the Apple spec, original version didn't have the below fields,
200 * version numbers were taken from the OpenType spec.
202 /* version 0 (TrueType 1.5) */
203 USHORT sTypoAscender
;
204 USHORT sTypoDescender
;
208 /* version 1 (TrueType 1.66) */
209 ULONG ulCodePageRange1
;
210 ULONG ulCodePageRange2
;
211 /* version 2 (OpenType 1.2) */
214 USHORT usDefaultChar
;
225 USHORT advanceWidthMax
;
226 SHORT minLeftSideBearing
;
227 SHORT minRightSideBearing
;
229 SHORT caretSlopeRise
;
233 SHORT metricDataFormat
;
234 USHORT numberOfHMetrics
;
241 DWORD strikeOffset
[1];
247 DWORD glyphDataOffsets
[1];
264 enum OS2_FSSELECTION
{
265 OS2_FSSELECTION_ITALIC
= 1 << 0,
266 OS2_FSSELECTION_UNDERSCORE
= 1 << 1,
267 OS2_FSSELECTION_NEGATIVE
= 1 << 2,
268 OS2_FSSELECTION_OUTLINED
= 1 << 3,
269 OS2_FSSELECTION_STRIKEOUT
= 1 << 4,
270 OS2_FSSELECTION_BOLD
= 1 << 5,
271 OS2_FSSELECTION_REGULAR
= 1 << 6,
272 OS2_FSSELECTION_USE_TYPO_METRICS
= 1 << 7,
273 OS2_FSSELECTION_WWS
= 1 << 8,
274 OS2_FSSELECTION_OBLIQUE
= 1 << 9
290 TT_NameRecord nameRecord
[1];
329 OT_FeatureRecord FeatureRecord
[1];
333 WORD LookupOrder
; /* Reserved */
334 WORD ReqFeatureIndex
;
336 WORD FeatureIndex
[1];
347 OT_LangSysRecord LangSysRecord
[1];
357 OT_ScriptRecord ScriptRecord
[1];
367 enum OPENTYPE_PLATFORM_ID
369 OPENTYPE_PLATFORM_UNICODE
= 0,
370 OPENTYPE_PLATFORM_MAC
,
371 OPENTYPE_PLATFORM_ISO
,
372 OPENTYPE_PLATFORM_WIN
,
373 OPENTYPE_PLATFORM_CUSTOM
379 WORD LookupListIndex
[1];
398 } GSUB_SingleSubstFormat1
;
405 } GSUB_SingleSubstFormat2
;
409 WORD ExtensionLookupType
;
410 DWORD ExtensionOffset
;
411 } GSUB_ExtensionPosFormat1
;
413 enum OPENTYPE_GPOS_LOOKUPS
415 OPENTYPE_GPOS_SINGLE_SUBST
= 1,
416 OPENTYPE_GPOS_EXTENSION_SUBST
= 7
419 enum TT_NAME_WINDOWS_ENCODING_ID
421 TT_NAME_WINDOWS_ENCODING_SYMBOL
= 0,
422 TT_NAME_WINDOWS_ENCODING_UCS2
,
423 TT_NAME_WINDOWS_ENCODING_SJIS
,
424 TT_NAME_WINDOWS_ENCODING_PRC
,
425 TT_NAME_WINDOWS_ENCODING_BIG5
,
426 TT_NAME_WINDOWS_ENCODING_WANSUNG
,
427 TT_NAME_WINDOWS_ENCODING_JOHAB
,
428 TT_NAME_WINDOWS_ENCODING_RESERVED1
,
429 TT_NAME_WINDOWS_ENCODING_RESERVED2
,
430 TT_NAME_WINDOWS_ENCODING_RESERVED3
,
431 TT_NAME_WINDOWS_ENCODING_UCS4
434 enum TT_NAME_MAC_ENCODING_ID
436 TT_NAME_MAC_ENCODING_ROMAN
= 0,
437 TT_NAME_MAC_ENCODING_JAPANESE
,
438 TT_NAME_MAC_ENCODING_TRAD_CHINESE
,
439 TT_NAME_MAC_ENCODING_KOREAN
,
440 TT_NAME_MAC_ENCODING_ARABIC
,
441 TT_NAME_MAC_ENCODING_HEBREW
,
442 TT_NAME_MAC_ENCODING_GREEK
,
443 TT_NAME_MAC_ENCODING_RUSSIAN
,
444 TT_NAME_MAC_ENCODING_RSYMBOL
,
445 TT_NAME_MAC_ENCODING_DEVANAGARI
,
446 TT_NAME_MAC_ENCODING_GURMUKHI
,
447 TT_NAME_MAC_ENCODING_GUJARATI
,
448 TT_NAME_MAC_ENCODING_ORIYA
,
449 TT_NAME_MAC_ENCODING_BENGALI
,
450 TT_NAME_MAC_ENCODING_TAMIL
,
451 TT_NAME_MAC_ENCODING_TELUGU
,
452 TT_NAME_MAC_ENCODING_KANNADA
,
453 TT_NAME_MAC_ENCODING_MALAYALAM
,
454 TT_NAME_MAC_ENCODING_SINHALESE
,
455 TT_NAME_MAC_ENCODING_BURMESE
,
456 TT_NAME_MAC_ENCODING_KHMER
,
457 TT_NAME_MAC_ENCODING_THAI
,
458 TT_NAME_MAC_ENCODING_LAOTIAN
,
459 TT_NAME_MAC_ENCODING_GEORGIAN
,
460 TT_NAME_MAC_ENCODING_ARMENIAN
,
461 TT_NAME_MAC_ENCODING_SIMPL_CHINESE
,
462 TT_NAME_MAC_ENCODING_TIBETAN
,
463 TT_NAME_MAC_ENCODING_MONGOLIAN
,
464 TT_NAME_MAC_ENCODING_GEEZ
,
465 TT_NAME_MAC_ENCODING_SLAVIC
,
466 TT_NAME_MAC_ENCODING_VIETNAMESE
,
467 TT_NAME_MAC_ENCODING_SINDHI
,
468 TT_NAME_MAC_ENCODING_UNINTERPRETED
471 enum TT_NAME_MAC_LANGUAGE_ID
473 TT_NAME_MAC_LANGID_ENGLISH
= 0,
474 TT_NAME_MAC_LANGID_FRENCH
,
475 TT_NAME_MAC_LANGID_GERMAN
,
476 TT_NAME_MAC_LANGID_ITALIAN
,
477 TT_NAME_MAC_LANGID_DUTCH
,
478 TT_NAME_MAC_LANGID_SWEDISH
,
479 TT_NAME_MAC_LANGID_SPANISH
,
480 TT_NAME_MAC_LANGID_DANISH
,
481 TT_NAME_MAC_LANGID_PORTUGUESE
,
482 TT_NAME_MAC_LANGID_NORWEGIAN
,
483 TT_NAME_MAC_LANGID_HEBREW
,
484 TT_NAME_MAC_LANGID_JAPANESE
,
485 TT_NAME_MAC_LANGID_ARABIC
,
486 TT_NAME_MAC_LANGID_FINNISH
,
487 TT_NAME_MAC_LANGID_GREEK
,
488 TT_NAME_MAC_LANGID_ICELANDIC
,
489 TT_NAME_MAC_LANGID_MALTESE
,
490 TT_NAME_MAC_LANGID_TURKISH
,
491 TT_NAME_MAC_LANGID_CROATIAN
,
492 TT_NAME_MAC_LANGID_TRAD_CHINESE
,
493 TT_NAME_MAC_LANGID_URDU
,
494 TT_NAME_MAC_LANGID_HINDI
,
495 TT_NAME_MAC_LANGID_THAI
,
496 TT_NAME_MAC_LANGID_KOREAN
,
497 TT_NAME_MAC_LANGID_LITHUANIAN
,
498 TT_NAME_MAC_LANGID_POLISH
,
499 TT_NAME_MAC_LANGID_HUNGARIAN
,
500 TT_NAME_MAC_LANGID_ESTONIAN
,
501 TT_NAME_MAC_LANGID_LATVIAN
,
502 TT_NAME_MAC_LANGID_SAMI
,
503 TT_NAME_MAC_LANGID_FAROESE
,
504 TT_NAME_MAC_LANGID_FARSI
,
505 TT_NAME_MAC_LANGID_RUSSIAN
,
506 TT_NAME_MAC_LANGID_SIMPL_CHINESE
,
507 TT_NAME_MAC_LANGID_FLEMISH
,
508 TT_NAME_MAC_LANGID_GAELIC
,
509 TT_NAME_MAC_LANGID_ALBANIAN
,
510 TT_NAME_MAC_LANGID_ROMANIAN
,
511 TT_NAME_MAC_LANGID_CZECH
,
512 TT_NAME_MAC_LANGID_SLOVAK
,
513 TT_NAME_MAC_LANGID_SLOVENIAN
,
514 TT_NAME_MAC_LANGID_YIDDISH
,
515 TT_NAME_MAC_LANGID_SERBIAN
,
516 TT_NAME_MAC_LANGID_MACEDONIAN
,
517 TT_NAME_MAC_LANGID_BULGARIAN
,
518 TT_NAME_MAC_LANGID_UKRAINIAN
,
519 TT_NAME_MAC_LANGID_BYELORUSSIAN
,
520 TT_NAME_MAC_LANGID_UZBEK
,
521 TT_NAME_MAC_LANGID_KAZAKH
,
522 TT_NAME_MAC_LANGID_AZERB_CYR
,
523 TT_NAME_MAC_LANGID_AZERB_ARABIC
,
524 TT_NAME_MAC_LANGID_ARMENIAN
,
525 TT_NAME_MAC_LANGID_GEORGIAN
,
526 TT_NAME_MAC_LANGID_MOLDAVIAN
,
527 TT_NAME_MAC_LANGID_KIRGHIZ
,
528 TT_NAME_MAC_LANGID_TAJIKI
,
529 TT_NAME_MAC_LANGID_TURKMEN
,
530 TT_NAME_MAC_LANGID_MONGOLIAN
,
531 TT_NAME_MAC_LANGID_MONGOLIAN_CYR
,
532 TT_NAME_MAC_LANGID_PASHTO
,
533 TT_NAME_MAC_LANGID_KURDISH
,
534 TT_NAME_MAC_LANGID_KASHMIRI
,
535 TT_NAME_MAC_LANGID_SINDHI
,
536 TT_NAME_MAC_LANGID_TIBETAN
,
537 TT_NAME_MAC_LANGID_NEPALI
,
538 TT_NAME_MAC_LANGID_SANSKRIT
,
539 TT_NAME_MAC_LANGID_MARATHI
,
540 TT_NAME_MAC_LANGID_BENGALI
,
541 TT_NAME_MAC_LANGID_ASSAMESE
,
542 TT_NAME_MAC_LANGID_GUJARATI
,
543 TT_NAME_MAC_LANGID_PUNJABI
,
544 TT_NAME_MAC_LANGID_ORIYA
,
545 TT_NAME_MAC_LANGID_MALAYALAM
,
546 TT_NAME_MAC_LANGID_KANNADA
,
547 TT_NAME_MAC_LANGID_TAMIL
,
548 TT_NAME_MAC_LANGID_TELUGU
,
549 TT_NAME_MAC_LANGID_SINHALESE
,
550 TT_NAME_MAC_LANGID_BURMESE
,
551 TT_NAME_MAC_LANGID_KHMER
,
552 TT_NAME_MAC_LANGID_LAO
,
553 TT_NAME_MAC_LANGID_VIETNAMESE
,
554 TT_NAME_MAC_LANGID_INDONESIAN
,
555 TT_NAME_MAC_LANGID_TAGALOG
,
556 TT_NAME_MAC_LANGID_MALAY_ROMAN
,
557 TT_NAME_MAC_LANGID_MALAY_ARABIC
,
558 TT_NAME_MAC_LANGID_AMHARIC
,
559 TT_NAME_MAC_LANGID_TIGRINYA
,
560 TT_NAME_MAC_LANGID_GALLA
,
561 TT_NAME_MAC_LANGID_SOMALI
,
562 TT_NAME_MAC_LANGID_SWAHILI
,
563 TT_NAME_MAC_LANGID_KINYARWANDA
,
564 TT_NAME_MAC_LANGID_RUNDI
,
565 TT_NAME_MAC_LANGID_NYANJA
,
566 TT_NAME_MAC_LANGID_MALAGASY
,
567 TT_NAME_MAC_LANGID_ESPERANTO
,
568 TT_NAME_MAC_LANGID_WELSH
= 128,
569 TT_NAME_MAC_LANGID_BASQUE
,
570 TT_NAME_MAC_LANGID_CATALAN
,
571 TT_NAME_MAC_LANGID_LATIN
,
572 TT_NAME_MAC_LANGID_QUECHUA
,
573 TT_NAME_MAC_LANGID_GUARANI
,
574 TT_NAME_MAC_LANGID_AYMARA
,
575 TT_NAME_MAC_LANGID_TATAR
,
576 TT_NAME_MAC_LANGID_UIGHUR
,
577 TT_NAME_MAC_LANGID_DZONGKHA
,
578 TT_NAME_MAC_LANGID_JAVANESE
,
579 TT_NAME_MAC_LANGID_SUNDANESE
,
580 TT_NAME_MAC_LANGID_GALICIAN
,
581 TT_NAME_MAC_LANGID_AFRIKAANS
,
582 TT_NAME_MAC_LANGID_BRETON
,
583 TT_NAME_MAC_LANGID_INUKTITUT
,
584 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC
,
585 TT_NAME_MAC_LANGID_MANX_GAELIC
,
586 TT_NAME_MAC_LANGID_IRISH_GAELIC
,
587 TT_NAME_MAC_LANGID_TONGAN
,
588 TT_NAME_MAC_LANGID_GREEK_POLYTONIC
,
589 TT_NAME_MAC_LANGID_GREENLANDIC
,
590 TT_NAME_MAC_LANGID_AZER_ROMAN
593 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
594 static const char name_mac_langid_to_locale
[][10] = {
748 enum OPENTYPE_STRING_ID
750 OPENTYPE_STRING_COPYRIGHT_NOTICE
= 0,
751 OPENTYPE_STRING_FAMILY_NAME
,
752 OPENTYPE_STRING_SUBFAMILY_NAME
,
753 OPENTYPE_STRING_UNIQUE_IDENTIFIER
,
754 OPENTYPE_STRING_FULL_FONTNAME
,
755 OPENTYPE_STRING_VERSION_STRING
,
756 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
757 OPENTYPE_STRING_TRADEMARK
,
758 OPENTYPE_STRING_MANUFACTURER
,
759 OPENTYPE_STRING_DESIGNER
,
760 OPENTYPE_STRING_DESCRIPTION
,
761 OPENTYPE_STRING_VENDOR_URL
,
762 OPENTYPE_STRING_DESIGNER_URL
,
763 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
764 OPENTYPE_STRING_LICENSE_INFO_URL
,
765 OPENTYPE_STRING_RESERVED_ID15
,
766 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
767 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
768 OPENTYPE_STRING_COMPATIBLE_FULLNAME
,
769 OPENTYPE_STRING_SAMPLE_TEXT
,
770 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
771 OPENTYPE_STRING_WWS_FAMILY_NAME
,
772 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
775 static const UINT16 dwriteid_to_opentypeid
[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME
+1] =
777 (UINT16
)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
778 OPENTYPE_STRING_COPYRIGHT_NOTICE
,
779 OPENTYPE_STRING_VERSION_STRING
,
780 OPENTYPE_STRING_TRADEMARK
,
781 OPENTYPE_STRING_MANUFACTURER
,
782 OPENTYPE_STRING_DESIGNER
,
783 OPENTYPE_STRING_DESIGNER_URL
,
784 OPENTYPE_STRING_DESCRIPTION
,
785 OPENTYPE_STRING_VENDOR_URL
,
786 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
787 OPENTYPE_STRING_LICENSE_INFO_URL
,
788 OPENTYPE_STRING_FAMILY_NAME
,
789 OPENTYPE_STRING_SUBFAMILY_NAME
,
790 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
791 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
792 OPENTYPE_STRING_SAMPLE_TEXT
,
793 OPENTYPE_STRING_FULL_FONTNAME
,
794 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
795 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
802 USHORT numPaletteEntries
;
804 USHORT numColorRecords
;
805 ULONG offsetFirstColorRecord
;
806 USHORT colorRecordIndices
[1];
809 /* for version == 1, this comes after full CPAL_Header_0 */
810 struct CPAL_SubHeader_1
812 ULONG offsetPaletteTypeArray
;
813 ULONG offsetPaletteLabelArray
;
814 ULONG offsetPaletteEntryLabelArray
;
817 struct CPAL_ColorRecord
829 USHORT numBaseGlyphRecords
;
830 ULONG offsetBaseGlyphRecord
;
831 ULONG offsetLayerRecord
;
832 USHORT numLayerRecords
;
835 struct COLR_BaseGlyphRecord
838 USHORT firstLayerIndex
;
842 struct COLR_LayerRecord
848 BOOL
is_face_type_supported(DWRITE_FONT_FACE_TYPE type
)
850 return (type
== DWRITE_FONT_FACE_TYPE_CFF
) ||
851 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE
) ||
852 (type
== DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
) ||
853 (type
== DWRITE_FONT_FACE_TYPE_RAW_CFF
);
856 typedef HRESULT (*dwrite_fontfile_analyzer
)(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
857 DWRITE_FONT_FACE_TYPE
*face_type
);
859 static HRESULT
opentype_ttc_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
860 DWRITE_FONT_FACE_TYPE
*face_type
)
862 static const DWORD ttctag
= MS_TTCF_TAG
;
863 const TTC_Header_V1
*header
;
867 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(header
), &context
);
871 if (!memcmp(header
->TTCTag
, &ttctag
, sizeof(ttctag
))) {
872 *font_count
= GET_BE_DWORD(header
->numFonts
);
873 *file_type
= DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION
;
874 *face_type
= DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
;
877 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
879 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
882 static HRESULT
opentype_ttf_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
883 DWRITE_FONT_FACE_TYPE
*face_type
)
889 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
893 if (GET_BE_DWORD(*header
) == 0x10000) {
895 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE
;
896 *face_type
= DWRITE_FONT_FACE_TYPE_TRUETYPE
;
899 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
901 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
904 static HRESULT
opentype_otf_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
905 DWRITE_FONT_FACE_TYPE
*face_type
)
911 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
915 if (GET_BE_DWORD(*header
) == MS_OTTO_TAG
) {
917 *file_type
= DWRITE_FONT_FILE_TYPE_CFF
;
918 *face_type
= DWRITE_FONT_FACE_TYPE_CFF
;
921 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
923 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
926 static HRESULT
opentype_type1_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
927 DWRITE_FONT_FACE_TYPE
*face_type
)
929 #include "pshpack1.h"
930 /* Specified in Adobe TechNote #5178 */
939 struct type1_header
{
943 const struct type1_header
*header
;
947 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
951 /* tag is followed by plain text section */
952 if (header
->tag
== 0x8001 &&
953 (!memcmp(header
->data
, "%!PS-AdobeFont", 14) ||
954 !memcmp(header
->data
, "%!FontType", 10))) {
956 *file_type
= DWRITE_FONT_FILE_TYPE_TYPE1_PFB
;
957 *face_type
= DWRITE_FONT_FACE_TYPE_TYPE1
;
960 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
962 /* let's see if it's a .pfm metrics file */
963 if (*file_type
== DWRITE_FONT_FILE_TYPE_UNKNOWN
) {
964 const struct pfm_header
*pfm_header
;
969 hr
= IDWriteFontFileStream_GetFileSize(stream
, &filesize
);
973 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&pfm_header
, 0, sizeof(*pfm_header
), &context
);
977 offset
= pfm_header
->dfDevice
;
978 header_checked
= pfm_header
->dfVersion
== 0x100 && pfm_header
->dfSize
== filesize
;
979 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
981 /* as a last test check static string in PostScript information section */
982 if (header_checked
) {
983 static const char postscript
[] = "PostScript";
986 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&devtype_name
, offset
, sizeof(postscript
), &context
);
990 if (!memcmp(devtype_name
, postscript
, sizeof(postscript
))) {
992 *file_type
= DWRITE_FONT_FILE_TYPE_TYPE1_PFM
;
993 *face_type
= DWRITE_FONT_FACE_TYPE_TYPE1
;
996 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
1000 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
1003 HRESULT
opentype_analyze_font(IDWriteFontFileStream
*stream
, UINT32
* font_count
, DWRITE_FONT_FILE_TYPE
*file_type
, DWRITE_FONT_FACE_TYPE
*face_type
, BOOL
*supported
)
1005 static dwrite_fontfile_analyzer fontfile_analyzers
[] = {
1006 opentype_ttf_analyzer
,
1007 opentype_otf_analyzer
,
1008 opentype_ttc_analyzer
,
1009 opentype_type1_analyzer
,
1012 dwrite_fontfile_analyzer
*analyzer
= fontfile_analyzers
;
1013 DWRITE_FONT_FACE_TYPE face
;
1019 *file_type
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
1020 *face_type
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
1024 hr
= (*analyzer
)(stream
, font_count
, file_type
, face_type
);
1034 *supported
= is_face_type_supported(*face_type
);
1038 HRESULT
opentype_get_font_table(struct file_stream_desc
*stream_desc
, UINT32 tag
, const void **table_data
,
1039 void **table_context
, UINT32
*table_size
, BOOL
*found
)
1042 TTC_SFNT_V1
*font_header
= NULL
;
1044 TT_TableRecord
*table_record
= NULL
;
1045 void *table_record_context
;
1046 int table_count
, table_offset
= 0;
1049 if (found
) *found
= FALSE
;
1050 if (table_size
) *table_size
= 0;
1053 *table_context
= NULL
;
1055 if (stream_desc
->face_type
== DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
) {
1056 const TTC_Header_V1
*ttc_header
;
1058 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&ttc_header
, 0, sizeof(*ttc_header
), &ttc_context
);
1059 if (SUCCEEDED(hr
)) {
1060 if (stream_desc
->face_index
>= GET_BE_DWORD(ttc_header
->numFonts
))
1063 table_offset
= GET_BE_DWORD(ttc_header
->OffsetTable
[stream_desc
->face_index
]);
1064 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&font_header
, table_offset
, sizeof(*font_header
), &sfnt_context
);
1066 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, ttc_context
);
1070 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&font_header
, 0, sizeof(*font_header
), &sfnt_context
);
1075 table_count
= GET_BE_WORD(font_header
->numTables
);
1076 table_offset
+= sizeof(*font_header
);
1077 for (i
= 0; i
< table_count
; i
++)
1079 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&table_record
, table_offset
, sizeof(*table_record
), &table_record_context
);
1082 if (DWRITE_MAKE_OPENTYPE_TAG(table_record
->tag
[0], table_record
->tag
[1], table_record
->tag
[2], table_record
->tag
[3]) == tag
)
1084 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, table_record_context
);
1085 table_offset
+= sizeof(*table_record
);
1088 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, sfnt_context
);
1089 if (SUCCEEDED(hr
) && i
< table_count
)
1091 int offset
= GET_BE_DWORD(table_record
->offset
);
1092 int length
= GET_BE_DWORD(table_record
->length
);
1093 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, table_record_context
);
1095 if (found
) *found
= TRUE
;
1096 if (table_size
) *table_size
= length
;
1097 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, table_data
, offset
, length
, table_context
);
1107 static UINT32
opentype_cmap_get_unicode_ranges_count(const CMAP_Header
*CMAP_Table
)
1112 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
); i
++) {
1116 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
1119 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
1120 type
= GET_BE_WORD(*table
);
1121 TRACE("table type %i\n", type
);
1125 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
1127 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
1128 count
+= GET_BE_WORD(format
->segCountX2
)/2;
1131 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
1133 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
1134 count
+= GET_BE_DWORD(format
->nGroups
);
1138 FIXME("table type %i unhandled.\n", type
);
1145 HRESULT
opentype_cmap_get_unicode_ranges(void *data
, UINT32 max_count
, DWRITE_UNICODE_RANGE
*ranges
, UINT32
*count
)
1147 CMAP_Header
*CMAP_Table
= data
;
1153 *count
= opentype_cmap_get_unicode_ranges_count(CMAP_Table
);
1155 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
) && k
< max_count
; i
++)
1161 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
1164 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
1165 type
= GET_BE_WORD(*table
);
1166 TRACE("table type %i\n", type
);
1170 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
1172 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
1173 UINT16 segment_count
= GET_BE_WORD(format
->segCountX2
)/2;
1174 UINT16
*startCode
= (WORD
*)((BYTE
*)format
+ sizeof(CMAP_SegmentMapping_0
) + (sizeof(WORD
) * segment_count
));
1176 for (j
= 0; j
< segment_count
&& GET_BE_WORD(format
->endCode
[j
]) < 0xffff && k
< max_count
; j
++, k
++) {
1177 ranges
[k
].first
= GET_BE_WORD(startCode
[j
]);
1178 ranges
[k
].last
= GET_BE_WORD(format
->endCode
[j
]);
1182 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
1184 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
1185 for (j
= 0; j
< GET_BE_DWORD(format
->nGroups
) && k
< max_count
; j
++, k
++) {
1186 ranges
[k
].first
= GET_BE_DWORD(format
->groups
[j
].startCharCode
);
1187 ranges
[k
].last
= GET_BE_DWORD(format
->groups
[j
].endCharCode
);
1192 FIXME("table type %i unhandled.\n", type
);
1196 return *count
> max_count
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
1199 void opentype_get_font_metrics(struct file_stream_desc
*stream_desc
, DWRITE_FONT_METRICS1
*metrics
, DWRITE_CARET_METRICS
*caret
)
1201 void *os2_context
, *head_context
, *post_context
, *hhea_context
;
1202 const TT_OS2_V2
*tt_os2
;
1203 const TT_HEAD
*tt_head
;
1204 const TT_POST
*tt_post
;
1205 const TT_HHEA
*tt_hhea
;
1207 memset(metrics
, 0, sizeof(*metrics
));
1209 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1210 opentype_get_font_table(stream_desc
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
1211 opentype_get_font_table(stream_desc
, MS_POST_TAG
, (const void**)&tt_post
, &post_context
, NULL
, NULL
);
1212 opentype_get_font_table(stream_desc
, MS_HHEA_TAG
, (const void**)&tt_hhea
, &hhea_context
, NULL
, NULL
);
1215 metrics
->designUnitsPerEm
= GET_BE_WORD(tt_head
->unitsPerEm
);
1216 metrics
->glyphBoxLeft
= GET_BE_WORD(tt_head
->xMin
);
1217 metrics
->glyphBoxTop
= GET_BE_WORD(tt_head
->yMax
);
1218 metrics
->glyphBoxRight
= GET_BE_WORD(tt_head
->xMax
);
1219 metrics
->glyphBoxBottom
= GET_BE_WORD(tt_head
->yMin
);
1224 caret
->slopeRise
= GET_BE_WORD(tt_hhea
->caretSlopeRise
);
1225 caret
->slopeRun
= GET_BE_WORD(tt_hhea
->caretSlopeRun
);
1226 caret
->offset
= GET_BE_WORD(tt_hhea
->caretOffset
);
1229 caret
->slopeRise
= 0;
1230 caret
->slopeRun
= 0;
1236 USHORT version
= GET_BE_WORD(tt_os2
->version
);
1238 metrics
->ascent
= GET_BE_WORD(tt_os2
->usWinAscent
);
1239 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
1240 interpreted as large unsigned value. */
1241 metrics
->descent
= abs((SHORT
)GET_BE_WORD(tt_os2
->usWinDescent
));
1243 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
1245 SHORT descender
= (SHORT
)GET_BE_WORD(tt_hhea
->descender
);
1248 linegap
= GET_BE_WORD(tt_hhea
->ascender
) + abs(descender
) + GET_BE_WORD(tt_hhea
->linegap
) -
1249 metrics
->ascent
- metrics
->descent
;
1250 metrics
->lineGap
= linegap
> 0 ? linegap
: 0;
1253 metrics
->strikethroughPosition
= GET_BE_WORD(tt_os2
->yStrikeoutPosition
);
1254 metrics
->strikethroughThickness
= GET_BE_WORD(tt_os2
->yStrikeoutSize
);
1255 metrics
->subscriptPositionX
= GET_BE_WORD(tt_os2
->ySubscriptXOffset
);
1256 /* Y offset is stored as positive offset below baseline */
1257 metrics
->subscriptPositionY
= -GET_BE_WORD(tt_os2
->ySubscriptYOffset
);
1258 metrics
->subscriptSizeX
= GET_BE_WORD(tt_os2
->ySubscriptXSize
);
1259 metrics
->subscriptSizeY
= GET_BE_WORD(tt_os2
->ySubscriptYSize
);
1260 metrics
->superscriptPositionX
= GET_BE_WORD(tt_os2
->ySuperscriptXOffset
);
1261 metrics
->superscriptPositionY
= GET_BE_WORD(tt_os2
->ySuperscriptYOffset
);
1262 metrics
->superscriptSizeX
= GET_BE_WORD(tt_os2
->ySuperscriptXSize
);
1263 metrics
->superscriptSizeY
= GET_BE_WORD(tt_os2
->ySuperscriptYSize
);
1265 /* version 2 fields */
1267 metrics
->capHeight
= GET_BE_WORD(tt_os2
->sCapHeight
);
1268 metrics
->xHeight
= GET_BE_WORD(tt_os2
->sxHeight
);
1271 if (GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_USE_TYPO_METRICS
) {
1272 SHORT descent
= GET_BE_WORD(tt_os2
->sTypoDescender
);
1273 metrics
->ascent
= GET_BE_WORD(tt_os2
->sTypoAscender
);
1274 metrics
->descent
= descent
< 0 ? -descent
: 0;
1275 metrics
->lineGap
= GET_BE_WORD(tt_os2
->sTypoLineGap
);
1276 metrics
->hasTypographicMetrics
= TRUE
;
1281 metrics
->underlinePosition
= GET_BE_WORD(tt_post
->underlinePosition
);
1282 metrics
->underlineThickness
= GET_BE_WORD(tt_post
->underlineThickness
);
1285 if (metrics
->underlineThickness
== 0)
1286 metrics
->underlineThickness
= metrics
->designUnitsPerEm
/ 14;
1287 if (metrics
->strikethroughThickness
== 0)
1288 metrics
->strikethroughThickness
= metrics
->underlineThickness
;
1290 /* estimate missing metrics */
1291 if (metrics
->xHeight
== 0)
1292 metrics
->xHeight
= metrics
->designUnitsPerEm
/ 2;
1293 if (metrics
->capHeight
== 0)
1294 metrics
->capHeight
= metrics
->designUnitsPerEm
* 7 / 10;
1297 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1299 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, head_context
);
1301 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, post_context
);
1303 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, hhea_context
);
1306 void opentype_get_font_properties(struct file_stream_desc
*stream_desc
, struct dwrite_font_props
*props
)
1308 void *os2_context
, *head_context
;
1309 const TT_OS2_V2
*tt_os2
;
1310 const TT_HEAD
*tt_head
;
1312 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1313 opentype_get_font_table(stream_desc
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
1315 /* default stretch, weight and style to normal */
1316 props
->stretch
= DWRITE_FONT_STRETCH_NORMAL
;
1317 props
->weight
= DWRITE_FONT_WEIGHT_NORMAL
;
1318 props
->style
= DWRITE_FONT_STYLE_NORMAL
;
1319 memset(&props
->panose
, 0, sizeof(props
->panose
));
1320 memset(&props
->lf
, 0, sizeof(props
->lf
));
1322 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1324 USHORT version
= GET_BE_WORD(tt_os2
->version
);
1325 USHORT fsSelection
= GET_BE_WORD(tt_os2
->fsSelection
);
1326 USHORT usWeightClass
= GET_BE_WORD(tt_os2
->usWeightClass
);
1327 USHORT usWidthClass
= GET_BE_WORD(tt_os2
->usWidthClass
);
1329 if (usWidthClass
> DWRITE_FONT_STRETCH_UNDEFINED
&& usWidthClass
<= DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
1330 props
->stretch
= usWidthClass
;
1332 if (usWeightClass
>= 1 && usWeightClass
<= 9)
1333 usWeightClass
*= 100;
1335 if (usWeightClass
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
1336 props
->weight
= DWRITE_FONT_WEIGHT_ULTRA_BLACK
;
1337 else if (usWeightClass
> 0)
1338 props
->weight
= usWeightClass
;
1340 if (version
>= 4 && (fsSelection
& OS2_FSSELECTION_OBLIQUE
))
1341 props
->style
= DWRITE_FONT_STYLE_OBLIQUE
;
1342 else if (fsSelection
& OS2_FSSELECTION_ITALIC
)
1343 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
1345 memcpy(&props
->panose
, &tt_os2
->panose
, sizeof(props
->panose
));
1348 USHORT macStyle
= GET_BE_WORD(tt_head
->macStyle
);
1350 if (macStyle
& TT_HEAD_MACSTYLE_CONDENSED
)
1351 props
->stretch
= DWRITE_FONT_STRETCH_CONDENSED
;
1352 else if (macStyle
& TT_HEAD_MACSTYLE_EXTENDED
)
1353 props
->stretch
= DWRITE_FONT_STRETCH_EXPANDED
;
1355 if (macStyle
& TT_HEAD_MACSTYLE_BOLD
)
1356 props
->weight
= DWRITE_FONT_WEIGHT_BOLD
;
1358 if (macStyle
& TT_HEAD_MACSTYLE_ITALIC
)
1359 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
1362 props
->lf
.lfWeight
= props
->weight
;
1363 props
->lf
.lfItalic
= props
->style
== DWRITE_FONT_STYLE_ITALIC
;
1365 TRACE("stretch=%d, weight=%d, style %d\n", props
->stretch
, props
->weight
, props
->style
);
1368 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1370 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, head_context
);
1373 static UINT
get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform
, USHORT encoding
)
1378 case OPENTYPE_PLATFORM_UNICODE
:
1380 case OPENTYPE_PLATFORM_MAC
:
1383 case TT_NAME_MAC_ENCODING_ROMAN
:
1386 case TT_NAME_MAC_ENCODING_JAPANESE
:
1389 case TT_NAME_MAC_ENCODING_TRAD_CHINESE
:
1392 case TT_NAME_MAC_ENCODING_KOREAN
:
1395 case TT_NAME_MAC_ENCODING_ARABIC
:
1398 case TT_NAME_MAC_ENCODING_HEBREW
:
1401 case TT_NAME_MAC_ENCODING_GREEK
:
1404 case TT_NAME_MAC_ENCODING_RUSSIAN
:
1407 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE
:
1410 case TT_NAME_MAC_ENCODING_THAI
:
1414 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1418 case OPENTYPE_PLATFORM_WIN
:
1421 case TT_NAME_WINDOWS_ENCODING_SYMBOL
:
1422 case TT_NAME_WINDOWS_ENCODING_UCS2
:
1424 case TT_NAME_WINDOWS_ENCODING_SJIS
:
1427 case TT_NAME_WINDOWS_ENCODING_PRC
:
1430 case TT_NAME_WINDOWS_ENCODING_BIG5
:
1433 case TT_NAME_WINDOWS_ENCODING_WANSUNG
:
1436 case TT_NAME_WINDOWS_ENCODING_JOHAB
:
1440 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1445 FIXME("unknown platform %d\n", platform
);
1451 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform
, USHORT lang_id
, WCHAR
*locale
, USHORT locale_len
)
1453 static const WCHAR enusW
[] = {'e','n','-','U','S',0};
1456 case OPENTYPE_PLATFORM_MAC
:
1458 const char *locale_name
= NULL
;
1460 if (lang_id
> TT_NAME_MAC_LANGID_AZER_ROMAN
)
1461 WARN("invalid mac lang id %d\n", lang_id
);
1462 else if (!name_mac_langid_to_locale
[lang_id
][0])
1463 FIXME("failed to map mac lang id %d to locale name\n", lang_id
);
1465 locale_name
= name_mac_langid_to_locale
[lang_id
];
1468 MultiByteToWideChar(CP_ACP
, 0, name_mac_langid_to_locale
[lang_id
], -1, locale
, locale_len
);
1470 strcpyW(locale
, enusW
);
1473 case OPENTYPE_PLATFORM_WIN
:
1474 if (!LCIDToLocaleName(MAKELCID(lang_id
, SORT_DEFAULT
), locale
, locale_len
, 0)) {
1475 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id
, SORT_DEFAULT
));
1476 strcpyW(locale
, enusW
);
1479 case OPENTYPE_PLATFORM_UNICODE
:
1480 strcpyW(locale
, enusW
);
1483 FIXME("unknown platform %d\n", platform
);
1487 static BOOL
opentype_decode_namerecord(const TT_NAME_V0
*header
, BYTE
*storage_area
, USHORT recid
, IDWriteLocalizedStrings
*strings
)
1489 const TT_NameRecord
*record
= &header
->nameRecord
[recid
];
1490 USHORT lang_id
, length
, offset
, encoding
, platform
;
1493 platform
= GET_BE_WORD(record
->platformID
);
1494 lang_id
= GET_BE_WORD(record
->languageID
);
1495 length
= GET_BE_WORD(record
->length
);
1496 offset
= GET_BE_WORD(record
->offset
);
1497 encoding
= GET_BE_WORD(record
->encodingID
);
1499 if (lang_id
< 0x8000) {
1500 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
1504 codepage
= get_name_record_codepage(platform
, encoding
);
1505 get_name_record_locale(platform
, lang_id
, locale
, sizeof(locale
)/sizeof(WCHAR
));
1508 DWORD len
= MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, NULL
, 0);
1509 name_string
= heap_alloc(sizeof(WCHAR
) * (len
+1));
1510 MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, name_string
, len
);
1511 name_string
[len
] = 0;
1516 length
/= sizeof(WCHAR
);
1517 name_string
= heap_strdupnW((LPWSTR
)(storage_area
+ offset
), length
);
1518 for (i
= 0; i
< length
; i
++)
1519 name_string
[i
] = GET_BE_WORD(name_string
[i
]);
1522 TRACE("string %s for locale %s found\n", debugstr_w(name_string
), debugstr_w(locale
));
1523 add_localizedstring(strings
, locale
, name_string
);
1524 heap_free(name_string
);
1528 FIXME("handle NAME format 1\n");
1533 static HRESULT
opentype_get_font_strings_from_id(const void *table_data
, enum OPENTYPE_STRING_ID id
, IDWriteLocalizedStrings
**strings
)
1535 const TT_NAME_V0
*header
;
1536 BYTE
*storage_area
= 0;
1546 hr
= create_localizedstrings(strings
);
1547 if (FAILED(hr
)) return hr
;
1549 header
= table_data
;
1550 format
= GET_BE_WORD(header
->format
);
1557 FIXME("unsupported NAME format %d\n", format
);
1560 storage_area
= (LPBYTE
)table_data
+ GET_BE_WORD(header
->stringOffset
);
1561 count
= GET_BE_WORD(header
->count
);
1565 for (i
= 0; i
< count
; i
++) {
1566 const TT_NameRecord
*record
= &header
->nameRecord
[i
];
1569 if (GET_BE_WORD(record
->nameID
) != id
)
1572 /* Right now only accept unicode and windows encoded fonts */
1573 platform
= GET_BE_WORD(record
->platformID
);
1574 if (platform
!= OPENTYPE_PLATFORM_UNICODE
&&
1575 platform
!= OPENTYPE_PLATFORM_MAC
&&
1576 platform
!= OPENTYPE_PLATFORM_WIN
)
1578 FIXME("platform %i not supported\n", platform
);
1582 /* Skip such entries for now, fonts tend to duplicate those strings as
1583 WIN platform entries. If font does not have WIN or MAC entry for this id, we will
1584 use this Unicode platform entry while assuming en-US locale. */
1585 if (platform
== OPENTYPE_PLATFORM_UNICODE
) {
1590 if (!opentype_decode_namerecord(header
, storage_area
, i
, *strings
))
1597 if (candidate
!= -1)
1598 exists
= opentype_decode_namerecord(header
, storage_area
, candidate
, *strings
);
1600 IDWriteLocalizedStrings_Release(*strings
);
1605 return exists
? S_OK
: E_FAIL
;
1608 /* Provides a conversion from DWRITE to OpenType name ids, input id should be valid, it's not checked. */
1609 HRESULT
opentype_get_font_info_strings(const void *table_data
, DWRITE_INFORMATIONAL_STRING_ID id
, IDWriteLocalizedStrings
**strings
)
1611 return opentype_get_font_strings_from_id(table_data
, dwriteid_to_opentypeid
[id
], strings
);
1614 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
1615 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
1616 HRESULT
opentype_get_font_familyname(struct file_stream_desc
*stream_desc
, IDWriteLocalizedStrings
**names
)
1618 const TT_OS2_V2
*tt_os2
;
1619 void *os2_context
, *name_context
;
1620 const void *name_table
;
1623 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1624 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name_table
, &name_context
, NULL
, NULL
);
1628 /* if Preferred Family doesn't conform to WWS model try WWS name */
1629 if (tt_os2
&& !(GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_WWS
))
1630 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_WWS_FAMILY_NAME
, names
);
1635 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_PREFERRED_FAMILY_NAME
, names
);
1637 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_FAMILY_NAME
, names
);
1640 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1642 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name_context
);
1647 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
1648 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
1649 HRESULT
opentype_get_font_facename(struct file_stream_desc
*stream_desc
, WCHAR
*lfname
, IDWriteLocalizedStrings
**names
)
1651 IDWriteLocalizedStrings
*lfnames
;
1652 void *os2_context
, *name_context
;
1653 const TT_OS2_V2
*tt_os2
;
1654 const void *name_table
;
1657 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1658 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name_table
, &name_context
, NULL
, NULL
);
1662 /* if Preferred Family doesn't conform to WWS model try WWS name */
1663 if (tt_os2
&& !(GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_WWS
))
1664 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_WWS_SUBFAMILY_NAME
, names
);
1669 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
, names
);
1671 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_SUBFAMILY_NAME
, names
);
1673 /* User locale is preferred, with fallback to en-us. */
1675 if (SUCCEEDED(opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_FAMILY_NAME
, &lfnames
))) {
1676 static const WCHAR enusW
[] = {'e','n','-','u','s',0};
1677 WCHAR localeW
[LOCALE_NAME_MAX_LENGTH
];
1682 if (GetSystemDefaultLocaleName(localeW
, sizeof(localeW
)/sizeof(WCHAR
)))
1683 IDWriteLocalizedStrings_FindLocaleName(lfnames
, localeW
, &index
, &exists
);
1686 IDWriteLocalizedStrings_FindLocaleName(lfnames
, enusW
, &index
, &exists
);
1689 IDWriteLocalizedStrings_GetString(lfnames
, index
, lfname
, LF_FACESIZE
);
1691 IDWriteLocalizedStrings_Release(lfnames
);
1695 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1697 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name_context
);
1702 static inline const OT_Script
*opentype_get_script(const OT_ScriptList
*scriptlist
, UINT32 scripttag
)
1706 for (j
= 0; j
< GET_BE_WORD(scriptlist
->ScriptCount
); j
++) {
1707 const char *tag
= scriptlist
->ScriptRecord
[j
].ScriptTag
;
1708 if (scripttag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1709 return (OT_Script
*)((BYTE
*)scriptlist
+ GET_BE_WORD(scriptlist
->ScriptRecord
[j
].Script
));
1715 static inline const OT_LangSys
*opentype_get_langsys(const OT_Script
*script
, UINT32 languagetag
)
1719 for (j
= 0; j
< GET_BE_WORD(script
->LangSysCount
); j
++) {
1720 const char *tag
= script
->LangSysRecord
[j
].LangSysTag
;
1721 if (languagetag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1722 return (OT_LangSys
*)((BYTE
*)script
+ GET_BE_WORD(script
->LangSysRecord
[j
].LangSys
));
1728 static void opentype_add_font_features(const GPOS_GSUB_Header
*header
, const OT_LangSys
*langsys
,
1729 UINT32 max_tagcount
, UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1731 const OT_FeatureList
*features
= (const OT_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1734 for (j
= 0; j
< GET_BE_WORD(langsys
->FeatureCount
); j
++) {
1735 const OT_FeatureRecord
*feature
= &features
->FeatureRecord
[langsys
->FeatureIndex
[j
]];
1736 const char *tag
= feature
->FeatureTag
;
1738 if (*count
< max_tagcount
)
1739 tags
[*count
] = DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]);
1745 HRESULT
opentype_get_typographic_features(IDWriteFontFace
*fontface
, UINT32 scripttag
, UINT32 languagetag
, UINT32 max_tagcount
,
1746 UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1748 UINT32 tables
[2] = { MS_GSUB_TAG
, MS_GPOS_TAG
};
1753 for (i
= 0; i
< sizeof(tables
)/sizeof(tables
[0]); i
++) {
1754 const OT_ScriptList
*scriptlist
;
1755 const GPOS_GSUB_Header
*header
;
1756 const OT_Script
*script
;
1763 hr
= IDWriteFontFace_TryGetFontTable(fontface
, tables
[i
], &ptr
, &size
, &context
, &exists
);
1770 header
= (const GPOS_GSUB_Header
*)ptr
;
1771 scriptlist
= (const OT_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
1773 script
= opentype_get_script(scriptlist
, scripttag
);
1775 const OT_LangSys
*langsys
= opentype_get_langsys(script
, languagetag
);
1777 opentype_add_font_features(header
, langsys
, max_tagcount
, count
, tags
);
1780 IDWriteFontFace_ReleaseFontTable(fontface
, context
);
1783 return *count
> max_tagcount
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
1786 static const struct VDMX_group
*find_vdmx_group(const struct VDMX_Header
*hdr
)
1788 WORD num_ratios
, i
, group_offset
= 0;
1789 struct VDMX_Ratio
*ratios
= (struct VDMX_Ratio
*)(hdr
+ 1);
1790 BYTE dev_x_ratio
= 1, dev_y_ratio
= 1;
1792 num_ratios
= GET_BE_WORD(hdr
->numRatios
);
1794 for (i
= 0; i
< num_ratios
; i
++) {
1796 if (!ratios
[i
].bCharSet
) continue;
1798 if ((ratios
[i
].xRatio
== 0 && ratios
[i
].yStartRatio
== 0 &&
1799 ratios
[i
].yEndRatio
== 0) ||
1800 (ratios
[i
].xRatio
== dev_x_ratio
&& ratios
[i
].yStartRatio
<= dev_y_ratio
&&
1801 ratios
[i
].yEndRatio
>= dev_y_ratio
))
1803 group_offset
= GET_BE_WORD(*((WORD
*)(ratios
+ num_ratios
) + i
));
1808 return (const struct VDMX_group
*)((BYTE
*)hdr
+ group_offset
);
1812 BOOL
opentype_get_vdmx_size(const void *data
, INT emsize
, UINT16
*ascent
, UINT16
*descent
)
1814 const struct VDMX_Header
*hdr
= (const struct VDMX_Header
*)data
;
1815 const struct VDMX_group
*group
;
1816 const struct VDMX_vTable
*tables
;
1822 group
= find_vdmx_group(hdr
);
1826 recs
= GET_BE_WORD(group
->recs
);
1827 if (emsize
< group
->startsz
|| emsize
>= group
->endsz
) return FALSE
;
1829 tables
= (const struct VDMX_vTable
*)(group
+ 1);
1830 for (i
= 0; i
< recs
; i
++) {
1831 WORD ppem
= GET_BE_WORD(tables
[i
].yPelHeight
);
1832 if (ppem
> emsize
) {
1833 FIXME("interpolate %d\n", emsize
);
1837 if (ppem
== emsize
) {
1838 *ascent
= (SHORT
)GET_BE_WORD(tables
[i
].yMax
);
1839 *descent
= -(SHORT
)GET_BE_WORD(tables
[i
].yMin
);
1846 WORD
opentype_get_gasp_flags(const WORD
*ptr
, UINT32 size
, INT emsize
)
1848 WORD num_recs
, version
;
1854 version
= GET_BE_WORD( *ptr
++ );
1855 num_recs
= GET_BE_WORD( *ptr
++ );
1856 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
)) {
1857 ERR("unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
1861 while (num_recs
--) {
1862 flags
= GET_BE_WORD( *(ptr
+ 1) );
1863 if (emsize
<= GET_BE_WORD( *ptr
)) break;
1871 UINT32
opentype_get_cpal_palettecount(const void *cpal
)
1873 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1874 return header
? GET_BE_WORD(header
->numPalette
) : 0;
1877 UINT32
opentype_get_cpal_paletteentrycount(const void *cpal
)
1879 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1880 return header
? GET_BE_WORD(header
->numPaletteEntries
) : 0;
1883 HRESULT
opentype_get_cpal_entries(const void *cpal
, UINT32 palette
, UINT32 first_entry_index
, UINT32 entry_count
,
1884 DWRITE_COLOR_F
*entries
)
1886 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1887 const struct CPAL_ColorRecord
*records
;
1888 UINT32 palettecount
, entrycount
, i
;
1890 if (!header
) return DWRITE_E_NOCOLOR
;
1892 palettecount
= GET_BE_WORD(header
->numPalette
);
1893 if (palette
>= palettecount
)
1894 return DWRITE_E_NOCOLOR
;
1896 entrycount
= GET_BE_WORD(header
->numPaletteEntries
);
1897 if (first_entry_index
+ entry_count
> entrycount
)
1898 return E_INVALIDARG
;
1900 records
= (const struct CPAL_ColorRecord
*)((BYTE
*)cpal
+ GET_BE_DWORD(header
->offsetFirstColorRecord
));
1901 first_entry_index
+= GET_BE_WORD(header
->colorRecordIndices
[palette
]);
1903 for (i
= 0; i
< entry_count
; i
++) {
1904 entries
[i
].u1
.r
= records
[first_entry_index
+ i
].red
/ 255.0f
;
1905 entries
[i
].u2
.g
= records
[first_entry_index
+ i
].green
/ 255.0f
;
1906 entries
[i
].u3
.b
= records
[first_entry_index
+ i
].blue
/ 255.0f
;
1907 entries
[i
].u4
.a
= records
[first_entry_index
+ i
].alpha
/ 255.0f
;
1913 static int colr_compare_gid(const void *g
, const void *r
)
1915 const struct COLR_BaseGlyphRecord
*record
= r
;
1916 UINT16 glyph
= *(UINT16
*)g
, GID
= GET_BE_WORD(record
->GID
);
1921 else if (glyph
< GID
)
1927 HRESULT
opentype_get_colr_glyph(const void *colr
, UINT16 glyph
, struct dwrite_colorglyph
*ret
)
1929 const struct COLR_BaseGlyphRecord
*record
;
1930 const struct COLR_Header
*header
= colr
;
1931 const struct COLR_LayerRecord
*layer
;
1932 DWORD layerrecordoffset
= GET_BE_DWORD(header
->offsetLayerRecord
);
1933 DWORD baserecordoffset
= GET_BE_DWORD(header
->offsetBaseGlyphRecord
);
1934 WORD numbaserecords
= GET_BE_WORD(header
->numBaseGlyphRecords
);
1936 record
= bsearch(&glyph
, (BYTE
*)colr
+ baserecordoffset
, numbaserecords
, sizeof(struct COLR_BaseGlyphRecord
),
1940 ret
->first_layer
= 0;
1941 ret
->num_layers
= 0;
1943 ret
->palette_index
= 0xffff;
1948 ret
->first_layer
= GET_BE_WORD(record
->firstLayerIndex
);
1949 ret
->num_layers
= GET_BE_WORD(record
->numLayers
);
1951 layer
= (struct COLR_LayerRecord
*)((BYTE
*)colr
+ layerrecordoffset
) + ret
->first_layer
+ ret
->layer
;
1952 ret
->glyph
= GET_BE_WORD(layer
->GID
);
1953 ret
->palette_index
= GET_BE_WORD(layer
->paletteIndex
);
1958 void opentype_colr_next_glyph(const void *colr
, struct dwrite_colorglyph
*glyph
)
1960 const struct COLR_Header
*header
= colr
;
1961 const struct COLR_LayerRecord
*layer
;
1962 DWORD layerrecordoffset
= GET_BE_DWORD(header
->offsetLayerRecord
);
1964 /* iterated all the way through */
1965 if (glyph
->layer
== glyph
->num_layers
)
1969 layer
= (struct COLR_LayerRecord
*)((BYTE
*)colr
+ layerrecordoffset
) + glyph
->first_layer
+ glyph
->layer
;
1970 glyph
->glyph
= GET_BE_WORD(layer
->GID
);
1971 glyph
->palette_index
= GET_BE_WORD(layer
->paletteIndex
);
1974 HRESULT
opentype_get_font_signature(struct file_stream_desc
*stream_desc
, FONTSIGNATURE
*fontsig
)
1976 const TT_OS2_V2
*tt_os2
;
1980 hr
= opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1982 fontsig
->fsUsb
[0] = GET_BE_DWORD(tt_os2
->ulUnicodeRange1
);
1983 fontsig
->fsUsb
[1] = GET_BE_DWORD(tt_os2
->ulUnicodeRange2
);
1984 fontsig
->fsUsb
[2] = GET_BE_DWORD(tt_os2
->ulUnicodeRange3
);
1985 fontsig
->fsUsb
[3] = GET_BE_DWORD(tt_os2
->ulUnicodeRange4
);
1987 if (GET_BE_WORD(tt_os2
->version
) == 0) {
1988 fontsig
->fsCsb
[0] = 0;
1989 fontsig
->fsCsb
[1] = 0;
1992 fontsig
->fsCsb
[0] = GET_BE_DWORD(tt_os2
->ulCodePageRange1
);
1993 fontsig
->fsCsb
[1] = GET_BE_DWORD(tt_os2
->ulCodePageRange2
);
1996 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
2002 BOOL
opentype_has_vertical_variants(IDWriteFontFace4
*fontface
)
2004 const OT_FeatureList
*featurelist
;
2005 const OT_LookupList
*lookup_list
;
2006 BOOL exists
= FALSE
, ret
= FALSE
;
2007 const GPOS_GSUB_Header
*header
;
2014 hr
= IDWriteFontFace4_TryGetFontTable(fontface
, MS_GSUB_TAG
, &data
, &size
, &context
, &exists
);
2015 if (FAILED(hr
) || !exists
)
2019 featurelist
= (OT_FeatureList
*)((BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
2020 lookup_list
= (const OT_LookupList
*)((BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
2022 for (i
= 0; i
< GET_BE_WORD(featurelist
->FeatureCount
); i
++) {
2023 if (*(UINT32
*)featurelist
->FeatureRecord
[i
].FeatureTag
== DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING
) {
2024 const OT_Feature
*feature
= (const OT_Feature
*)((BYTE
*)featurelist
+ GET_BE_WORD(featurelist
->FeatureRecord
[i
].Feature
));
2025 UINT16 lookup_count
= GET_BE_WORD(feature
->LookupCount
), i
, index
, count
, type
;
2026 const GSUB_SingleSubstFormat2
*subst2
;
2027 const OT_LookupTable
*lookup_table
;
2030 if (lookup_count
== 0)
2033 for (i
= 0; i
< lookup_count
; i
++) {
2034 /* check if lookup is empty */
2035 index
= GET_BE_WORD(feature
->LookupListIndex
[i
]);
2036 lookup_table
= (const OT_LookupTable
*)((BYTE
*)lookup_list
+ GET_BE_WORD(lookup_list
->Lookup
[index
]));
2038 type
= GET_BE_WORD(lookup_table
->LookupType
);
2039 if (type
!= OPENTYPE_GPOS_SINGLE_SUBST
&& type
!= OPENTYPE_GPOS_EXTENSION_SUBST
)
2042 count
= GET_BE_WORD(lookup_table
->SubTableCount
);
2046 offset
= GET_BE_WORD(lookup_table
->SubTable
[0]);
2047 if (type
== OPENTYPE_GPOS_EXTENSION_SUBST
) {
2048 const GSUB_ExtensionPosFormat1
*ext
= (const GSUB_ExtensionPosFormat1
*)((const BYTE
*)lookup_table
+ offset
);
2049 if (GET_BE_WORD(ext
->SubstFormat
) == 1)
2050 offset
+= GET_BE_DWORD(ext
->ExtensionOffset
);
2052 FIXME("Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext
->SubstFormat
));
2055 subst2
= (const GSUB_SingleSubstFormat2
*)((BYTE
*)lookup_table
+ offset
);
2056 index
= GET_BE_WORD(subst2
->SubstFormat
);
2058 FIXME("Validate Single Substitution Format 1\n");
2059 else if (index
== 2) {
2060 /* SimSun-ExtB has 0 glyph count for this substitution */
2061 if (GET_BE_WORD(subst2
->GlyphCount
) > 0) {
2067 WARN("Unknown Single Substitution Format, %u\n", index
);
2072 IDWriteFontFace4_ReleaseFontTable(fontface
, context
);
2077 static BOOL
opentype_has_font_table(IDWriteFontFace4
*fontface
, UINT32 tag
)
2079 BOOL exists
= FALSE
;
2085 hr
= IDWriteFontFace4_TryGetFontTable(fontface
, tag
, &data
, &size
, &context
, &exists
);
2090 IDWriteFontFace4_ReleaseFontTable(fontface
, context
);
2095 static DWORD
opentype_get_sbix_formats(IDWriteFontFace4
*fontface
)
2097 UINT32 size
, s
, num_strikes
;
2098 const sbix_header
*header
;
2099 UINT16 g
, num_glyphs
;
2100 BOOL exists
= FALSE
;
2107 hr
= IDWriteFontFace4_TryGetFontTable(fontface
, MS_MAXP_TAG
, &data
, &size
, &context
, &exists
);
2108 if (FAILED(hr
) || !exists
)
2112 num_glyphs
= GET_BE_WORD(maxp
->numGlyphs
);
2114 IDWriteFontFace4_ReleaseFontTable(fontface
, context
);
2116 if (FAILED(IDWriteFontFace4_TryGetFontTable(fontface
, MS_SBIX_TAG
, &data
, &size
, &context
, &exists
))) {
2117 WARN("Failed to get 'sbix' table, %#x\n", hr
);
2122 num_strikes
= GET_BE_DWORD(header
->numStrikes
);
2124 for (s
= 0; s
< num_strikes
; s
++) {
2125 sbix_strike
*strike
= (sbix_strike
*)((BYTE
*)header
+ GET_BE_DWORD(header
->strikeOffset
[s
]));
2127 for (g
= 0; g
< num_glyphs
; g
++) {
2128 DWORD offset
= GET_BE_DWORD(strike
->glyphDataOffsets
[g
]);
2129 DWORD offset_next
= GET_BE_DWORD(strike
->glyphDataOffsets
[g
+ 1]);
2130 sbix_glyph_data
*glyph_data
;
2133 if (offset
== offset_next
)
2136 glyph_data
= (sbix_glyph_data
*)((BYTE
*)strike
+ offset
);
2137 switch (format
= glyph_data
->graphicType
)
2140 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_PNG
;
2143 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_JPEG
;
2146 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_TIFF
;
2149 format
= GET_BE_DWORD(format
);
2150 FIXME("unexpected bitmap format %s\n", debugstr_an((char *)&format
, 4));
2155 IDWriteFontFace4_ReleaseFontTable(fontface
, context
);
2160 UINT32
opentype_get_glyph_image_formats(IDWriteFontFace4
*fontface
)
2162 UINT32 ret
= DWRITE_GLYPH_IMAGE_FORMATS_NONE
;
2164 if (opentype_has_font_table(fontface
, MS_GLYF_TAG
))
2165 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE
;
2167 if (opentype_has_font_table(fontface
, MS_CFF__TAG
))
2168 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_CFF
;
2170 if (opentype_has_font_table(fontface
, MS_COLR_TAG
))
2171 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_COLR
;
2173 if (opentype_has_font_table(fontface
, MS_SVG__TAG
))
2174 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_SVG
;
2176 if (opentype_has_font_table(fontface
, MS_SBIX_TAG
))
2177 ret
|= opentype_get_sbix_formats(fontface
);
2179 /* TODO: handle embedded bitmaps tables */