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
23 #include "dwrite_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
28 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
29 #define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
30 #define MS_OTTO_TAG DWRITE_MAKE_OPENTYPE_TAG('O','T','T','O')
31 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
32 #define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
33 #define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f')
34 #define MS_GPOS_TAG DWRITE_MAKE_OPENTYPE_TAG('G','P','O','S')
35 #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B')
36 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
38 #ifdef WORDS_BIGENDIAN
39 #define GET_BE_WORD(x) (x)
40 #define GET_BE_DWORD(x) (x)
42 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
43 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
72 } CMAP_EncodingRecord
;
77 CMAP_EncodingRecord tables
[1];
84 } CMAP_SegmentedCoverage_group
;
92 CMAP_SegmentedCoverage_group groups
[1];
93 } CMAP_SegmentedCoverage
;
104 } CMAP_SegmentMapping_0
;
106 enum OPENTYPE_CMAP_TABLE_FORMAT
108 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
= 4,
109 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
= 12
112 /* PANOSE is 10 bytes in size, need to pack the structure properly */
113 #include "pshpack2.h"
130 USHORT lowestRecPPEM
;
131 SHORT direction_hint
;
133 SHORT glyphdata_format
;
136 enum TT_HEAD_MACSTYLE
138 TT_HEAD_MACSTYLE_BOLD
= 1 << 0,
139 TT_HEAD_MACSTYLE_ITALIC
= 1 << 1,
140 TT_HEAD_MACSTYLE_UNDERLINE
= 1 << 2,
141 TT_HEAD_MACSTYLE_OUTLINE
= 1 << 3,
142 TT_HEAD_MACSTYLE_SHADOW
= 1 << 4,
143 TT_HEAD_MACSTYLE_CONDENSED
= 1 << 5,
144 TT_HEAD_MACSTYLE_EXTENDED
= 1 << 6,
151 SHORT underlinePosition
;
152 SHORT underlineThickness
;
164 USHORT usWeightClass
;
167 SHORT ySubscriptXSize
;
168 SHORT ySubscriptYSize
;
169 SHORT ySubscriptXOffset
;
170 SHORT ySubscriptYOffset
;
171 SHORT ySuperscriptXSize
;
172 SHORT ySuperscriptYSize
;
173 SHORT ySuperscriptXOffset
;
174 SHORT ySuperscriptYOffset
;
175 SHORT yStrikeoutSize
;
176 SHORT yStrikeoutPosition
;
179 ULONG ulUnicodeRange1
;
180 ULONG ulUnicodeRange2
;
181 ULONG ulUnicodeRange3
;
182 ULONG ulUnicodeRange4
;
185 USHORT usFirstCharIndex
;
186 USHORT usLastCharIndex
;
187 /* According to the Apple spec, original version didn't have the below fields,
188 * version numbers were taken from the OpenType spec.
190 /* version 0 (TrueType 1.5) */
191 USHORT sTypoAscender
;
192 USHORT sTypoDescender
;
196 /* version 1 (TrueType 1.66) */
197 ULONG ulCodePageRange1
;
198 ULONG ulCodePageRange2
;
199 /* version 2 (OpenType 1.2) */
202 USHORT usDefaultChar
;
213 USHORT advanceWidthMax
;
214 SHORT minLeftSideBearing
;
215 SHORT minRightSideBearing
;
217 SHORT caretSlopeRise
;
221 SHORT metricDataFormat
;
222 USHORT numberOfHMetrics
;
227 enum OS2_FSSELECTION
{
228 OS2_FSSELECTION_ITALIC
= 1 << 0,
229 OS2_FSSELECTION_UNDERSCORE
= 1 << 1,
230 OS2_FSSELECTION_NEGATIVE
= 1 << 2,
231 OS2_FSSELECTION_OUTLINED
= 1 << 3,
232 OS2_FSSELECTION_STRIKEOUT
= 1 << 4,
233 OS2_FSSELECTION_BOLD
= 1 << 5,
234 OS2_FSSELECTION_REGULAR
= 1 << 6,
235 OS2_FSSELECTION_USE_TYPO_METRICS
= 1 << 7,
236 OS2_FSSELECTION_WWS
= 1 << 8,
237 OS2_FSSELECTION_OBLIQUE
= 1 << 9
253 TT_NameRecord nameRecord
[1];
292 OT_FeatureRecord FeatureRecord
[1];
296 WORD LookupOrder
; /* Reserved */
297 WORD ReqFeatureIndex
;
299 WORD FeatureIndex
[1];
310 OT_LangSysRecord LangSysRecord
[1];
320 OT_ScriptRecord ScriptRecord
[1];
330 enum OPENTYPE_PLATFORM_ID
332 OPENTYPE_PLATFORM_UNICODE
= 0,
333 OPENTYPE_PLATFORM_MAC
,
334 OPENTYPE_PLATFORM_ISO
,
335 OPENTYPE_PLATFORM_WIN
,
336 OPENTYPE_PLATFORM_CUSTOM
342 WORD LookupListIndex
[1];
361 } GSUB_SingleSubstFormat1
;
368 } GSUB_SingleSubstFormat2
;
372 WORD ExtensionLookupType
;
373 DWORD ExtensionOffset
;
374 } GSUB_ExtensionPosFormat1
;
376 enum OPENTYPE_GPOS_LOOKUPS
378 OPENTYPE_GPOS_SINGLE_SUBST
= 1,
379 OPENTYPE_GPOS_EXTENSION_SUBST
= 7
382 enum TT_NAME_WINDOWS_ENCODING_ID
384 TT_NAME_WINDOWS_ENCODING_SYMBOL
= 0,
385 TT_NAME_WINDOWS_ENCODING_UCS2
,
386 TT_NAME_WINDOWS_ENCODING_SJIS
,
387 TT_NAME_WINDOWS_ENCODING_PRC
,
388 TT_NAME_WINDOWS_ENCODING_BIG5
,
389 TT_NAME_WINDOWS_ENCODING_WANSUNG
,
390 TT_NAME_WINDOWS_ENCODING_JOHAB
,
391 TT_NAME_WINDOWS_ENCODING_RESERVED1
,
392 TT_NAME_WINDOWS_ENCODING_RESERVED2
,
393 TT_NAME_WINDOWS_ENCODING_RESERVED3
,
394 TT_NAME_WINDOWS_ENCODING_UCS4
397 enum TT_NAME_MAC_ENCODING_ID
399 TT_NAME_MAC_ENCODING_ROMAN
= 0,
400 TT_NAME_MAC_ENCODING_JAPANESE
,
401 TT_NAME_MAC_ENCODING_TRAD_CHINESE
,
402 TT_NAME_MAC_ENCODING_KOREAN
,
403 TT_NAME_MAC_ENCODING_ARABIC
,
404 TT_NAME_MAC_ENCODING_HEBREW
,
405 TT_NAME_MAC_ENCODING_GREEK
,
406 TT_NAME_MAC_ENCODING_RUSSIAN
,
407 TT_NAME_MAC_ENCODING_RSYMBOL
,
408 TT_NAME_MAC_ENCODING_DEVANAGARI
,
409 TT_NAME_MAC_ENCODING_GURMUKHI
,
410 TT_NAME_MAC_ENCODING_GUJARATI
,
411 TT_NAME_MAC_ENCODING_ORIYA
,
412 TT_NAME_MAC_ENCODING_BENGALI
,
413 TT_NAME_MAC_ENCODING_TAMIL
,
414 TT_NAME_MAC_ENCODING_TELUGU
,
415 TT_NAME_MAC_ENCODING_KANNADA
,
416 TT_NAME_MAC_ENCODING_MALAYALAM
,
417 TT_NAME_MAC_ENCODING_SINHALESE
,
418 TT_NAME_MAC_ENCODING_BURMESE
,
419 TT_NAME_MAC_ENCODING_KHMER
,
420 TT_NAME_MAC_ENCODING_THAI
,
421 TT_NAME_MAC_ENCODING_LAOTIAN
,
422 TT_NAME_MAC_ENCODING_GEORGIAN
,
423 TT_NAME_MAC_ENCODING_ARMENIAN
,
424 TT_NAME_MAC_ENCODING_SIMPL_CHINESE
,
425 TT_NAME_MAC_ENCODING_TIBETAN
,
426 TT_NAME_MAC_ENCODING_MONGOLIAN
,
427 TT_NAME_MAC_ENCODING_GEEZ
,
428 TT_NAME_MAC_ENCODING_SLAVIC
,
429 TT_NAME_MAC_ENCODING_VIETNAMESE
,
430 TT_NAME_MAC_ENCODING_SINDHI
,
431 TT_NAME_MAC_ENCODING_UNINTERPRETED
434 enum TT_NAME_MAC_LANGUAGE_ID
436 TT_NAME_MAC_LANGID_ENGLISH
= 0,
437 TT_NAME_MAC_LANGID_FRENCH
,
438 TT_NAME_MAC_LANGID_GERMAN
,
439 TT_NAME_MAC_LANGID_ITALIAN
,
440 TT_NAME_MAC_LANGID_DUTCH
,
441 TT_NAME_MAC_LANGID_SWEDISH
,
442 TT_NAME_MAC_LANGID_SPANISH
,
443 TT_NAME_MAC_LANGID_DANISH
,
444 TT_NAME_MAC_LANGID_PORTUGUESE
,
445 TT_NAME_MAC_LANGID_NORWEGIAN
,
446 TT_NAME_MAC_LANGID_HEBREW
,
447 TT_NAME_MAC_LANGID_JAPANESE
,
448 TT_NAME_MAC_LANGID_ARABIC
,
449 TT_NAME_MAC_LANGID_FINNISH
,
450 TT_NAME_MAC_LANGID_GREEK
,
451 TT_NAME_MAC_LANGID_ICELANDIC
,
452 TT_NAME_MAC_LANGID_MALTESE
,
453 TT_NAME_MAC_LANGID_TURKISH
,
454 TT_NAME_MAC_LANGID_CROATIAN
,
455 TT_NAME_MAC_LANGID_TRAD_CHINESE
,
456 TT_NAME_MAC_LANGID_URDU
,
457 TT_NAME_MAC_LANGID_HINDI
,
458 TT_NAME_MAC_LANGID_THAI
,
459 TT_NAME_MAC_LANGID_KOREAN
,
460 TT_NAME_MAC_LANGID_LITHUANIAN
,
461 TT_NAME_MAC_LANGID_POLISH
,
462 TT_NAME_MAC_LANGID_HUNGARIAN
,
463 TT_NAME_MAC_LANGID_ESTONIAN
,
464 TT_NAME_MAC_LANGID_LATVIAN
,
465 TT_NAME_MAC_LANGID_SAMI
,
466 TT_NAME_MAC_LANGID_FAROESE
,
467 TT_NAME_MAC_LANGID_FARSI
,
468 TT_NAME_MAC_LANGID_RUSSIAN
,
469 TT_NAME_MAC_LANGID_SIMPL_CHINESE
,
470 TT_NAME_MAC_LANGID_FLEMISH
,
471 TT_NAME_MAC_LANGID_GAELIC
,
472 TT_NAME_MAC_LANGID_ALBANIAN
,
473 TT_NAME_MAC_LANGID_ROMANIAN
,
474 TT_NAME_MAC_LANGID_CZECH
,
475 TT_NAME_MAC_LANGID_SLOVAK
,
476 TT_NAME_MAC_LANGID_SLOVENIAN
,
477 TT_NAME_MAC_LANGID_YIDDISH
,
478 TT_NAME_MAC_LANGID_SERBIAN
,
479 TT_NAME_MAC_LANGID_MACEDONIAN
,
480 TT_NAME_MAC_LANGID_BULGARIAN
,
481 TT_NAME_MAC_LANGID_UKRAINIAN
,
482 TT_NAME_MAC_LANGID_BYELORUSSIAN
,
483 TT_NAME_MAC_LANGID_UZBEK
,
484 TT_NAME_MAC_LANGID_KAZAKH
,
485 TT_NAME_MAC_LANGID_AZERB_CYR
,
486 TT_NAME_MAC_LANGID_AZERB_ARABIC
,
487 TT_NAME_MAC_LANGID_ARMENIAN
,
488 TT_NAME_MAC_LANGID_GEORGIAN
,
489 TT_NAME_MAC_LANGID_MOLDAVIAN
,
490 TT_NAME_MAC_LANGID_KIRGHIZ
,
491 TT_NAME_MAC_LANGID_TAJIKI
,
492 TT_NAME_MAC_LANGID_TURKMEN
,
493 TT_NAME_MAC_LANGID_MONGOLIAN
,
494 TT_NAME_MAC_LANGID_MONGOLIAN_CYR
,
495 TT_NAME_MAC_LANGID_PASHTO
,
496 TT_NAME_MAC_LANGID_KURDISH
,
497 TT_NAME_MAC_LANGID_KASHMIRI
,
498 TT_NAME_MAC_LANGID_SINDHI
,
499 TT_NAME_MAC_LANGID_TIBETAN
,
500 TT_NAME_MAC_LANGID_NEPALI
,
501 TT_NAME_MAC_LANGID_SANSKRIT
,
502 TT_NAME_MAC_LANGID_MARATHI
,
503 TT_NAME_MAC_LANGID_BENGALI
,
504 TT_NAME_MAC_LANGID_ASSAMESE
,
505 TT_NAME_MAC_LANGID_GUJARATI
,
506 TT_NAME_MAC_LANGID_PUNJABI
,
507 TT_NAME_MAC_LANGID_ORIYA
,
508 TT_NAME_MAC_LANGID_MALAYALAM
,
509 TT_NAME_MAC_LANGID_KANNADA
,
510 TT_NAME_MAC_LANGID_TAMIL
,
511 TT_NAME_MAC_LANGID_TELUGU
,
512 TT_NAME_MAC_LANGID_SINHALESE
,
513 TT_NAME_MAC_LANGID_BURMESE
,
514 TT_NAME_MAC_LANGID_KHMER
,
515 TT_NAME_MAC_LANGID_LAO
,
516 TT_NAME_MAC_LANGID_VIETNAMESE
,
517 TT_NAME_MAC_LANGID_INDONESIAN
,
518 TT_NAME_MAC_LANGID_TAGALOG
,
519 TT_NAME_MAC_LANGID_MALAY_ROMAN
,
520 TT_NAME_MAC_LANGID_MALAY_ARABIC
,
521 TT_NAME_MAC_LANGID_AMHARIC
,
522 TT_NAME_MAC_LANGID_TIGRINYA
,
523 TT_NAME_MAC_LANGID_GALLA
,
524 TT_NAME_MAC_LANGID_SOMALI
,
525 TT_NAME_MAC_LANGID_SWAHILI
,
526 TT_NAME_MAC_LANGID_KINYARWANDA
,
527 TT_NAME_MAC_LANGID_RUNDI
,
528 TT_NAME_MAC_LANGID_NYANJA
,
529 TT_NAME_MAC_LANGID_MALAGASY
,
530 TT_NAME_MAC_LANGID_ESPERANTO
,
531 TT_NAME_MAC_LANGID_WELSH
= 128,
532 TT_NAME_MAC_LANGID_BASQUE
,
533 TT_NAME_MAC_LANGID_CATALAN
,
534 TT_NAME_MAC_LANGID_LATIN
,
535 TT_NAME_MAC_LANGID_QUECHUA
,
536 TT_NAME_MAC_LANGID_GUARANI
,
537 TT_NAME_MAC_LANGID_AYMARA
,
538 TT_NAME_MAC_LANGID_TATAR
,
539 TT_NAME_MAC_LANGID_UIGHUR
,
540 TT_NAME_MAC_LANGID_DZONGKHA
,
541 TT_NAME_MAC_LANGID_JAVANESE
,
542 TT_NAME_MAC_LANGID_SUNDANESE
,
543 TT_NAME_MAC_LANGID_GALICIAN
,
544 TT_NAME_MAC_LANGID_AFRIKAANS
,
545 TT_NAME_MAC_LANGID_BRETON
,
546 TT_NAME_MAC_LANGID_INUKTITUT
,
547 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC
,
548 TT_NAME_MAC_LANGID_MANX_GAELIC
,
549 TT_NAME_MAC_LANGID_IRISH_GAELIC
,
550 TT_NAME_MAC_LANGID_TONGAN
,
551 TT_NAME_MAC_LANGID_GREEK_POLYTONIC
,
552 TT_NAME_MAC_LANGID_GREENLANDIC
,
553 TT_NAME_MAC_LANGID_AZER_ROMAN
556 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
557 static const char name_mac_langid_to_locale
[][10] = {
711 enum OPENTYPE_STRING_ID
713 OPENTYPE_STRING_COPYRIGHT_NOTICE
= 0,
714 OPENTYPE_STRING_FAMILY_NAME
,
715 OPENTYPE_STRING_SUBFAMILY_NAME
,
716 OPENTYPE_STRING_UNIQUE_IDENTIFIER
,
717 OPENTYPE_STRING_FULL_FONTNAME
,
718 OPENTYPE_STRING_VERSION_STRING
,
719 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
720 OPENTYPE_STRING_TRADEMARK
,
721 OPENTYPE_STRING_MANUFACTURER
,
722 OPENTYPE_STRING_DESIGNER
,
723 OPENTYPE_STRING_DESCRIPTION
,
724 OPENTYPE_STRING_VENDOR_URL
,
725 OPENTYPE_STRING_DESIGNER_URL
,
726 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
727 OPENTYPE_STRING_LICENSE_INFO_URL
,
728 OPENTYPE_STRING_RESERVED_ID15
,
729 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
730 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
731 OPENTYPE_STRING_COMPATIBLE_FULLNAME
,
732 OPENTYPE_STRING_SAMPLE_TEXT
,
733 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
734 OPENTYPE_STRING_WWS_FAMILY_NAME
,
735 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
738 static const UINT16 dwriteid_to_opentypeid
[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME
+1] =
740 (UINT16
)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
741 OPENTYPE_STRING_COPYRIGHT_NOTICE
,
742 OPENTYPE_STRING_VERSION_STRING
,
743 OPENTYPE_STRING_TRADEMARK
,
744 OPENTYPE_STRING_MANUFACTURER
,
745 OPENTYPE_STRING_DESIGNER
,
746 OPENTYPE_STRING_DESIGNER_URL
,
747 OPENTYPE_STRING_DESCRIPTION
,
748 OPENTYPE_STRING_VENDOR_URL
,
749 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
750 OPENTYPE_STRING_LICENSE_INFO_URL
,
751 OPENTYPE_STRING_FAMILY_NAME
,
752 OPENTYPE_STRING_SUBFAMILY_NAME
,
753 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
754 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
755 OPENTYPE_STRING_SAMPLE_TEXT
,
756 OPENTYPE_STRING_FULL_FONTNAME
,
757 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
758 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
765 USHORT numPaletteEntries
;
767 USHORT numColorRecords
;
768 ULONG offsetFirstColorRecord
;
769 USHORT colorRecordIndices
[1];
772 /* for version == 1, this comes after full CPAL_Header_0 */
773 struct CPAL_SubHeader_1
775 ULONG offsetPaletteTypeArray
;
776 ULONG offsetPaletteLabelArray
;
777 ULONG offsetPaletteEntryLabelArray
;
780 struct CPAL_ColorRecord
792 USHORT numBaseGlyphRecords
;
793 ULONG offsetBaseGlyphRecord
;
794 ULONG offsetLayerRecord
;
795 USHORT numLayerRecords
;
798 struct COLR_BaseGlyphRecord
801 USHORT firstLayerIndex
;
805 struct COLR_LayerRecord
811 BOOL
is_face_type_supported(DWRITE_FONT_FACE_TYPE type
)
813 return (type
== DWRITE_FONT_FACE_TYPE_CFF
) ||
814 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE
) ||
815 (type
== DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
) ||
816 (type
== DWRITE_FONT_FACE_TYPE_RAW_CFF
);
819 typedef HRESULT (*dwrite_fontfile_analyzer
)(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
820 DWRITE_FONT_FACE_TYPE
*face_type
);
822 static HRESULT
opentype_ttc_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
823 DWRITE_FONT_FACE_TYPE
*face_type
)
825 static const DWORD ttctag
= MS_TTCF_TAG
;
826 const TTC_Header_V1
*header
;
830 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(header
), &context
);
834 if (!memcmp(header
->TTCTag
, &ttctag
, sizeof(ttctag
))) {
835 *font_count
= GET_BE_DWORD(header
->numFonts
);
836 *file_type
= DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION
;
837 *face_type
= DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
;
840 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
842 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
845 static HRESULT
opentype_ttf_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
846 DWRITE_FONT_FACE_TYPE
*face_type
)
852 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
856 if (GET_BE_DWORD(*header
) == 0x10000) {
858 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE
;
859 *face_type
= DWRITE_FONT_FACE_TYPE_TRUETYPE
;
862 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
864 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
867 static HRESULT
opentype_otf_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
868 DWRITE_FONT_FACE_TYPE
*face_type
)
874 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
878 if (GET_BE_DWORD(*header
) == MS_OTTO_TAG
) {
880 *file_type
= DWRITE_FONT_FILE_TYPE_CFF
;
881 *face_type
= DWRITE_FONT_FACE_TYPE_CFF
;
884 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
886 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
889 static HRESULT
opentype_type1_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
890 DWRITE_FONT_FACE_TYPE
*face_type
)
892 #include "pshpack1.h"
893 /* Specified in Adobe TechNote #5178 */
902 struct type1_header
{
906 const struct type1_header
*header
;
910 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
914 /* tag is followed by plain text section */
915 if (header
->tag
== 0x8001 &&
916 (!memcmp(header
->data
, "%!PS-AdobeFont", 14) ||
917 !memcmp(header
->data
, "%!FontType", 10))) {
919 *file_type
= DWRITE_FONT_FILE_TYPE_TYPE1_PFB
;
920 *face_type
= DWRITE_FONT_FACE_TYPE_TYPE1
;
923 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
925 /* let's see if it's a .pfm metrics file */
926 if (*file_type
== DWRITE_FONT_FILE_TYPE_UNKNOWN
) {
927 const struct pfm_header
*pfm_header
;
932 hr
= IDWriteFontFileStream_GetFileSize(stream
, &filesize
);
936 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&pfm_header
, 0, sizeof(*pfm_header
), &context
);
940 offset
= pfm_header
->dfDevice
;
941 header_checked
= pfm_header
->dfVersion
== 0x100 && pfm_header
->dfSize
== filesize
;
942 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
944 /* as a last test check static string in PostScript information section */
945 if (header_checked
) {
946 static const char postscript
[] = "PostScript";
949 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&devtype_name
, offset
, sizeof(postscript
), &context
);
953 if (!memcmp(devtype_name
, postscript
, sizeof(postscript
))) {
955 *file_type
= DWRITE_FONT_FILE_TYPE_TYPE1_PFM
;
956 *face_type
= DWRITE_FONT_FACE_TYPE_TYPE1
;
959 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
963 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
966 HRESULT
opentype_analyze_font(IDWriteFontFileStream
*stream
, UINT32
* font_count
, DWRITE_FONT_FILE_TYPE
*file_type
, DWRITE_FONT_FACE_TYPE
*face_type
, BOOL
*supported
)
968 static dwrite_fontfile_analyzer fontfile_analyzers
[] = {
969 opentype_ttf_analyzer
,
970 opentype_otf_analyzer
,
971 opentype_ttc_analyzer
,
972 opentype_type1_analyzer
,
975 dwrite_fontfile_analyzer
*analyzer
= fontfile_analyzers
;
976 DWRITE_FONT_FACE_TYPE face
;
982 *file_type
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
983 *face_type
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
987 hr
= (*analyzer
)(stream
, font_count
, file_type
, face_type
);
997 *supported
= is_face_type_supported(*face_type
);
1001 HRESULT
opentype_get_font_table(struct file_stream_desc
*stream_desc
, UINT32 tag
, const void **table_data
,
1002 void **table_context
, UINT32
*table_size
, BOOL
*found
)
1005 TTC_SFNT_V1
*font_header
= NULL
;
1007 TT_TableRecord
*table_record
= NULL
;
1008 void *table_record_context
;
1009 int table_count
, table_offset
= 0;
1012 if (found
) *found
= FALSE
;
1013 if (table_size
) *table_size
= 0;
1016 *table_context
= NULL
;
1018 if (stream_desc
->face_type
== DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION
) {
1019 const TTC_Header_V1
*ttc_header
;
1021 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&ttc_header
, 0, sizeof(*ttc_header
), &ttc_context
);
1022 if (SUCCEEDED(hr
)) {
1023 if (stream_desc
->face_index
>= GET_BE_DWORD(ttc_header
->numFonts
))
1026 table_offset
= GET_BE_DWORD(ttc_header
->OffsetTable
[stream_desc
->face_index
]);
1027 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&font_header
, table_offset
, sizeof(*font_header
), &sfnt_context
);
1029 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, ttc_context
);
1033 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&font_header
, 0, sizeof(*font_header
), &sfnt_context
);
1038 table_count
= GET_BE_WORD(font_header
->numTables
);
1039 table_offset
+= sizeof(*font_header
);
1040 for (i
= 0; i
< table_count
; i
++)
1042 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&table_record
, table_offset
, sizeof(*table_record
), &table_record_context
);
1045 if (DWRITE_MAKE_OPENTYPE_TAG(table_record
->tag
[0], table_record
->tag
[1], table_record
->tag
[2], table_record
->tag
[3]) == tag
)
1047 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, table_record_context
);
1048 table_offset
+= sizeof(*table_record
);
1051 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, sfnt_context
);
1052 if (SUCCEEDED(hr
) && i
< table_count
)
1054 int offset
= GET_BE_DWORD(table_record
->offset
);
1055 int length
= GET_BE_DWORD(table_record
->length
);
1056 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, table_record_context
);
1058 if (found
) *found
= TRUE
;
1059 if (table_size
) *table_size
= length
;
1060 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, table_data
, offset
, length
, table_context
);
1070 static UINT32
opentype_cmap_get_unicode_ranges_count(const CMAP_Header
*CMAP_Table
)
1075 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
); i
++) {
1079 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
1082 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
1083 type
= GET_BE_WORD(*table
);
1084 TRACE("table type %i\n", type
);
1088 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
1090 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
1091 count
+= GET_BE_WORD(format
->segCountX2
)/2;
1094 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
1096 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
1097 count
+= GET_BE_DWORD(format
->nGroups
);
1101 FIXME("table type %i unhandled.\n", type
);
1108 HRESULT
opentype_cmap_get_unicode_ranges(void *data
, UINT32 max_count
, DWRITE_UNICODE_RANGE
*ranges
, UINT32
*count
)
1110 CMAP_Header
*CMAP_Table
= data
;
1116 *count
= opentype_cmap_get_unicode_ranges_count(CMAP_Table
);
1118 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
) && k
< max_count
; i
++)
1124 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
1127 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
1128 type
= GET_BE_WORD(*table
);
1129 TRACE("table type %i\n", type
);
1133 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
1135 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
1136 UINT16 segment_count
= GET_BE_WORD(format
->segCountX2
)/2;
1137 UINT16
*startCode
= (WORD
*)((BYTE
*)format
+ sizeof(CMAP_SegmentMapping_0
) + (sizeof(WORD
) * segment_count
));
1139 for (j
= 0; j
< segment_count
&& GET_BE_WORD(format
->endCode
[j
]) < 0xffff && k
< max_count
; j
++, k
++) {
1140 ranges
[k
].first
= GET_BE_WORD(startCode
[j
]);
1141 ranges
[k
].last
= GET_BE_WORD(format
->endCode
[j
]);
1145 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
1147 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
1148 for (j
= 0; j
< GET_BE_DWORD(format
->nGroups
) && k
< max_count
; j
++, k
++) {
1149 ranges
[k
].first
= GET_BE_DWORD(format
->groups
[j
].startCharCode
);
1150 ranges
[k
].last
= GET_BE_DWORD(format
->groups
[j
].endCharCode
);
1155 FIXME("table type %i unhandled.\n", type
);
1159 return *count
> max_count
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
1162 void opentype_get_font_metrics(struct file_stream_desc
*stream_desc
, DWRITE_FONT_METRICS1
*metrics
, DWRITE_CARET_METRICS
*caret
)
1164 void *os2_context
, *head_context
, *post_context
, *hhea_context
;
1165 const TT_OS2_V2
*tt_os2
;
1166 const TT_HEAD
*tt_head
;
1167 const TT_POST
*tt_post
;
1168 const TT_HHEA
*tt_hhea
;
1170 memset(metrics
, 0, sizeof(*metrics
));
1172 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1173 opentype_get_font_table(stream_desc
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
1174 opentype_get_font_table(stream_desc
, MS_POST_TAG
, (const void**)&tt_post
, &post_context
, NULL
, NULL
);
1175 opentype_get_font_table(stream_desc
, MS_HHEA_TAG
, (const void**)&tt_hhea
, &hhea_context
, NULL
, NULL
);
1178 metrics
->designUnitsPerEm
= GET_BE_WORD(tt_head
->unitsPerEm
);
1179 metrics
->glyphBoxLeft
= GET_BE_WORD(tt_head
->xMin
);
1180 metrics
->glyphBoxTop
= GET_BE_WORD(tt_head
->yMax
);
1181 metrics
->glyphBoxRight
= GET_BE_WORD(tt_head
->xMax
);
1182 metrics
->glyphBoxBottom
= GET_BE_WORD(tt_head
->yMin
);
1187 caret
->slopeRise
= GET_BE_WORD(tt_hhea
->caretSlopeRise
);
1188 caret
->slopeRun
= GET_BE_WORD(tt_hhea
->caretSlopeRun
);
1189 caret
->offset
= GET_BE_WORD(tt_hhea
->caretOffset
);
1192 caret
->slopeRise
= 0;
1193 caret
->slopeRun
= 0;
1199 USHORT version
= GET_BE_WORD(tt_os2
->version
);
1201 metrics
->ascent
= GET_BE_WORD(tt_os2
->usWinAscent
);
1202 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
1203 interpreted as large unsigned value. */
1204 metrics
->descent
= abs((SHORT
)GET_BE_WORD(tt_os2
->usWinDescent
));
1206 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
1208 SHORT descender
= (SHORT
)GET_BE_WORD(tt_hhea
->descender
);
1211 linegap
= GET_BE_WORD(tt_hhea
->ascender
) + abs(descender
) + GET_BE_WORD(tt_hhea
->linegap
) -
1212 metrics
->ascent
- metrics
->descent
;
1213 metrics
->lineGap
= linegap
> 0 ? linegap
: 0;
1216 metrics
->strikethroughPosition
= GET_BE_WORD(tt_os2
->yStrikeoutPosition
);
1217 metrics
->strikethroughThickness
= GET_BE_WORD(tt_os2
->yStrikeoutSize
);
1218 metrics
->subscriptPositionX
= GET_BE_WORD(tt_os2
->ySubscriptXOffset
);
1219 /* Y offset is stored as positive offset below baseline */
1220 metrics
->subscriptPositionY
= -GET_BE_WORD(tt_os2
->ySubscriptYOffset
);
1221 metrics
->subscriptSizeX
= GET_BE_WORD(tt_os2
->ySubscriptXSize
);
1222 metrics
->subscriptSizeY
= GET_BE_WORD(tt_os2
->ySubscriptYSize
);
1223 metrics
->superscriptPositionX
= GET_BE_WORD(tt_os2
->ySuperscriptXOffset
);
1224 metrics
->superscriptPositionY
= GET_BE_WORD(tt_os2
->ySuperscriptYOffset
);
1225 metrics
->superscriptSizeX
= GET_BE_WORD(tt_os2
->ySuperscriptXSize
);
1226 metrics
->superscriptSizeY
= GET_BE_WORD(tt_os2
->ySuperscriptYSize
);
1228 /* version 2 fields */
1230 metrics
->capHeight
= GET_BE_WORD(tt_os2
->sCapHeight
);
1231 metrics
->xHeight
= GET_BE_WORD(tt_os2
->sxHeight
);
1234 if (GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_USE_TYPO_METRICS
) {
1235 SHORT descent
= GET_BE_WORD(tt_os2
->sTypoDescender
);
1236 metrics
->ascent
= GET_BE_WORD(tt_os2
->sTypoAscender
);
1237 metrics
->descent
= descent
< 0 ? -descent
: 0;
1238 metrics
->lineGap
= GET_BE_WORD(tt_os2
->sTypoLineGap
);
1239 metrics
->hasTypographicMetrics
= TRUE
;
1244 metrics
->underlinePosition
= GET_BE_WORD(tt_post
->underlinePosition
);
1245 metrics
->underlineThickness
= GET_BE_WORD(tt_post
->underlineThickness
);
1248 if (metrics
->underlineThickness
== 0)
1249 metrics
->underlineThickness
= metrics
->designUnitsPerEm
/ 14;
1250 if (metrics
->strikethroughThickness
== 0)
1251 metrics
->strikethroughThickness
= metrics
->underlineThickness
;
1253 /* estimate missing metrics */
1254 if (metrics
->xHeight
== 0)
1255 metrics
->xHeight
= metrics
->designUnitsPerEm
/ 2;
1256 if (metrics
->capHeight
== 0)
1257 metrics
->capHeight
= metrics
->designUnitsPerEm
* 7 / 10;
1260 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1262 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, head_context
);
1264 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, post_context
);
1266 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, hhea_context
);
1269 void opentype_get_font_properties(struct file_stream_desc
*stream_desc
, struct dwrite_font_props
*props
)
1271 void *os2_context
, *head_context
;
1272 const TT_OS2_V2
*tt_os2
;
1273 const TT_HEAD
*tt_head
;
1275 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1276 opentype_get_font_table(stream_desc
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
1278 /* default stretch, weight and style to normal */
1279 props
->stretch
= DWRITE_FONT_STRETCH_NORMAL
;
1280 props
->weight
= DWRITE_FONT_WEIGHT_NORMAL
;
1281 props
->style
= DWRITE_FONT_STYLE_NORMAL
;
1282 memset(&props
->panose
, 0, sizeof(props
->panose
));
1283 memset(&props
->lf
, 0, sizeof(props
->lf
));
1285 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1287 USHORT version
= GET_BE_WORD(tt_os2
->version
);
1288 USHORT fsSelection
= GET_BE_WORD(tt_os2
->fsSelection
);
1289 USHORT usWeightClass
= GET_BE_WORD(tt_os2
->usWeightClass
);
1290 USHORT usWidthClass
= GET_BE_WORD(tt_os2
->usWidthClass
);
1292 if (usWidthClass
> DWRITE_FONT_STRETCH_UNDEFINED
&& usWidthClass
<= DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
1293 props
->stretch
= usWidthClass
;
1295 if (usWeightClass
>= 1 && usWeightClass
<= 9)
1296 usWeightClass
*= 100;
1298 if (usWeightClass
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
1299 props
->weight
= DWRITE_FONT_WEIGHT_ULTRA_BLACK
;
1300 else if (usWeightClass
> 0)
1301 props
->weight
= usWeightClass
;
1303 if (version
>= 4 && (fsSelection
& OS2_FSSELECTION_OBLIQUE
))
1304 props
->style
= DWRITE_FONT_STYLE_OBLIQUE
;
1305 else if (fsSelection
& OS2_FSSELECTION_ITALIC
)
1306 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
1308 memcpy(&props
->panose
, &tt_os2
->panose
, sizeof(props
->panose
));
1311 USHORT macStyle
= GET_BE_WORD(tt_head
->macStyle
);
1313 if (macStyle
& TT_HEAD_MACSTYLE_CONDENSED
)
1314 props
->stretch
= DWRITE_FONT_STRETCH_CONDENSED
;
1315 else if (macStyle
& TT_HEAD_MACSTYLE_EXTENDED
)
1316 props
->stretch
= DWRITE_FONT_STRETCH_EXPANDED
;
1318 if (macStyle
& TT_HEAD_MACSTYLE_BOLD
)
1319 props
->weight
= DWRITE_FONT_WEIGHT_BOLD
;
1321 if (macStyle
& TT_HEAD_MACSTYLE_ITALIC
)
1322 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
1325 props
->lf
.lfWeight
= props
->weight
;
1326 props
->lf
.lfItalic
= props
->style
== DWRITE_FONT_STYLE_ITALIC
;
1328 TRACE("stretch=%d, weight=%d, style %d\n", props
->stretch
, props
->weight
, props
->style
);
1331 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1333 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, head_context
);
1336 static UINT
get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform
, USHORT encoding
)
1341 case OPENTYPE_PLATFORM_UNICODE
:
1343 case OPENTYPE_PLATFORM_MAC
:
1346 case TT_NAME_MAC_ENCODING_ROMAN
:
1349 case TT_NAME_MAC_ENCODING_JAPANESE
:
1352 case TT_NAME_MAC_ENCODING_TRAD_CHINESE
:
1355 case TT_NAME_MAC_ENCODING_KOREAN
:
1358 case TT_NAME_MAC_ENCODING_ARABIC
:
1361 case TT_NAME_MAC_ENCODING_HEBREW
:
1364 case TT_NAME_MAC_ENCODING_GREEK
:
1367 case TT_NAME_MAC_ENCODING_RUSSIAN
:
1370 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE
:
1373 case TT_NAME_MAC_ENCODING_THAI
:
1377 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1381 case OPENTYPE_PLATFORM_WIN
:
1384 case TT_NAME_WINDOWS_ENCODING_SYMBOL
:
1385 case TT_NAME_WINDOWS_ENCODING_UCS2
:
1387 case TT_NAME_WINDOWS_ENCODING_SJIS
:
1390 case TT_NAME_WINDOWS_ENCODING_PRC
:
1393 case TT_NAME_WINDOWS_ENCODING_BIG5
:
1396 case TT_NAME_WINDOWS_ENCODING_WANSUNG
:
1399 case TT_NAME_WINDOWS_ENCODING_JOHAB
:
1403 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1408 FIXME("unknown platform %d\n", platform
);
1414 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform
, USHORT lang_id
, WCHAR
*locale
, USHORT locale_len
)
1416 static const WCHAR enusW
[] = {'e','n','-','U','S',0};
1419 case OPENTYPE_PLATFORM_MAC
:
1421 const char *locale_name
= NULL
;
1423 if (lang_id
> TT_NAME_MAC_LANGID_AZER_ROMAN
)
1424 WARN("invalid mac lang id %d\n", lang_id
);
1425 else if (!name_mac_langid_to_locale
[lang_id
][0])
1426 FIXME("failed to map mac lang id %d to locale name\n", lang_id
);
1428 locale_name
= name_mac_langid_to_locale
[lang_id
];
1431 MultiByteToWideChar(CP_ACP
, 0, name_mac_langid_to_locale
[lang_id
], -1, locale
, locale_len
);
1433 strcpyW(locale
, enusW
);
1436 case OPENTYPE_PLATFORM_WIN
:
1437 if (!LCIDToLocaleName(MAKELCID(lang_id
, SORT_DEFAULT
), locale
, locale_len
, 0)) {
1438 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id
, SORT_DEFAULT
));
1439 strcpyW(locale
, enusW
);
1442 case OPENTYPE_PLATFORM_UNICODE
:
1443 strcpyW(locale
, enusW
);
1446 FIXME("unknown platform %d\n", platform
);
1450 static BOOL
opentype_decode_namerecord(const TT_NAME_V0
*header
, BYTE
*storage_area
, USHORT recid
, IDWriteLocalizedStrings
*strings
)
1452 const TT_NameRecord
*record
= &header
->nameRecord
[recid
];
1453 USHORT lang_id
, length
, offset
, encoding
, platform
;
1456 platform
= GET_BE_WORD(record
->platformID
);
1457 lang_id
= GET_BE_WORD(record
->languageID
);
1458 length
= GET_BE_WORD(record
->length
);
1459 offset
= GET_BE_WORD(record
->offset
);
1460 encoding
= GET_BE_WORD(record
->encodingID
);
1462 if (lang_id
< 0x8000) {
1463 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
1467 codepage
= get_name_record_codepage(platform
, encoding
);
1468 get_name_record_locale(platform
, lang_id
, locale
, sizeof(locale
)/sizeof(WCHAR
));
1471 DWORD len
= MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, NULL
, 0);
1472 name_string
= heap_alloc(sizeof(WCHAR
) * (len
+1));
1473 MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, name_string
, len
);
1474 name_string
[len
] = 0;
1479 length
/= sizeof(WCHAR
);
1480 name_string
= heap_strdupnW((LPWSTR
)(storage_area
+ offset
), length
);
1481 for (i
= 0; i
< length
; i
++)
1482 name_string
[i
] = GET_BE_WORD(name_string
[i
]);
1485 TRACE("string %s for locale %s found\n", debugstr_w(name_string
), debugstr_w(locale
));
1486 add_localizedstring(strings
, locale
, name_string
);
1487 heap_free(name_string
);
1491 FIXME("handle NAME format 1\n");
1496 static HRESULT
opentype_get_font_strings_from_id(const void *table_data
, enum OPENTYPE_STRING_ID id
, IDWriteLocalizedStrings
**strings
)
1498 const TT_NAME_V0
*header
;
1499 BYTE
*storage_area
= 0;
1509 hr
= create_localizedstrings(strings
);
1510 if (FAILED(hr
)) return hr
;
1512 header
= table_data
;
1513 format
= GET_BE_WORD(header
->format
);
1520 FIXME("unsupported NAME format %d\n", format
);
1523 storage_area
= (LPBYTE
)table_data
+ GET_BE_WORD(header
->stringOffset
);
1524 count
= GET_BE_WORD(header
->count
);
1528 for (i
= 0; i
< count
; i
++) {
1529 const TT_NameRecord
*record
= &header
->nameRecord
[i
];
1532 if (GET_BE_WORD(record
->nameID
) != id
)
1535 /* Right now only accept unicode and windows encoded fonts */
1536 platform
= GET_BE_WORD(record
->platformID
);
1537 if (platform
!= OPENTYPE_PLATFORM_UNICODE
&&
1538 platform
!= OPENTYPE_PLATFORM_MAC
&&
1539 platform
!= OPENTYPE_PLATFORM_WIN
)
1541 FIXME("platform %i not supported\n", platform
);
1545 /* Skip such entries for now, fonts tend to duplicate those strings as
1546 WIN platform entries. If font does not have WIN or MAC entry for this id, we will
1547 use this Unicode platform entry while assuming en-US locale. */
1548 if (platform
== OPENTYPE_PLATFORM_UNICODE
) {
1553 if (!(exists
= opentype_decode_namerecord(header
, storage_area
, i
, *strings
)))
1558 if (candidate
!= -1)
1559 exists
= opentype_decode_namerecord(header
, storage_area
, candidate
, *strings
);
1561 IDWriteLocalizedStrings_Release(*strings
);
1566 return exists
? S_OK
: E_FAIL
;
1569 /* Provides a conversion from DWRITE to OpenType name ids, input id should be valid, it's not checked. */
1570 HRESULT
opentype_get_font_info_strings(const void *table_data
, DWRITE_INFORMATIONAL_STRING_ID id
, IDWriteLocalizedStrings
**strings
)
1572 return opentype_get_font_strings_from_id(table_data
, dwriteid_to_opentypeid
[id
], strings
);
1575 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
1576 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
1577 HRESULT
opentype_get_font_familyname(struct file_stream_desc
*stream_desc
, IDWriteLocalizedStrings
**names
)
1579 const TT_OS2_V2
*tt_os2
;
1580 void *os2_context
, *name_context
;
1581 const void *name_table
;
1584 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1585 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name_table
, &name_context
, NULL
, NULL
);
1589 /* if Preferred Family doesn't conform to WWS model try WWS name */
1590 if (tt_os2
&& !(GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_WWS
))
1591 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_WWS_FAMILY_NAME
, names
);
1596 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_PREFERRED_FAMILY_NAME
, names
);
1598 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_FAMILY_NAME
, names
);
1601 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1603 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name_context
);
1608 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
1609 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
1610 HRESULT
opentype_get_font_facename(struct file_stream_desc
*stream_desc
, WCHAR
*lfname
, IDWriteLocalizedStrings
**names
)
1612 IDWriteLocalizedStrings
*lfnames
;
1613 void *os2_context
, *name_context
;
1614 const TT_OS2_V2
*tt_os2
;
1615 const void *name_table
;
1618 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1619 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name_table
, &name_context
, NULL
, NULL
);
1623 /* if Preferred Family doesn't conform to WWS model try WWS name */
1624 if (tt_os2
&& !(GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_WWS
))
1625 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_WWS_SUBFAMILY_NAME
, names
);
1630 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
, names
);
1632 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_SUBFAMILY_NAME
, names
);
1634 /* User locale is preferred, with fallback to en-us. */
1636 if (SUCCEEDED(opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_FAMILY_NAME
, &lfnames
))) {
1637 static const WCHAR enusW
[] = {'e','n','-','u','s',0};
1638 WCHAR localeW
[LOCALE_NAME_MAX_LENGTH
];
1643 if (GetSystemDefaultLocaleName(localeW
, sizeof(localeW
)/sizeof(WCHAR
)))
1644 IDWriteLocalizedStrings_FindLocaleName(lfnames
, localeW
, &index
, &exists
);
1647 IDWriteLocalizedStrings_FindLocaleName(lfnames
, enusW
, &index
, &exists
);
1650 IDWriteLocalizedStrings_GetString(lfnames
, index
, lfname
, LF_FACESIZE
);
1652 IDWriteLocalizedStrings_Release(lfnames
);
1656 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1658 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name_context
);
1663 static inline const OT_Script
*opentype_get_script(const OT_ScriptList
*scriptlist
, UINT32 scripttag
)
1667 for (j
= 0; j
< GET_BE_WORD(scriptlist
->ScriptCount
); j
++) {
1668 const char *tag
= scriptlist
->ScriptRecord
[j
].ScriptTag
;
1669 if (scripttag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1670 return (OT_Script
*)((BYTE
*)scriptlist
+ GET_BE_WORD(scriptlist
->ScriptRecord
[j
].Script
));
1676 static inline const OT_LangSys
*opentype_get_langsys(const OT_Script
*script
, UINT32 languagetag
)
1680 for (j
= 0; j
< GET_BE_WORD(script
->LangSysCount
); j
++) {
1681 const char *tag
= script
->LangSysRecord
[j
].LangSysTag
;
1682 if (languagetag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1683 return (OT_LangSys
*)((BYTE
*)script
+ GET_BE_WORD(script
->LangSysRecord
[j
].LangSys
));
1689 static void opentype_add_font_features(const GPOS_GSUB_Header
*header
, const OT_LangSys
*langsys
,
1690 UINT32 max_tagcount
, UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1692 const OT_FeatureList
*features
= (const OT_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1695 for (j
= 0; j
< GET_BE_WORD(langsys
->FeatureCount
); j
++) {
1696 const OT_FeatureRecord
*feature
= &features
->FeatureRecord
[langsys
->FeatureIndex
[j
]];
1697 const char *tag
= feature
->FeatureTag
;
1699 if (*count
< max_tagcount
)
1700 tags
[*count
] = DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]);
1706 HRESULT
opentype_get_typographic_features(IDWriteFontFace
*fontface
, UINT32 scripttag
, UINT32 languagetag
, UINT32 max_tagcount
,
1707 UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1709 UINT32 tables
[2] = { MS_GSUB_TAG
, MS_GPOS_TAG
};
1714 for (i
= 0; i
< sizeof(tables
)/sizeof(tables
[0]); i
++) {
1715 const OT_ScriptList
*scriptlist
;
1716 const GPOS_GSUB_Header
*header
;
1717 const OT_Script
*script
;
1724 hr
= IDWriteFontFace_TryGetFontTable(fontface
, tables
[i
], &ptr
, &size
, &context
, &exists
);
1731 header
= (const GPOS_GSUB_Header
*)ptr
;
1732 scriptlist
= (const OT_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
1734 script
= opentype_get_script(scriptlist
, scripttag
);
1736 const OT_LangSys
*langsys
= opentype_get_langsys(script
, languagetag
);
1738 opentype_add_font_features(header
, langsys
, max_tagcount
, count
, tags
);
1741 IDWriteFontFace_ReleaseFontTable(fontface
, context
);
1744 return *count
> max_tagcount
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
1747 static const struct VDMX_group
*find_vdmx_group(const struct VDMX_Header
*hdr
)
1749 WORD num_ratios
, i
, group_offset
= 0;
1750 struct VDMX_Ratio
*ratios
= (struct VDMX_Ratio
*)(hdr
+ 1);
1751 BYTE dev_x_ratio
= 1, dev_y_ratio
= 1;
1753 num_ratios
= GET_BE_WORD(hdr
->numRatios
);
1755 for (i
= 0; i
< num_ratios
; i
++) {
1757 if (!ratios
[i
].bCharSet
) continue;
1759 if ((ratios
[i
].xRatio
== 0 && ratios
[i
].yStartRatio
== 0 &&
1760 ratios
[i
].yEndRatio
== 0) ||
1761 (ratios
[i
].xRatio
== dev_x_ratio
&& ratios
[i
].yStartRatio
<= dev_y_ratio
&&
1762 ratios
[i
].yEndRatio
>= dev_y_ratio
))
1764 group_offset
= GET_BE_WORD(*((WORD
*)(ratios
+ num_ratios
) + i
));
1769 return (const struct VDMX_group
*)((BYTE
*)hdr
+ group_offset
);
1773 BOOL
opentype_get_vdmx_size(const void *data
, INT emsize
, UINT16
*ascent
, UINT16
*descent
)
1775 const struct VDMX_Header
*hdr
= (const struct VDMX_Header
*)data
;
1776 const struct VDMX_group
*group
;
1777 const struct VDMX_vTable
*tables
;
1783 group
= find_vdmx_group(hdr
);
1787 recs
= GET_BE_WORD(group
->recs
);
1788 if (emsize
< group
->startsz
|| emsize
>= group
->endsz
) return FALSE
;
1790 tables
= (const struct VDMX_vTable
*)(group
+ 1);
1791 for (i
= 0; i
< recs
; i
++) {
1792 WORD ppem
= GET_BE_WORD(tables
[i
].yPelHeight
);
1793 if (ppem
> emsize
) {
1794 FIXME("interpolate %d\n", emsize
);
1798 if (ppem
== emsize
) {
1799 *ascent
= (SHORT
)GET_BE_WORD(tables
[i
].yMax
);
1800 *descent
= -(SHORT
)GET_BE_WORD(tables
[i
].yMin
);
1807 WORD
opentype_get_gasp_flags(const WORD
*ptr
, UINT32 size
, INT emsize
)
1809 WORD num_recs
, version
;
1815 version
= GET_BE_WORD( *ptr
++ );
1816 num_recs
= GET_BE_WORD( *ptr
++ );
1817 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
)) {
1818 ERR("unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
1822 while (num_recs
--) {
1823 flags
= GET_BE_WORD( *(ptr
+ 1) );
1824 if (emsize
<= GET_BE_WORD( *ptr
)) break;
1832 UINT32
opentype_get_cpal_palettecount(const void *cpal
)
1834 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1835 return header
? GET_BE_WORD(header
->numPalette
) : 0;
1838 UINT32
opentype_get_cpal_paletteentrycount(const void *cpal
)
1840 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1841 return header
? GET_BE_WORD(header
->numPaletteEntries
) : 0;
1844 HRESULT
opentype_get_cpal_entries(const void *cpal
, UINT32 palette
, UINT32 first_entry_index
, UINT32 entry_count
,
1845 DWRITE_COLOR_F
*entries
)
1847 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1848 const struct CPAL_ColorRecord
*records
;
1849 UINT32 palettecount
, entrycount
, i
;
1851 if (!header
) return DWRITE_E_NOCOLOR
;
1853 palettecount
= GET_BE_WORD(header
->numPalette
);
1854 if (palette
>= palettecount
)
1855 return DWRITE_E_NOCOLOR
;
1857 entrycount
= GET_BE_WORD(header
->numPaletteEntries
);
1858 if (first_entry_index
+ entry_count
> entrycount
)
1859 return E_INVALIDARG
;
1861 records
= (const struct CPAL_ColorRecord
*)((BYTE
*)cpal
+ GET_BE_DWORD(header
->offsetFirstColorRecord
));
1862 first_entry_index
+= GET_BE_WORD(header
->colorRecordIndices
[palette
]);
1864 for (i
= 0; i
< entry_count
; i
++) {
1865 entries
[i
].r
= records
[first_entry_index
+ i
].red
/ 255.0f
;
1866 entries
[i
].g
= records
[first_entry_index
+ i
].green
/ 255.0f
;
1867 entries
[i
].b
= records
[first_entry_index
+ i
].blue
/ 255.0f
;
1868 entries
[i
].a
= records
[first_entry_index
+ i
].alpha
/ 255.0f
;
1874 static int colr_compare_gid(const void *g
, const void *r
)
1876 const struct COLR_BaseGlyphRecord
*record
= r
;
1877 UINT16 glyph
= *(UINT16
*)g
, GID
= GET_BE_WORD(record
->GID
);
1882 else if (glyph
< GID
)
1888 HRESULT
opentype_get_colr_glyph(const void *colr
, UINT16 glyph
, struct dwrite_colorglyph
*ret
)
1890 const struct COLR_BaseGlyphRecord
*record
;
1891 const struct COLR_Header
*header
= colr
;
1892 const struct COLR_LayerRecord
*layer
;
1893 DWORD layerrecordoffset
= GET_BE_DWORD(header
->offsetLayerRecord
);
1894 DWORD baserecordoffset
= GET_BE_DWORD(header
->offsetBaseGlyphRecord
);
1895 WORD numbaserecords
= GET_BE_WORD(header
->numBaseGlyphRecords
);
1897 record
= bsearch(&glyph
, (BYTE
*)colr
+ baserecordoffset
, numbaserecords
, sizeof(struct COLR_BaseGlyphRecord
),
1901 ret
->first_layer
= 0;
1902 ret
->num_layers
= 0;
1904 ret
->palette_index
= 0xffff;
1909 ret
->first_layer
= GET_BE_WORD(record
->firstLayerIndex
);
1910 ret
->num_layers
= GET_BE_WORD(record
->numLayers
);
1912 layer
= (struct COLR_LayerRecord
*)((BYTE
*)colr
+ layerrecordoffset
) + ret
->first_layer
+ ret
->layer
;
1913 ret
->glyph
= GET_BE_WORD(layer
->GID
);
1914 ret
->palette_index
= GET_BE_WORD(layer
->paletteIndex
);
1919 void opentype_colr_next_glyph(const void *colr
, struct dwrite_colorglyph
*glyph
)
1921 const struct COLR_Header
*header
= colr
;
1922 const struct COLR_LayerRecord
*layer
;
1923 DWORD layerrecordoffset
= GET_BE_DWORD(header
->offsetLayerRecord
);
1925 /* iterated all the way through */
1926 if (glyph
->layer
== glyph
->num_layers
)
1930 layer
= (struct COLR_LayerRecord
*)((BYTE
*)colr
+ layerrecordoffset
) + glyph
->first_layer
+ glyph
->layer
;
1931 glyph
->glyph
= GET_BE_WORD(layer
->GID
);
1932 glyph
->palette_index
= GET_BE_WORD(layer
->paletteIndex
);
1935 HRESULT
opentype_get_font_signature(struct file_stream_desc
*stream_desc
, FONTSIGNATURE
*fontsig
)
1937 const TT_OS2_V2
*tt_os2
;
1941 hr
= opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1943 fontsig
->fsUsb
[0] = GET_BE_DWORD(tt_os2
->ulUnicodeRange1
);
1944 fontsig
->fsUsb
[1] = GET_BE_DWORD(tt_os2
->ulUnicodeRange2
);
1945 fontsig
->fsUsb
[2] = GET_BE_DWORD(tt_os2
->ulUnicodeRange3
);
1946 fontsig
->fsUsb
[3] = GET_BE_DWORD(tt_os2
->ulUnicodeRange4
);
1948 if (GET_BE_WORD(tt_os2
->version
) == 0) {
1949 fontsig
->fsCsb
[0] = 0;
1950 fontsig
->fsCsb
[1] = 0;
1953 fontsig
->fsCsb
[0] = GET_BE_DWORD(tt_os2
->ulCodePageRange1
);
1954 fontsig
->fsCsb
[1] = GET_BE_DWORD(tt_os2
->ulCodePageRange2
);
1957 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1963 BOOL
opentype_has_vertical_variants(IDWriteFontFace4
*fontface
)
1965 const OT_FeatureList
*featurelist
;
1966 const OT_LookupList
*lookup_list
;
1967 BOOL exists
= FALSE
, ret
= FALSE
;
1968 const GPOS_GSUB_Header
*header
;
1975 hr
= IDWriteFontFace4_TryGetFontTable(fontface
, MS_GSUB_TAG
, &data
, &size
, &context
, &exists
);
1976 if (FAILED(hr
) || !exists
)
1980 featurelist
= (OT_FeatureList
*)((BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1981 lookup_list
= (const OT_LookupList
*)((BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
1983 for (i
= 0; i
< GET_BE_WORD(featurelist
->FeatureCount
); i
++) {
1984 if (*(UINT32
*)featurelist
->FeatureRecord
[i
].FeatureTag
== DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING
) {
1985 const OT_Feature
*feature
= (const OT_Feature
*)((BYTE
*)featurelist
+ GET_BE_WORD(featurelist
->FeatureRecord
[i
].Feature
));
1986 UINT16 lookup_count
= GET_BE_WORD(feature
->LookupCount
), i
, index
, count
, type
;
1987 const GSUB_SingleSubstFormat2
*subst2
;
1988 const OT_LookupTable
*lookup_table
;
1991 if (lookup_count
== 0)
1994 for (i
= 0; i
< lookup_count
; i
++) {
1995 /* check if lookup is empty */
1996 index
= GET_BE_WORD(feature
->LookupListIndex
[i
]);
1997 lookup_table
= (const OT_LookupTable
*)((BYTE
*)lookup_list
+ GET_BE_WORD(lookup_list
->Lookup
[index
]));
1999 type
= GET_BE_WORD(lookup_table
->LookupType
);
2000 if (type
!= OPENTYPE_GPOS_SINGLE_SUBST
&& type
!= OPENTYPE_GPOS_EXTENSION_SUBST
)
2003 count
= GET_BE_WORD(lookup_table
->SubTableCount
);
2007 offset
= GET_BE_WORD(lookup_table
->SubTable
[0]);
2008 if (type
== OPENTYPE_GPOS_EXTENSION_SUBST
) {
2009 const GSUB_ExtensionPosFormat1
*ext
= (const GSUB_ExtensionPosFormat1
*)((const BYTE
*)lookup_table
+ offset
);
2010 if (GET_BE_WORD(ext
->SubstFormat
) == 1)
2011 offset
+= GET_BE_DWORD(ext
->ExtensionOffset
);
2013 FIXME("Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext
->SubstFormat
));
2016 subst2
= (const GSUB_SingleSubstFormat2
*)((BYTE
*)lookup_table
+ offset
);
2017 index
= GET_BE_WORD(subst2
->SubstFormat
);
2019 FIXME("Validate Single Substitution Format 1\n");
2020 else if (index
== 2) {
2021 /* SimSun-ExtB has 0 glyph count for this substitution */
2022 if (GET_BE_WORD(subst2
->GlyphCount
) > 0) {
2028 WARN("Unknown Single Substitution Format, %u\n", index
);
2033 IDWriteFontFace4_ReleaseFontTable(fontface
, context
);