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
->fontsig
, 0, sizeof(props
->fontsig
));
1321 memset(&props
->lf
, 0, sizeof(props
->lf
));
1323 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1325 USHORT version
= GET_BE_WORD(tt_os2
->version
);
1326 USHORT fsSelection
= GET_BE_WORD(tt_os2
->fsSelection
);
1327 USHORT usWeightClass
= GET_BE_WORD(tt_os2
->usWeightClass
);
1328 USHORT usWidthClass
= GET_BE_WORD(tt_os2
->usWidthClass
);
1330 if (usWidthClass
> DWRITE_FONT_STRETCH_UNDEFINED
&& usWidthClass
<= DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
1331 props
->stretch
= usWidthClass
;
1333 if (usWeightClass
>= 1 && usWeightClass
<= 9)
1334 usWeightClass
*= 100;
1336 if (usWeightClass
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
1337 props
->weight
= DWRITE_FONT_WEIGHT_ULTRA_BLACK
;
1338 else if (usWeightClass
> 0)
1339 props
->weight
= usWeightClass
;
1341 if (version
>= 4 && (fsSelection
& OS2_FSSELECTION_OBLIQUE
))
1342 props
->style
= DWRITE_FONT_STYLE_OBLIQUE
;
1343 else if (fsSelection
& OS2_FSSELECTION_ITALIC
)
1344 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
1346 memcpy(&props
->panose
, &tt_os2
->panose
, sizeof(props
->panose
));
1349 props
->fontsig
.fsUsb
[0] = GET_BE_DWORD(tt_os2
->ulUnicodeRange1
);
1350 props
->fontsig
.fsUsb
[1] = GET_BE_DWORD(tt_os2
->ulUnicodeRange2
);
1351 props
->fontsig
.fsUsb
[2] = GET_BE_DWORD(tt_os2
->ulUnicodeRange3
);
1352 props
->fontsig
.fsUsb
[3] = GET_BE_DWORD(tt_os2
->ulUnicodeRange4
);
1354 if (GET_BE_WORD(tt_os2
->version
) == 0) {
1355 props
->fontsig
.fsCsb
[0] = 0;
1356 props
->fontsig
.fsCsb
[1] = 0;
1359 props
->fontsig
.fsCsb
[0] = GET_BE_DWORD(tt_os2
->ulCodePageRange1
);
1360 props
->fontsig
.fsCsb
[1] = GET_BE_DWORD(tt_os2
->ulCodePageRange2
);
1364 USHORT macStyle
= GET_BE_WORD(tt_head
->macStyle
);
1366 if (macStyle
& TT_HEAD_MACSTYLE_CONDENSED
)
1367 props
->stretch
= DWRITE_FONT_STRETCH_CONDENSED
;
1368 else if (macStyle
& TT_HEAD_MACSTYLE_EXTENDED
)
1369 props
->stretch
= DWRITE_FONT_STRETCH_EXPANDED
;
1371 if (macStyle
& TT_HEAD_MACSTYLE_BOLD
)
1372 props
->weight
= DWRITE_FONT_WEIGHT_BOLD
;
1374 if (macStyle
& TT_HEAD_MACSTYLE_ITALIC
)
1375 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
1378 props
->lf
.lfWeight
= props
->weight
;
1379 props
->lf
.lfItalic
= props
->style
== DWRITE_FONT_STYLE_ITALIC
;
1381 TRACE("stretch=%d, weight=%d, style %d\n", props
->stretch
, props
->weight
, props
->style
);
1384 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1386 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, head_context
);
1389 static UINT
get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform
, USHORT encoding
)
1394 case OPENTYPE_PLATFORM_UNICODE
:
1396 case OPENTYPE_PLATFORM_MAC
:
1399 case TT_NAME_MAC_ENCODING_ROMAN
:
1402 case TT_NAME_MAC_ENCODING_JAPANESE
:
1405 case TT_NAME_MAC_ENCODING_TRAD_CHINESE
:
1408 case TT_NAME_MAC_ENCODING_KOREAN
:
1411 case TT_NAME_MAC_ENCODING_ARABIC
:
1414 case TT_NAME_MAC_ENCODING_HEBREW
:
1417 case TT_NAME_MAC_ENCODING_GREEK
:
1420 case TT_NAME_MAC_ENCODING_RUSSIAN
:
1423 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE
:
1426 case TT_NAME_MAC_ENCODING_THAI
:
1430 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1434 case OPENTYPE_PLATFORM_WIN
:
1437 case TT_NAME_WINDOWS_ENCODING_SYMBOL
:
1438 case TT_NAME_WINDOWS_ENCODING_UCS2
:
1440 case TT_NAME_WINDOWS_ENCODING_SJIS
:
1443 case TT_NAME_WINDOWS_ENCODING_PRC
:
1446 case TT_NAME_WINDOWS_ENCODING_BIG5
:
1449 case TT_NAME_WINDOWS_ENCODING_WANSUNG
:
1452 case TT_NAME_WINDOWS_ENCODING_JOHAB
:
1456 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1461 FIXME("unknown platform %d\n", platform
);
1467 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform
, USHORT lang_id
, WCHAR
*locale
, USHORT locale_len
)
1469 static const WCHAR enusW
[] = {'e','n','-','U','S',0};
1472 case OPENTYPE_PLATFORM_MAC
:
1474 const char *locale_name
= NULL
;
1476 if (lang_id
> TT_NAME_MAC_LANGID_AZER_ROMAN
)
1477 WARN("invalid mac lang id %d\n", lang_id
);
1478 else if (!name_mac_langid_to_locale
[lang_id
][0])
1479 FIXME("failed to map mac lang id %d to locale name\n", lang_id
);
1481 locale_name
= name_mac_langid_to_locale
[lang_id
];
1484 MultiByteToWideChar(CP_ACP
, 0, name_mac_langid_to_locale
[lang_id
], -1, locale
, locale_len
);
1486 strcpyW(locale
, enusW
);
1489 case OPENTYPE_PLATFORM_WIN
:
1490 if (!LCIDToLocaleName(MAKELCID(lang_id
, SORT_DEFAULT
), locale
, locale_len
, 0)) {
1491 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id
, SORT_DEFAULT
));
1492 strcpyW(locale
, enusW
);
1495 case OPENTYPE_PLATFORM_UNICODE
:
1496 strcpyW(locale
, enusW
);
1499 FIXME("unknown platform %d\n", platform
);
1503 static BOOL
opentype_decode_namerecord(const TT_NAME_V0
*header
, BYTE
*storage_area
, USHORT recid
, IDWriteLocalizedStrings
*strings
)
1505 const TT_NameRecord
*record
= &header
->nameRecord
[recid
];
1506 USHORT lang_id
, length
, offset
, encoding
, platform
;
1509 platform
= GET_BE_WORD(record
->platformID
);
1510 lang_id
= GET_BE_WORD(record
->languageID
);
1511 length
= GET_BE_WORD(record
->length
);
1512 offset
= GET_BE_WORD(record
->offset
);
1513 encoding
= GET_BE_WORD(record
->encodingID
);
1515 if (lang_id
< 0x8000) {
1516 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
1520 codepage
= get_name_record_codepage(platform
, encoding
);
1521 get_name_record_locale(platform
, lang_id
, locale
, sizeof(locale
)/sizeof(WCHAR
));
1524 DWORD len
= MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, NULL
, 0);
1525 name_string
= heap_alloc(sizeof(WCHAR
) * (len
+1));
1526 MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, name_string
, len
);
1527 name_string
[len
] = 0;
1532 length
/= sizeof(WCHAR
);
1533 name_string
= heap_strdupnW((LPWSTR
)(storage_area
+ offset
), length
);
1534 for (i
= 0; i
< length
; i
++)
1535 name_string
[i
] = GET_BE_WORD(name_string
[i
]);
1538 TRACE("string %s for locale %s found\n", debugstr_w(name_string
), debugstr_w(locale
));
1539 add_localizedstring(strings
, locale
, name_string
);
1540 heap_free(name_string
);
1544 FIXME("handle NAME format 1\n");
1549 static HRESULT
opentype_get_font_strings_from_id(const void *table_data
, enum OPENTYPE_STRING_ID id
, IDWriteLocalizedStrings
**strings
)
1551 const TT_NAME_V0
*header
;
1552 BYTE
*storage_area
= 0;
1562 hr
= create_localizedstrings(strings
);
1563 if (FAILED(hr
)) return hr
;
1565 header
= table_data
;
1566 format
= GET_BE_WORD(header
->format
);
1573 FIXME("unsupported NAME format %d\n", format
);
1576 storage_area
= (LPBYTE
)table_data
+ GET_BE_WORD(header
->stringOffset
);
1577 count
= GET_BE_WORD(header
->count
);
1581 for (i
= 0; i
< count
; i
++) {
1582 const TT_NameRecord
*record
= &header
->nameRecord
[i
];
1585 if (GET_BE_WORD(record
->nameID
) != id
)
1588 /* Right now only accept unicode and windows encoded fonts */
1589 platform
= GET_BE_WORD(record
->platformID
);
1590 if (platform
!= OPENTYPE_PLATFORM_UNICODE
&&
1591 platform
!= OPENTYPE_PLATFORM_MAC
&&
1592 platform
!= OPENTYPE_PLATFORM_WIN
)
1594 FIXME("platform %i not supported\n", platform
);
1598 /* Skip such entries for now, fonts tend to duplicate those strings as
1599 WIN platform entries. If font does not have WIN or MAC entry for this id, we will
1600 use this Unicode platform entry while assuming en-US locale. */
1601 if (platform
== OPENTYPE_PLATFORM_UNICODE
) {
1606 if (!opentype_decode_namerecord(header
, storage_area
, i
, *strings
))
1613 if (candidate
!= -1)
1614 exists
= opentype_decode_namerecord(header
, storage_area
, candidate
, *strings
);
1616 IDWriteLocalizedStrings_Release(*strings
);
1621 return exists
? S_OK
: E_FAIL
;
1624 /* Provides a conversion from DWRITE to OpenType name ids, input id should be valid, it's not checked. */
1625 HRESULT
opentype_get_font_info_strings(const void *table_data
, DWRITE_INFORMATIONAL_STRING_ID id
, IDWriteLocalizedStrings
**strings
)
1627 return opentype_get_font_strings_from_id(table_data
, dwriteid_to_opentypeid
[id
], strings
);
1630 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
1631 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
1632 HRESULT
opentype_get_font_familyname(struct file_stream_desc
*stream_desc
, IDWriteLocalizedStrings
**names
)
1634 const TT_OS2_V2
*tt_os2
;
1635 void *os2_context
, *name_context
;
1636 const void *name_table
;
1639 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1640 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name_table
, &name_context
, NULL
, NULL
);
1644 /* if Preferred Family doesn't conform to WWS model try WWS name */
1645 if (tt_os2
&& !(GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_WWS
))
1646 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_WWS_FAMILY_NAME
, names
);
1651 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_PREFERRED_FAMILY_NAME
, names
);
1653 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_FAMILY_NAME
, names
);
1656 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1658 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name_context
);
1663 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
1664 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
1665 HRESULT
opentype_get_font_facename(struct file_stream_desc
*stream_desc
, WCHAR
*lfname
, IDWriteLocalizedStrings
**names
)
1667 IDWriteLocalizedStrings
*lfnames
;
1668 void *os2_context
, *name_context
;
1669 const TT_OS2_V2
*tt_os2
;
1670 const void *name_table
;
1673 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1674 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name_table
, &name_context
, NULL
, NULL
);
1678 /* if Preferred Family doesn't conform to WWS model try WWS name */
1679 if (tt_os2
&& !(GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_WWS
))
1680 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_WWS_SUBFAMILY_NAME
, names
);
1685 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
, names
);
1687 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_SUBFAMILY_NAME
, names
);
1689 /* User locale is preferred, with fallback to en-us. */
1691 if (SUCCEEDED(opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_FAMILY_NAME
, &lfnames
))) {
1692 static const WCHAR enusW
[] = {'e','n','-','u','s',0};
1693 WCHAR localeW
[LOCALE_NAME_MAX_LENGTH
];
1698 if (GetSystemDefaultLocaleName(localeW
, sizeof(localeW
)/sizeof(WCHAR
)))
1699 IDWriteLocalizedStrings_FindLocaleName(lfnames
, localeW
, &index
, &exists
);
1702 IDWriteLocalizedStrings_FindLocaleName(lfnames
, enusW
, &index
, &exists
);
1705 IDWriteLocalizedStrings_GetString(lfnames
, index
, lfname
, LF_FACESIZE
);
1707 IDWriteLocalizedStrings_Release(lfnames
);
1711 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1713 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name_context
);
1718 static inline const OT_Script
*opentype_get_script(const OT_ScriptList
*scriptlist
, UINT32 scripttag
)
1722 for (j
= 0; j
< GET_BE_WORD(scriptlist
->ScriptCount
); j
++) {
1723 const char *tag
= scriptlist
->ScriptRecord
[j
].ScriptTag
;
1724 if (scripttag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1725 return (OT_Script
*)((BYTE
*)scriptlist
+ GET_BE_WORD(scriptlist
->ScriptRecord
[j
].Script
));
1731 static inline const OT_LangSys
*opentype_get_langsys(const OT_Script
*script
, UINT32 languagetag
)
1735 for (j
= 0; j
< GET_BE_WORD(script
->LangSysCount
); j
++) {
1736 const char *tag
= script
->LangSysRecord
[j
].LangSysTag
;
1737 if (languagetag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1738 return (OT_LangSys
*)((BYTE
*)script
+ GET_BE_WORD(script
->LangSysRecord
[j
].LangSys
));
1744 static void opentype_add_font_features(const GPOS_GSUB_Header
*header
, const OT_LangSys
*langsys
,
1745 UINT32 max_tagcount
, UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1747 const OT_FeatureList
*features
= (const OT_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1750 for (j
= 0; j
< GET_BE_WORD(langsys
->FeatureCount
); j
++) {
1751 const OT_FeatureRecord
*feature
= &features
->FeatureRecord
[langsys
->FeatureIndex
[j
]];
1752 const char *tag
= feature
->FeatureTag
;
1754 if (*count
< max_tagcount
)
1755 tags
[*count
] = DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]);
1761 HRESULT
opentype_get_typographic_features(IDWriteFontFace
*fontface
, UINT32 scripttag
, UINT32 languagetag
, UINT32 max_tagcount
,
1762 UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1764 UINT32 tables
[2] = { MS_GSUB_TAG
, MS_GPOS_TAG
};
1769 for (i
= 0; i
< sizeof(tables
)/sizeof(tables
[0]); i
++) {
1770 const OT_ScriptList
*scriptlist
;
1771 const GPOS_GSUB_Header
*header
;
1772 const OT_Script
*script
;
1779 hr
= IDWriteFontFace_TryGetFontTable(fontface
, tables
[i
], &ptr
, &size
, &context
, &exists
);
1786 header
= (const GPOS_GSUB_Header
*)ptr
;
1787 scriptlist
= (const OT_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
1789 script
= opentype_get_script(scriptlist
, scripttag
);
1791 const OT_LangSys
*langsys
= opentype_get_langsys(script
, languagetag
);
1793 opentype_add_font_features(header
, langsys
, max_tagcount
, count
, tags
);
1796 IDWriteFontFace_ReleaseFontTable(fontface
, context
);
1799 return *count
> max_tagcount
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
1802 static const struct VDMX_group
*find_vdmx_group(const struct VDMX_Header
*hdr
)
1804 WORD num_ratios
, i
, group_offset
= 0;
1805 struct VDMX_Ratio
*ratios
= (struct VDMX_Ratio
*)(hdr
+ 1);
1806 BYTE dev_x_ratio
= 1, dev_y_ratio
= 1;
1808 num_ratios
= GET_BE_WORD(hdr
->numRatios
);
1810 for (i
= 0; i
< num_ratios
; i
++) {
1812 if (!ratios
[i
].bCharSet
) continue;
1814 if ((ratios
[i
].xRatio
== 0 && ratios
[i
].yStartRatio
== 0 &&
1815 ratios
[i
].yEndRatio
== 0) ||
1816 (ratios
[i
].xRatio
== dev_x_ratio
&& ratios
[i
].yStartRatio
<= dev_y_ratio
&&
1817 ratios
[i
].yEndRatio
>= dev_y_ratio
))
1819 group_offset
= GET_BE_WORD(*((WORD
*)(ratios
+ num_ratios
) + i
));
1824 return (const struct VDMX_group
*)((BYTE
*)hdr
+ group_offset
);
1828 BOOL
opentype_get_vdmx_size(const void *data
, INT emsize
, UINT16
*ascent
, UINT16
*descent
)
1830 const struct VDMX_Header
*hdr
= (const struct VDMX_Header
*)data
;
1831 const struct VDMX_group
*group
;
1832 const struct VDMX_vTable
*tables
;
1838 group
= find_vdmx_group(hdr
);
1842 recs
= GET_BE_WORD(group
->recs
);
1843 if (emsize
< group
->startsz
|| emsize
>= group
->endsz
) return FALSE
;
1845 tables
= (const struct VDMX_vTable
*)(group
+ 1);
1846 for (i
= 0; i
< recs
; i
++) {
1847 WORD ppem
= GET_BE_WORD(tables
[i
].yPelHeight
);
1848 if (ppem
> emsize
) {
1849 FIXME("interpolate %d\n", emsize
);
1853 if (ppem
== emsize
) {
1854 *ascent
= (SHORT
)GET_BE_WORD(tables
[i
].yMax
);
1855 *descent
= -(SHORT
)GET_BE_WORD(tables
[i
].yMin
);
1862 WORD
opentype_get_gasp_flags(const WORD
*ptr
, UINT32 size
, INT emsize
)
1864 WORD num_recs
, version
;
1870 version
= GET_BE_WORD( *ptr
++ );
1871 num_recs
= GET_BE_WORD( *ptr
++ );
1872 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
)) {
1873 ERR("unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
1877 while (num_recs
--) {
1878 flags
= GET_BE_WORD( *(ptr
+ 1) );
1879 if (emsize
<= GET_BE_WORD( *ptr
)) break;
1887 UINT32
opentype_get_cpal_palettecount(const void *cpal
)
1889 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1890 return header
? GET_BE_WORD(header
->numPalette
) : 0;
1893 UINT32
opentype_get_cpal_paletteentrycount(const void *cpal
)
1895 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1896 return header
? GET_BE_WORD(header
->numPaletteEntries
) : 0;
1899 HRESULT
opentype_get_cpal_entries(const void *cpal
, UINT32 palette
, UINT32 first_entry_index
, UINT32 entry_count
,
1900 DWRITE_COLOR_F
*entries
)
1902 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1903 const struct CPAL_ColorRecord
*records
;
1904 UINT32 palettecount
, entrycount
, i
;
1906 if (!header
) return DWRITE_E_NOCOLOR
;
1908 palettecount
= GET_BE_WORD(header
->numPalette
);
1909 if (palette
>= palettecount
)
1910 return DWRITE_E_NOCOLOR
;
1912 entrycount
= GET_BE_WORD(header
->numPaletteEntries
);
1913 if (first_entry_index
+ entry_count
> entrycount
)
1914 return E_INVALIDARG
;
1916 records
= (const struct CPAL_ColorRecord
*)((BYTE
*)cpal
+ GET_BE_DWORD(header
->offsetFirstColorRecord
));
1917 first_entry_index
+= GET_BE_WORD(header
->colorRecordIndices
[palette
]);
1919 for (i
= 0; i
< entry_count
; i
++) {
1920 entries
[i
].u1
.r
= records
[first_entry_index
+ i
].red
/ 255.0f
;
1921 entries
[i
].u2
.g
= records
[first_entry_index
+ i
].green
/ 255.0f
;
1922 entries
[i
].u3
.b
= records
[first_entry_index
+ i
].blue
/ 255.0f
;
1923 entries
[i
].u4
.a
= records
[first_entry_index
+ i
].alpha
/ 255.0f
;
1929 static int colr_compare_gid(const void *g
, const void *r
)
1931 const struct COLR_BaseGlyphRecord
*record
= r
;
1932 UINT16 glyph
= *(UINT16
*)g
, GID
= GET_BE_WORD(record
->GID
);
1937 else if (glyph
< GID
)
1943 HRESULT
opentype_get_colr_glyph(const void *colr
, UINT16 glyph
, struct dwrite_colorglyph
*ret
)
1945 const struct COLR_BaseGlyphRecord
*record
;
1946 const struct COLR_Header
*header
= colr
;
1947 const struct COLR_LayerRecord
*layer
;
1948 DWORD layerrecordoffset
= GET_BE_DWORD(header
->offsetLayerRecord
);
1949 DWORD baserecordoffset
= GET_BE_DWORD(header
->offsetBaseGlyphRecord
);
1950 WORD numbaserecords
= GET_BE_WORD(header
->numBaseGlyphRecords
);
1952 record
= bsearch(&glyph
, (BYTE
*)colr
+ baserecordoffset
, numbaserecords
, sizeof(struct COLR_BaseGlyphRecord
),
1956 ret
->first_layer
= 0;
1957 ret
->num_layers
= 0;
1959 ret
->palette_index
= 0xffff;
1964 ret
->first_layer
= GET_BE_WORD(record
->firstLayerIndex
);
1965 ret
->num_layers
= GET_BE_WORD(record
->numLayers
);
1967 layer
= (struct COLR_LayerRecord
*)((BYTE
*)colr
+ layerrecordoffset
) + ret
->first_layer
+ ret
->layer
;
1968 ret
->glyph
= GET_BE_WORD(layer
->GID
);
1969 ret
->palette_index
= GET_BE_WORD(layer
->paletteIndex
);
1974 void opentype_colr_next_glyph(const void *colr
, struct dwrite_colorglyph
*glyph
)
1976 const struct COLR_Header
*header
= colr
;
1977 const struct COLR_LayerRecord
*layer
;
1978 DWORD layerrecordoffset
= GET_BE_DWORD(header
->offsetLayerRecord
);
1980 /* iterated all the way through */
1981 if (glyph
->layer
== glyph
->num_layers
)
1985 layer
= (struct COLR_LayerRecord
*)((BYTE
*)colr
+ layerrecordoffset
) + glyph
->first_layer
+ glyph
->layer
;
1986 glyph
->glyph
= GET_BE_WORD(layer
->GID
);
1987 glyph
->palette_index
= GET_BE_WORD(layer
->paletteIndex
);
1990 BOOL
opentype_has_vertical_variants(IDWriteFontFace4
*fontface
)
1992 const OT_FeatureList
*featurelist
;
1993 const OT_LookupList
*lookup_list
;
1994 BOOL exists
= FALSE
, ret
= FALSE
;
1995 const GPOS_GSUB_Header
*header
;
2002 hr
= IDWriteFontFace4_TryGetFontTable(fontface
, MS_GSUB_TAG
, &data
, &size
, &context
, &exists
);
2003 if (FAILED(hr
) || !exists
)
2007 featurelist
= (OT_FeatureList
*)((BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
2008 lookup_list
= (const OT_LookupList
*)((BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
2010 for (i
= 0; i
< GET_BE_WORD(featurelist
->FeatureCount
); i
++) {
2011 if (*(UINT32
*)featurelist
->FeatureRecord
[i
].FeatureTag
== DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING
) {
2012 const OT_Feature
*feature
= (const OT_Feature
*)((BYTE
*)featurelist
+ GET_BE_WORD(featurelist
->FeatureRecord
[i
].Feature
));
2013 UINT16 lookup_count
= GET_BE_WORD(feature
->LookupCount
), i
, index
, count
, type
;
2014 const GSUB_SingleSubstFormat2
*subst2
;
2015 const OT_LookupTable
*lookup_table
;
2018 if (lookup_count
== 0)
2021 for (i
= 0; i
< lookup_count
; i
++) {
2022 /* check if lookup is empty */
2023 index
= GET_BE_WORD(feature
->LookupListIndex
[i
]);
2024 lookup_table
= (const OT_LookupTable
*)((BYTE
*)lookup_list
+ GET_BE_WORD(lookup_list
->Lookup
[index
]));
2026 type
= GET_BE_WORD(lookup_table
->LookupType
);
2027 if (type
!= OPENTYPE_GPOS_SINGLE_SUBST
&& type
!= OPENTYPE_GPOS_EXTENSION_SUBST
)
2030 count
= GET_BE_WORD(lookup_table
->SubTableCount
);
2034 offset
= GET_BE_WORD(lookup_table
->SubTable
[0]);
2035 if (type
== OPENTYPE_GPOS_EXTENSION_SUBST
) {
2036 const GSUB_ExtensionPosFormat1
*ext
= (const GSUB_ExtensionPosFormat1
*)((const BYTE
*)lookup_table
+ offset
);
2037 if (GET_BE_WORD(ext
->SubstFormat
) == 1)
2038 offset
+= GET_BE_DWORD(ext
->ExtensionOffset
);
2040 FIXME("Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext
->SubstFormat
));
2043 subst2
= (const GSUB_SingleSubstFormat2
*)((BYTE
*)lookup_table
+ offset
);
2044 index
= GET_BE_WORD(subst2
->SubstFormat
);
2046 FIXME("Validate Single Substitution Format 1\n");
2047 else if (index
== 2) {
2048 /* SimSun-ExtB has 0 glyph count for this substitution */
2049 if (GET_BE_WORD(subst2
->GlyphCount
) > 0) {
2055 WARN("Unknown Single Substitution Format, %u\n", index
);
2060 IDWriteFontFace4_ReleaseFontTable(fontface
, context
);
2065 static BOOL
opentype_has_font_table(IDWriteFontFace4
*fontface
, UINT32 tag
)
2067 BOOL exists
= FALSE
;
2073 hr
= IDWriteFontFace4_TryGetFontTable(fontface
, tag
, &data
, &size
, &context
, &exists
);
2078 IDWriteFontFace4_ReleaseFontTable(fontface
, context
);
2083 static DWORD
opentype_get_sbix_formats(IDWriteFontFace4
*fontface
)
2085 UINT32 size
, s
, num_strikes
;
2086 const sbix_header
*header
;
2087 UINT16 g
, num_glyphs
;
2088 BOOL exists
= FALSE
;
2095 hr
= IDWriteFontFace4_TryGetFontTable(fontface
, MS_MAXP_TAG
, &data
, &size
, &context
, &exists
);
2096 if (FAILED(hr
) || !exists
)
2100 num_glyphs
= GET_BE_WORD(maxp
->numGlyphs
);
2102 IDWriteFontFace4_ReleaseFontTable(fontface
, context
);
2104 if (FAILED(IDWriteFontFace4_TryGetFontTable(fontface
, MS_SBIX_TAG
, &data
, &size
, &context
, &exists
))) {
2105 WARN("Failed to get 'sbix' table, %#x\n", hr
);
2110 num_strikes
= GET_BE_DWORD(header
->numStrikes
);
2112 for (s
= 0; s
< num_strikes
; s
++) {
2113 sbix_strike
*strike
= (sbix_strike
*)((BYTE
*)header
+ GET_BE_DWORD(header
->strikeOffset
[s
]));
2115 for (g
= 0; g
< num_glyphs
; g
++) {
2116 DWORD offset
= GET_BE_DWORD(strike
->glyphDataOffsets
[g
]);
2117 DWORD offset_next
= GET_BE_DWORD(strike
->glyphDataOffsets
[g
+ 1]);
2118 sbix_glyph_data
*glyph_data
;
2121 if (offset
== offset_next
)
2124 glyph_data
= (sbix_glyph_data
*)((BYTE
*)strike
+ offset
);
2125 switch (format
= glyph_data
->graphicType
)
2128 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_PNG
;
2131 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_JPEG
;
2134 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_TIFF
;
2137 format
= GET_BE_DWORD(format
);
2138 FIXME("unexpected bitmap format %s\n", debugstr_an((char *)&format
, 4));
2143 IDWriteFontFace4_ReleaseFontTable(fontface
, context
);
2148 UINT32
opentype_get_glyph_image_formats(IDWriteFontFace4
*fontface
)
2150 UINT32 ret
= DWRITE_GLYPH_IMAGE_FORMATS_NONE
;
2152 if (opentype_has_font_table(fontface
, MS_GLYF_TAG
))
2153 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE
;
2155 if (opentype_has_font_table(fontface
, MS_CFF__TAG
))
2156 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_CFF
;
2158 if (opentype_has_font_table(fontface
, MS_COLR_TAG
))
2159 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_COLR
;
2161 if (opentype_has_font_table(fontface
, MS_SVG__TAG
))
2162 ret
|= DWRITE_GLYPH_IMAGE_FORMATS_SVG
;
2164 if (opentype_has_font_table(fontface
, MS_SBIX_TAG
))
2165 ret
|= opentype_get_sbix_formats(fontface
);
2167 /* TODO: handle embedded bitmaps tables */