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"
129 USHORT lowestRecPPEM
;
130 SHORT direction_hint
;
132 SHORT glyphdata_format
;
135 enum TT_HEAD_MACSTYLE
137 TT_HEAD_MACSTYLE_BOLD
= 1 << 0,
138 TT_HEAD_MACSTYLE_ITALIC
= 1 << 1,
139 TT_HEAD_MACSTYLE_UNDERLINE
= 1 << 2,
140 TT_HEAD_MACSTYLE_OUTLINE
= 1 << 3,
141 TT_HEAD_MACSTYLE_SHADOW
= 1 << 4,
142 TT_HEAD_MACSTYLE_CONDENSED
= 1 << 5,
143 TT_HEAD_MACSTYLE_EXTENDED
= 1 << 6,
150 SHORT underlinePosition
;
151 SHORT underlineThickness
;
163 USHORT usWeightClass
;
166 SHORT ySubscriptXSize
;
167 SHORT ySubscriptYSize
;
168 SHORT ySubscriptXOffset
;
169 SHORT ySubscriptYOffset
;
170 SHORT ySuperscriptXSize
;
171 SHORT ySuperscriptYSize
;
172 SHORT ySuperscriptXOffset
;
173 SHORT ySuperscriptYOffset
;
174 SHORT yStrikeoutSize
;
175 SHORT yStrikeoutPosition
;
178 ULONG ulUnicodeRange1
;
179 ULONG ulUnicodeRange2
;
180 ULONG ulUnicodeRange3
;
181 ULONG ulUnicodeRange4
;
184 USHORT usFirstCharIndex
;
185 USHORT usLastCharIndex
;
186 /* According to the Apple spec, original version didn't have the below fields,
187 * version numbers were taken from the OpenType spec.
189 /* version 0 (TrueType 1.5) */
190 USHORT sTypoAscender
;
191 USHORT sTypoDescender
;
195 /* version 1 (TrueType 1.66) */
196 ULONG ulCodePageRange1
;
197 ULONG ulCodePageRange2
;
198 /* version 2 (OpenType 1.2) */
201 USHORT usDefaultChar
;
211 USHORT advanceWidthMax
;
212 SHORT minLeftSideBearing
;
213 SHORT minRightSideBearing
;
215 SHORT caretSlopeRise
;
219 SHORT metricDataFormat
;
220 USHORT numberOfHMetrics
;
225 enum OS2_FSSELECTION
{
226 OS2_FSSELECTION_ITALIC
= 1 << 0,
227 OS2_FSSELECTION_UNDERSCORE
= 1 << 1,
228 OS2_FSSELECTION_NEGATIVE
= 1 << 2,
229 OS2_FSSELECTION_OUTLINED
= 1 << 3,
230 OS2_FSSELECTION_STRIKEOUT
= 1 << 4,
231 OS2_FSSELECTION_BOLD
= 1 << 5,
232 OS2_FSSELECTION_REGULAR
= 1 << 6,
233 OS2_FSSELECTION_USE_TYPO_METRICS
= 1 << 7,
234 OS2_FSSELECTION_WWS
= 1 << 8,
235 OS2_FSSELECTION_OBLIQUE
= 1 << 9
251 TT_NameRecord nameRecord
[1];
290 OT_FeatureRecord FeatureRecord
[1];
294 WORD LookupOrder
; /* Reserved */
295 WORD ReqFeatureIndex
;
297 WORD FeatureIndex
[1];
308 OT_LangSysRecord LangSysRecord
[1];
318 OT_ScriptRecord ScriptRecord
[1];
328 enum OPENTYPE_PLATFORM_ID
330 OPENTYPE_PLATFORM_UNICODE
= 0,
331 OPENTYPE_PLATFORM_MAC
,
332 OPENTYPE_PLATFORM_ISO
,
333 OPENTYPE_PLATFORM_WIN
,
334 OPENTYPE_PLATFORM_CUSTOM
340 WORD LookupListIndex
[1];
359 } GSUB_SingleSubstFormat1
;
366 } GSUB_SingleSubstFormat2
;
370 WORD ExtensionLookupType
;
371 DWORD ExtensionOffset
;
372 } GSUB_ExtensionPosFormat1
;
374 enum OPENTYPE_GPOS_LOOKUPS
376 OPENTYPE_GPOS_SINGLE_SUBST
= 1,
377 OPENTYPE_GPOS_EXTENSION_SUBST
= 7
380 enum TT_NAME_WINDOWS_ENCODING_ID
382 TT_NAME_WINDOWS_ENCODING_SYMBOL
= 0,
383 TT_NAME_WINDOWS_ENCODING_UCS2
,
384 TT_NAME_WINDOWS_ENCODING_SJIS
,
385 TT_NAME_WINDOWS_ENCODING_PRC
,
386 TT_NAME_WINDOWS_ENCODING_BIG5
,
387 TT_NAME_WINDOWS_ENCODING_WANSUNG
,
388 TT_NAME_WINDOWS_ENCODING_JOHAB
,
389 TT_NAME_WINDOWS_ENCODING_RESERVED1
,
390 TT_NAME_WINDOWS_ENCODING_RESERVED2
,
391 TT_NAME_WINDOWS_ENCODING_RESERVED3
,
392 TT_NAME_WINDOWS_ENCODING_UCS4
395 enum TT_NAME_MAC_ENCODING_ID
397 TT_NAME_MAC_ENCODING_ROMAN
= 0,
398 TT_NAME_MAC_ENCODING_JAPANESE
,
399 TT_NAME_MAC_ENCODING_TRAD_CHINESE
,
400 TT_NAME_MAC_ENCODING_KOREAN
,
401 TT_NAME_MAC_ENCODING_ARABIC
,
402 TT_NAME_MAC_ENCODING_HEBREW
,
403 TT_NAME_MAC_ENCODING_GREEK
,
404 TT_NAME_MAC_ENCODING_RUSSIAN
,
405 TT_NAME_MAC_ENCODING_RSYMBOL
,
406 TT_NAME_MAC_ENCODING_DEVANAGARI
,
407 TT_NAME_MAC_ENCODING_GURMUKHI
,
408 TT_NAME_MAC_ENCODING_GUJARATI
,
409 TT_NAME_MAC_ENCODING_ORIYA
,
410 TT_NAME_MAC_ENCODING_BENGALI
,
411 TT_NAME_MAC_ENCODING_TAMIL
,
412 TT_NAME_MAC_ENCODING_TELUGU
,
413 TT_NAME_MAC_ENCODING_KANNADA
,
414 TT_NAME_MAC_ENCODING_MALAYALAM
,
415 TT_NAME_MAC_ENCODING_SINHALESE
,
416 TT_NAME_MAC_ENCODING_BURMESE
,
417 TT_NAME_MAC_ENCODING_KHMER
,
418 TT_NAME_MAC_ENCODING_THAI
,
419 TT_NAME_MAC_ENCODING_LAOTIAN
,
420 TT_NAME_MAC_ENCODING_GEORGIAN
,
421 TT_NAME_MAC_ENCODING_ARMENIAN
,
422 TT_NAME_MAC_ENCODING_SIMPL_CHINESE
,
423 TT_NAME_MAC_ENCODING_TIBETAN
,
424 TT_NAME_MAC_ENCODING_MONGOLIAN
,
425 TT_NAME_MAC_ENCODING_GEEZ
,
426 TT_NAME_MAC_ENCODING_SLAVIC
,
427 TT_NAME_MAC_ENCODING_VIETNAMESE
,
428 TT_NAME_MAC_ENCODING_SINDHI
,
429 TT_NAME_MAC_ENCODING_UNINTERPRETED
432 enum TT_NAME_MAC_LANGUAGE_ID
434 TT_NAME_MAC_LANGID_ENGLISH
= 0,
435 TT_NAME_MAC_LANGID_FRENCH
,
436 TT_NAME_MAC_LANGID_GERMAN
,
437 TT_NAME_MAC_LANGID_ITALIAN
,
438 TT_NAME_MAC_LANGID_DUTCH
,
439 TT_NAME_MAC_LANGID_SWEDISH
,
440 TT_NAME_MAC_LANGID_SPANISH
,
441 TT_NAME_MAC_LANGID_DANISH
,
442 TT_NAME_MAC_LANGID_PORTUGUESE
,
443 TT_NAME_MAC_LANGID_NORWEGIAN
,
444 TT_NAME_MAC_LANGID_HEBREW
,
445 TT_NAME_MAC_LANGID_JAPANESE
,
446 TT_NAME_MAC_LANGID_ARABIC
,
447 TT_NAME_MAC_LANGID_FINNISH
,
448 TT_NAME_MAC_LANGID_GREEK
,
449 TT_NAME_MAC_LANGID_ICELANDIC
,
450 TT_NAME_MAC_LANGID_MALTESE
,
451 TT_NAME_MAC_LANGID_TURKISH
,
452 TT_NAME_MAC_LANGID_CROATIAN
,
453 TT_NAME_MAC_LANGID_TRAD_CHINESE
,
454 TT_NAME_MAC_LANGID_URDU
,
455 TT_NAME_MAC_LANGID_HINDI
,
456 TT_NAME_MAC_LANGID_THAI
,
457 TT_NAME_MAC_LANGID_KOREAN
,
458 TT_NAME_MAC_LANGID_LITHUANIAN
,
459 TT_NAME_MAC_LANGID_POLISH
,
460 TT_NAME_MAC_LANGID_HUNGARIAN
,
461 TT_NAME_MAC_LANGID_ESTONIAN
,
462 TT_NAME_MAC_LANGID_LATVIAN
,
463 TT_NAME_MAC_LANGID_SAMI
,
464 TT_NAME_MAC_LANGID_FAROESE
,
465 TT_NAME_MAC_LANGID_FARSI
,
466 TT_NAME_MAC_LANGID_RUSSIAN
,
467 TT_NAME_MAC_LANGID_SIMPL_CHINESE
,
468 TT_NAME_MAC_LANGID_FLEMISH
,
469 TT_NAME_MAC_LANGID_GAELIC
,
470 TT_NAME_MAC_LANGID_ALBANIAN
,
471 TT_NAME_MAC_LANGID_ROMANIAN
,
472 TT_NAME_MAC_LANGID_CZECH
,
473 TT_NAME_MAC_LANGID_SLOVAK
,
474 TT_NAME_MAC_LANGID_SLOVENIAN
,
475 TT_NAME_MAC_LANGID_YIDDISH
,
476 TT_NAME_MAC_LANGID_SERBIAN
,
477 TT_NAME_MAC_LANGID_MACEDONIAN
,
478 TT_NAME_MAC_LANGID_BULGARIAN
,
479 TT_NAME_MAC_LANGID_UKRAINIAN
,
480 TT_NAME_MAC_LANGID_BYELORUSSIAN
,
481 TT_NAME_MAC_LANGID_UZBEK
,
482 TT_NAME_MAC_LANGID_KAZAKH
,
483 TT_NAME_MAC_LANGID_AZERB_CYR
,
484 TT_NAME_MAC_LANGID_AZERB_ARABIC
,
485 TT_NAME_MAC_LANGID_ARMENIAN
,
486 TT_NAME_MAC_LANGID_GEORGIAN
,
487 TT_NAME_MAC_LANGID_MOLDAVIAN
,
488 TT_NAME_MAC_LANGID_KIRGHIZ
,
489 TT_NAME_MAC_LANGID_TAJIKI
,
490 TT_NAME_MAC_LANGID_TURKMEN
,
491 TT_NAME_MAC_LANGID_MONGOLIAN
,
492 TT_NAME_MAC_LANGID_MONGOLIAN_CYR
,
493 TT_NAME_MAC_LANGID_PASHTO
,
494 TT_NAME_MAC_LANGID_KURDISH
,
495 TT_NAME_MAC_LANGID_KASHMIRI
,
496 TT_NAME_MAC_LANGID_SINDHI
,
497 TT_NAME_MAC_LANGID_TIBETAN
,
498 TT_NAME_MAC_LANGID_NEPALI
,
499 TT_NAME_MAC_LANGID_SANSKRIT
,
500 TT_NAME_MAC_LANGID_MARATHI
,
501 TT_NAME_MAC_LANGID_BENGALI
,
502 TT_NAME_MAC_LANGID_ASSAMESE
,
503 TT_NAME_MAC_LANGID_GUJARATI
,
504 TT_NAME_MAC_LANGID_PUNJABI
,
505 TT_NAME_MAC_LANGID_ORIYA
,
506 TT_NAME_MAC_LANGID_MALAYALAM
,
507 TT_NAME_MAC_LANGID_KANNADA
,
508 TT_NAME_MAC_LANGID_TAMIL
,
509 TT_NAME_MAC_LANGID_TELUGU
,
510 TT_NAME_MAC_LANGID_SINHALESE
,
511 TT_NAME_MAC_LANGID_BURMESE
,
512 TT_NAME_MAC_LANGID_KHMER
,
513 TT_NAME_MAC_LANGID_LAO
,
514 TT_NAME_MAC_LANGID_VIETNAMESE
,
515 TT_NAME_MAC_LANGID_INDONESIAN
,
516 TT_NAME_MAC_LANGID_TAGALOG
,
517 TT_NAME_MAC_LANGID_MALAY_ROMAN
,
518 TT_NAME_MAC_LANGID_MALAY_ARABIC
,
519 TT_NAME_MAC_LANGID_AMHARIC
,
520 TT_NAME_MAC_LANGID_TIGRINYA
,
521 TT_NAME_MAC_LANGID_GALLA
,
522 TT_NAME_MAC_LANGID_SOMALI
,
523 TT_NAME_MAC_LANGID_SWAHILI
,
524 TT_NAME_MAC_LANGID_KINYARWANDA
,
525 TT_NAME_MAC_LANGID_RUNDI
,
526 TT_NAME_MAC_LANGID_NYANJA
,
527 TT_NAME_MAC_LANGID_MALAGASY
,
528 TT_NAME_MAC_LANGID_ESPERANTO
,
529 TT_NAME_MAC_LANGID_WELSH
= 128,
530 TT_NAME_MAC_LANGID_BASQUE
,
531 TT_NAME_MAC_LANGID_CATALAN
,
532 TT_NAME_MAC_LANGID_LATIN
,
533 TT_NAME_MAC_LANGID_QUECHUA
,
534 TT_NAME_MAC_LANGID_GUARANI
,
535 TT_NAME_MAC_LANGID_AYMARA
,
536 TT_NAME_MAC_LANGID_TATAR
,
537 TT_NAME_MAC_LANGID_UIGHUR
,
538 TT_NAME_MAC_LANGID_DZONGKHA
,
539 TT_NAME_MAC_LANGID_JAVANESE
,
540 TT_NAME_MAC_LANGID_SUNDANESE
,
541 TT_NAME_MAC_LANGID_GALICIAN
,
542 TT_NAME_MAC_LANGID_AFRIKAANS
,
543 TT_NAME_MAC_LANGID_BRETON
,
544 TT_NAME_MAC_LANGID_INUKTITUT
,
545 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC
,
546 TT_NAME_MAC_LANGID_MANX_GAELIC
,
547 TT_NAME_MAC_LANGID_IRISH_GAELIC
,
548 TT_NAME_MAC_LANGID_TONGAN
,
549 TT_NAME_MAC_LANGID_GREEK_POLYTONIC
,
550 TT_NAME_MAC_LANGID_GREENLANDIC
,
551 TT_NAME_MAC_LANGID_AZER_ROMAN
554 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
555 static const char name_mac_langid_to_locale
[][10] = {
709 enum OPENTYPE_STRING_ID
711 OPENTYPE_STRING_COPYRIGHT_NOTICE
= 0,
712 OPENTYPE_STRING_FAMILY_NAME
,
713 OPENTYPE_STRING_SUBFAMILY_NAME
,
714 OPENTYPE_STRING_UNIQUE_IDENTIFIER
,
715 OPENTYPE_STRING_FULL_FONTNAME
,
716 OPENTYPE_STRING_VERSION_STRING
,
717 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
718 OPENTYPE_STRING_TRADEMARK
,
719 OPENTYPE_STRING_MANUFACTURER
,
720 OPENTYPE_STRING_DESIGNER
,
721 OPENTYPE_STRING_DESCRIPTION
,
722 OPENTYPE_STRING_VENDOR_URL
,
723 OPENTYPE_STRING_DESIGNER_URL
,
724 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
725 OPENTYPE_STRING_LICENSE_INFO_URL
,
726 OPENTYPE_STRING_RESERVED_ID15
,
727 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
728 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
729 OPENTYPE_STRING_COMPATIBLE_FULLNAME
,
730 OPENTYPE_STRING_SAMPLE_TEXT
,
731 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
732 OPENTYPE_STRING_WWS_FAMILY_NAME
,
733 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
736 static const UINT16 dwriteid_to_opentypeid
[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME
+1] =
738 (UINT16
)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
739 OPENTYPE_STRING_COPYRIGHT_NOTICE
,
740 OPENTYPE_STRING_VERSION_STRING
,
741 OPENTYPE_STRING_TRADEMARK
,
742 OPENTYPE_STRING_MANUFACTURER
,
743 OPENTYPE_STRING_DESIGNER
,
744 OPENTYPE_STRING_DESIGNER_URL
,
745 OPENTYPE_STRING_DESCRIPTION
,
746 OPENTYPE_STRING_VENDOR_URL
,
747 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
748 OPENTYPE_STRING_LICENSE_INFO_URL
,
749 OPENTYPE_STRING_FAMILY_NAME
,
750 OPENTYPE_STRING_SUBFAMILY_NAME
,
751 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
752 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
753 OPENTYPE_STRING_SAMPLE_TEXT
,
754 OPENTYPE_STRING_FULL_FONTNAME
,
755 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
756 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
763 USHORT numPaletteEntries
;
765 USHORT numColorRecords
;
766 ULONG offsetFirstColorRecord
;
767 USHORT colorRecordIndices
[1];
770 /* for version == 1, this comes after full CPAL_Header_0 */
771 struct CPAL_SubHeader_1
773 ULONG offsetPaletteTypeArray
;
774 ULONG offsetPaletteLabelArray
;
775 ULONG offsetPaletteEntryLabelArray
;
778 struct CPAL_ColorRecord
790 USHORT numBaseGlyphRecords
;
791 ULONG offsetBaseGlyphRecord
;
792 ULONG offsetLayerRecord
;
793 USHORT numLayerRecords
;
796 struct COLR_BaseGlyphRecord
799 USHORT firstLayerIndex
;
803 struct COLR_LayerRecord
809 BOOL
is_face_type_supported(DWRITE_FONT_FACE_TYPE type
)
811 return (type
== DWRITE_FONT_FACE_TYPE_CFF
) ||
812 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE
) ||
813 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
) ||
814 (type
== DWRITE_FONT_FACE_TYPE_RAW_CFF
);
817 typedef HRESULT (*dwrite_fontfile_analyzer
)(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
818 DWRITE_FONT_FACE_TYPE
*face_type
);
820 static HRESULT
opentype_ttc_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
821 DWRITE_FONT_FACE_TYPE
*face_type
)
823 static const DWORD ttctag
= MS_TTCF_TAG
;
824 const TTC_Header_V1
*header
;
828 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(header
), &context
);
832 if (!memcmp(header
->TTCTag
, &ttctag
, sizeof(ttctag
))) {
833 *font_count
= GET_BE_DWORD(header
->numFonts
);
834 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION
;
835 *face_type
= DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
;
838 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
840 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
843 static HRESULT
opentype_ttf_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
844 DWRITE_FONT_FACE_TYPE
*face_type
)
850 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
854 if (GET_BE_DWORD(*header
) == 0x10000) {
856 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE
;
857 *face_type
= DWRITE_FONT_FACE_TYPE_TRUETYPE
;
860 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
862 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
865 static HRESULT
opentype_otf_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
866 DWRITE_FONT_FACE_TYPE
*face_type
)
872 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
876 if (GET_BE_DWORD(*header
) == MS_OTTO_TAG
) {
878 *file_type
= DWRITE_FONT_FILE_TYPE_CFF
;
879 *face_type
= DWRITE_FONT_FACE_TYPE_CFF
;
882 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
884 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
887 static HRESULT
opentype_type1_analyzer(IDWriteFontFileStream
*stream
, UINT32
*font_count
, DWRITE_FONT_FILE_TYPE
*file_type
,
888 DWRITE_FONT_FACE_TYPE
*face_type
)
890 #include "pshpack1.h"
891 /* Specified in Adobe TechNote #5178 */
900 struct type1_header
{
904 const struct type1_header
*header
;
908 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&header
, 0, sizeof(*header
), &context
);
912 /* tag is followed by plain text section */
913 if (header
->tag
== 0x8001 &&
914 (!memcmp(header
->data
, "%!PS-AdobeFont", 14) ||
915 !memcmp(header
->data
, "%!FontType", 10))) {
917 *file_type
= DWRITE_FONT_FILE_TYPE_TYPE1_PFB
;
918 *face_type
= DWRITE_FONT_FACE_TYPE_TYPE1
;
921 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
923 /* let's see if it's a .pfm metrics file */
924 if (*file_type
== DWRITE_FONT_FILE_TYPE_UNKNOWN
) {
925 const struct pfm_header
*pfm_header
;
930 hr
= IDWriteFontFileStream_GetFileSize(stream
, &filesize
);
934 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&pfm_header
, 0, sizeof(*pfm_header
), &context
);
938 offset
= pfm_header
->dfDevice
;
939 header_checked
= pfm_header
->dfVersion
== 0x100 && pfm_header
->dfSize
== filesize
;
940 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
942 /* as a last test check static string in PostScript information section */
943 if (header_checked
) {
944 static const char postscript
[] = "PostScript";
947 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&devtype_name
, offset
, sizeof(postscript
), &context
);
951 if (!memcmp(devtype_name
, postscript
, sizeof(postscript
))) {
953 *file_type
= DWRITE_FONT_FILE_TYPE_TYPE1_PFM
;
954 *face_type
= DWRITE_FONT_FACE_TYPE_TYPE1
;
957 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
961 return *file_type
!= DWRITE_FONT_FILE_TYPE_UNKNOWN
? S_OK
: S_FALSE
;
964 HRESULT
opentype_analyze_font(IDWriteFontFileStream
*stream
, UINT32
* font_count
, DWRITE_FONT_FILE_TYPE
*file_type
, DWRITE_FONT_FACE_TYPE
*face_type
, BOOL
*supported
)
966 static dwrite_fontfile_analyzer fontfile_analyzers
[] = {
967 opentype_ttf_analyzer
,
968 opentype_otf_analyzer
,
969 opentype_ttc_analyzer
,
970 opentype_type1_analyzer
,
973 dwrite_fontfile_analyzer
*analyzer
= fontfile_analyzers
;
974 DWRITE_FONT_FACE_TYPE face
;
980 *file_type
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
981 *face_type
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
985 hr
= (*analyzer
)(stream
, font_count
, file_type
, face_type
);
995 *supported
= is_face_type_supported(*face_type
);
999 HRESULT
opentype_get_font_table(struct file_stream_desc
*stream_desc
, UINT32 tag
, const void **table_data
,
1000 void **table_context
, UINT32
*table_size
, BOOL
*found
)
1003 TTC_SFNT_V1
*font_header
= NULL
;
1005 TT_TableRecord
*table_record
= NULL
;
1006 void *table_record_context
;
1007 int table_count
, table_offset
= 0;
1010 if (found
) *found
= FALSE
;
1011 if (table_size
) *table_size
= 0;
1014 *table_context
= NULL
;
1016 if (stream_desc
->face_type
== DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
) {
1017 const TTC_Header_V1
*ttc_header
;
1019 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&ttc_header
, 0, sizeof(*ttc_header
), &ttc_context
);
1020 if (SUCCEEDED(hr
)) {
1021 if (stream_desc
->face_index
>= GET_BE_DWORD(ttc_header
->numFonts
))
1024 table_offset
= GET_BE_DWORD(ttc_header
->OffsetTable
[stream_desc
->face_index
]);
1025 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&font_header
, table_offset
, sizeof(*font_header
), &sfnt_context
);
1027 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, ttc_context
);
1031 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&font_header
, 0, sizeof(*font_header
), &sfnt_context
);
1036 table_count
= GET_BE_WORD(font_header
->numTables
);
1037 table_offset
+= sizeof(*font_header
);
1038 for (i
= 0; i
< table_count
; i
++)
1040 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, (const void**)&table_record
, table_offset
, sizeof(*table_record
), &table_record_context
);
1043 if (DWRITE_MAKE_OPENTYPE_TAG(table_record
->tag
[0], table_record
->tag
[1], table_record
->tag
[2], table_record
->tag
[3]) == tag
)
1045 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, table_record_context
);
1046 table_offset
+= sizeof(*table_record
);
1049 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, sfnt_context
);
1050 if (SUCCEEDED(hr
) && i
< table_count
)
1052 int offset
= GET_BE_DWORD(table_record
->offset
);
1053 int length
= GET_BE_DWORD(table_record
->length
);
1054 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, table_record_context
);
1056 if (found
) *found
= TRUE
;
1057 if (table_size
) *table_size
= length
;
1058 hr
= IDWriteFontFileStream_ReadFileFragment(stream_desc
->stream
, table_data
, offset
, length
, table_context
);
1068 static UINT32
opentype_cmap_get_unicode_ranges_count(const CMAP_Header
*CMAP_Table
)
1073 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
); i
++) {
1077 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
1080 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
1081 type
= GET_BE_WORD(*table
);
1082 TRACE("table type %i\n", type
);
1086 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
1088 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
1089 count
+= GET_BE_WORD(format
->segCountX2
)/2;
1092 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
1094 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
1095 count
+= GET_BE_DWORD(format
->nGroups
);
1099 FIXME("table type %i unhandled.\n", type
);
1106 HRESULT
opentype_cmap_get_unicode_ranges(void *data
, UINT32 max_count
, DWRITE_UNICODE_RANGE
*ranges
, UINT32
*count
)
1108 CMAP_Header
*CMAP_Table
= data
;
1114 *count
= opentype_cmap_get_unicode_ranges_count(CMAP_Table
);
1116 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
) && k
< max_count
; i
++)
1122 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
1125 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
1126 type
= GET_BE_WORD(*table
);
1127 TRACE("table type %i\n", type
);
1131 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
1133 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
1134 UINT16 segment_count
= GET_BE_WORD(format
->segCountX2
)/2;
1135 UINT16
*startCode
= (WORD
*)((BYTE
*)format
+ sizeof(CMAP_SegmentMapping_0
) + (sizeof(WORD
) * segment_count
));
1137 for (j
= 0; j
< segment_count
&& GET_BE_WORD(format
->endCode
[j
]) < 0xffff && k
< max_count
; j
++, k
++) {
1138 ranges
[k
].first
= GET_BE_WORD(startCode
[j
]);
1139 ranges
[k
].last
= GET_BE_WORD(format
->endCode
[j
]);
1143 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
1145 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
1146 for (j
= 0; j
< GET_BE_DWORD(format
->nGroups
) && k
< max_count
; j
++, k
++) {
1147 ranges
[k
].first
= GET_BE_DWORD(format
->groups
[j
].startCharCode
);
1148 ranges
[k
].last
= GET_BE_DWORD(format
->groups
[j
].endCharCode
);
1153 FIXME("table type %i unhandled.\n", type
);
1157 return *count
> max_count
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
1160 void opentype_get_font_metrics(struct file_stream_desc
*stream_desc
, DWRITE_FONT_METRICS1
*metrics
, DWRITE_CARET_METRICS
*caret
)
1162 void *os2_context
, *head_context
, *post_context
, *hhea_context
;
1163 const TT_OS2_V2
*tt_os2
;
1164 const TT_HEAD
*tt_head
;
1165 const TT_POST
*tt_post
;
1166 const TT_HHEA
*tt_hhea
;
1168 memset(metrics
, 0, sizeof(*metrics
));
1170 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1171 opentype_get_font_table(stream_desc
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
1172 opentype_get_font_table(stream_desc
, MS_POST_TAG
, (const void**)&tt_post
, &post_context
, NULL
, NULL
);
1173 opentype_get_font_table(stream_desc
, MS_HHEA_TAG
, (const void**)&tt_hhea
, &hhea_context
, NULL
, NULL
);
1176 metrics
->designUnitsPerEm
= GET_BE_WORD(tt_head
->unitsPerEm
);
1177 metrics
->glyphBoxLeft
= GET_BE_WORD(tt_head
->xMin
);
1178 metrics
->glyphBoxTop
= GET_BE_WORD(tt_head
->yMax
);
1179 metrics
->glyphBoxRight
= GET_BE_WORD(tt_head
->xMax
);
1180 metrics
->glyphBoxBottom
= GET_BE_WORD(tt_head
->yMin
);
1185 caret
->slopeRise
= GET_BE_WORD(tt_hhea
->caretSlopeRise
);
1186 caret
->slopeRun
= GET_BE_WORD(tt_hhea
->caretSlopeRun
);
1187 caret
->offset
= GET_BE_WORD(tt_hhea
->caretOffset
);
1190 caret
->slopeRise
= 0;
1191 caret
->slopeRun
= 0;
1197 USHORT version
= GET_BE_WORD(tt_os2
->version
);
1199 metrics
->ascent
= GET_BE_WORD(tt_os2
->usWinAscent
);
1200 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
1201 interpreted as large unsigned value. */
1202 metrics
->descent
= abs((SHORT
)GET_BE_WORD(tt_os2
->usWinDescent
));
1204 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
1206 SHORT descender
= (SHORT
)GET_BE_WORD(tt_hhea
->descender
);
1209 linegap
= GET_BE_WORD(tt_hhea
->ascender
) + abs(descender
) + GET_BE_WORD(tt_hhea
->linegap
) -
1210 metrics
->ascent
- metrics
->descent
;
1211 metrics
->lineGap
= linegap
> 0 ? linegap
: 0;
1214 metrics
->strikethroughPosition
= GET_BE_WORD(tt_os2
->yStrikeoutPosition
);
1215 metrics
->strikethroughThickness
= GET_BE_WORD(tt_os2
->yStrikeoutSize
);
1216 metrics
->subscriptPositionX
= GET_BE_WORD(tt_os2
->ySubscriptXOffset
);
1217 /* Y offset is stored as positive offset below baseline */
1218 metrics
->subscriptPositionY
= -GET_BE_WORD(tt_os2
->ySubscriptYOffset
);
1219 metrics
->subscriptSizeX
= GET_BE_WORD(tt_os2
->ySubscriptXSize
);
1220 metrics
->subscriptSizeY
= GET_BE_WORD(tt_os2
->ySubscriptYSize
);
1221 metrics
->superscriptPositionX
= GET_BE_WORD(tt_os2
->ySuperscriptXOffset
);
1222 metrics
->superscriptPositionY
= GET_BE_WORD(tt_os2
->ySuperscriptYOffset
);
1223 metrics
->superscriptSizeX
= GET_BE_WORD(tt_os2
->ySuperscriptXSize
);
1224 metrics
->superscriptSizeY
= GET_BE_WORD(tt_os2
->ySuperscriptYSize
);
1226 /* version 2 fields */
1228 metrics
->capHeight
= GET_BE_WORD(tt_os2
->sCapHeight
);
1229 metrics
->xHeight
= GET_BE_WORD(tt_os2
->sxHeight
);
1232 if (GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_USE_TYPO_METRICS
) {
1233 SHORT descent
= GET_BE_WORD(tt_os2
->sTypoDescender
);
1234 metrics
->ascent
= GET_BE_WORD(tt_os2
->sTypoAscender
);
1235 metrics
->descent
= descent
< 0 ? -descent
: 0;
1236 metrics
->lineGap
= GET_BE_WORD(tt_os2
->sTypoLineGap
);
1237 metrics
->hasTypographicMetrics
= TRUE
;
1242 metrics
->underlinePosition
= GET_BE_WORD(tt_post
->underlinePosition
);
1243 metrics
->underlineThickness
= GET_BE_WORD(tt_post
->underlineThickness
);
1246 /* use any of thickness values if another one is zero, if both are zero use estimate */
1247 if (metrics
->strikethroughThickness
|| metrics
->underlineThickness
) {
1248 if (!metrics
->strikethroughThickness
)
1249 metrics
->strikethroughThickness
= metrics
->underlineThickness
;
1250 if (!metrics
->underlineThickness
)
1251 metrics
->underlineThickness
= metrics
->strikethroughThickness
;
1254 metrics
->strikethroughThickness
= metrics
->designUnitsPerEm
/ 14;
1255 metrics
->underlineThickness
= metrics
->designUnitsPerEm
/ 14;
1258 /* estimate missing metrics */
1259 if (metrics
->xHeight
== 0)
1260 metrics
->xHeight
= metrics
->designUnitsPerEm
/ 2;
1261 if (metrics
->capHeight
== 0)
1262 metrics
->capHeight
= metrics
->designUnitsPerEm
* 7 / 10;
1265 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1267 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, head_context
);
1269 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, post_context
);
1271 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, hhea_context
);
1274 void opentype_get_font_properties(struct file_stream_desc
*stream_desc
, struct dwrite_font_props
*props
)
1276 void *os2_context
, *head_context
;
1277 const TT_OS2_V2
*tt_os2
;
1278 const TT_HEAD
*tt_head
;
1280 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1281 opentype_get_font_table(stream_desc
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
1283 /* default stretch, weight and style to normal */
1284 props
->stretch
= DWRITE_FONT_STRETCH_NORMAL
;
1285 props
->weight
= DWRITE_FONT_WEIGHT_NORMAL
;
1286 props
->style
= DWRITE_FONT_STYLE_NORMAL
;
1287 memset(&props
->panose
, 0, sizeof(props
->panose
));
1289 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1291 USHORT version
= GET_BE_WORD(tt_os2
->version
);
1292 USHORT fsSelection
= GET_BE_WORD(tt_os2
->fsSelection
);
1293 USHORT usWeightClass
= GET_BE_WORD(tt_os2
->usWeightClass
);
1294 USHORT usWidthClass
= GET_BE_WORD(tt_os2
->usWidthClass
);
1296 if (usWidthClass
> DWRITE_FONT_STRETCH_UNDEFINED
&& usWidthClass
<= DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
1297 props
->stretch
= usWidthClass
;
1299 if (usWeightClass
>= 1 && usWeightClass
<= 9)
1300 usWeightClass
*= 100;
1302 if (usWeightClass
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
1303 props
->weight
= DWRITE_FONT_WEIGHT_ULTRA_BLACK
;
1304 else if (usWeightClass
> 0)
1305 props
->weight
= usWeightClass
;
1307 if (version
>= 4 && (fsSelection
& OS2_FSSELECTION_OBLIQUE
))
1308 props
->style
= DWRITE_FONT_STYLE_OBLIQUE
;
1309 else if (fsSelection
& OS2_FSSELECTION_ITALIC
)
1310 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
1311 memcpy(&props
->panose
, &tt_os2
->panose
, sizeof(props
->panose
));
1314 USHORT macStyle
= GET_BE_WORD(tt_head
->macStyle
);
1316 if (macStyle
& TT_HEAD_MACSTYLE_CONDENSED
)
1317 props
->stretch
= DWRITE_FONT_STRETCH_CONDENSED
;
1318 else if (macStyle
& TT_HEAD_MACSTYLE_EXTENDED
)
1319 props
->stretch
= DWRITE_FONT_STRETCH_EXPANDED
;
1321 if (macStyle
& TT_HEAD_MACSTYLE_BOLD
)
1322 props
->weight
= DWRITE_FONT_WEIGHT_BOLD
;
1324 if (macStyle
& TT_HEAD_MACSTYLE_ITALIC
)
1325 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
, IDWriteLocalizedStrings
**names
)
1612 const TT_OS2_V2
*tt_os2
;
1613 void *os2_context
, *name_context
;
1614 const void *name_table
;
1617 opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1618 opentype_get_font_table(stream_desc
, MS_NAME_TAG
, &name_table
, &name_context
, NULL
, NULL
);
1622 /* if Preferred Family doesn't conform to WWS model try WWS name */
1623 if (tt_os2
&& !(GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_WWS
))
1624 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_WWS_SUBFAMILY_NAME
, names
);
1629 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
, names
);
1631 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_SUBFAMILY_NAME
, names
);
1634 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1636 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, name_context
);
1641 static inline const OT_Script
*opentype_get_script(const OT_ScriptList
*scriptlist
, UINT32 scripttag
)
1645 for (j
= 0; j
< GET_BE_WORD(scriptlist
->ScriptCount
); j
++) {
1646 const char *tag
= scriptlist
->ScriptRecord
[j
].ScriptTag
;
1647 if (scripttag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1648 return (OT_Script
*)((BYTE
*)scriptlist
+ GET_BE_WORD(scriptlist
->ScriptRecord
[j
].Script
));
1654 static inline const OT_LangSys
*opentype_get_langsys(const OT_Script
*script
, UINT32 languagetag
)
1658 for (j
= 0; j
< GET_BE_WORD(script
->LangSysCount
); j
++) {
1659 const char *tag
= script
->LangSysRecord
[j
].LangSysTag
;
1660 if (languagetag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1661 return (OT_LangSys
*)((BYTE
*)script
+ GET_BE_WORD(script
->LangSysRecord
[j
].LangSys
));
1667 static void opentype_add_font_features(const GPOS_GSUB_Header
*header
, const OT_LangSys
*langsys
,
1668 UINT32 max_tagcount
, UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1670 const OT_FeatureList
*features
= (const OT_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1673 for (j
= 0; j
< GET_BE_WORD(langsys
->FeatureCount
); j
++) {
1674 const OT_FeatureRecord
*feature
= &features
->FeatureRecord
[langsys
->FeatureIndex
[j
]];
1675 const char *tag
= feature
->FeatureTag
;
1677 if (*count
< max_tagcount
)
1678 tags
[*count
] = DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]);
1684 HRESULT
opentype_get_typographic_features(IDWriteFontFace
*fontface
, UINT32 scripttag
, UINT32 languagetag
, UINT32 max_tagcount
,
1685 UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1687 UINT32 tables
[2] = { MS_GSUB_TAG
, MS_GPOS_TAG
};
1692 for (i
= 0; i
< sizeof(tables
)/sizeof(tables
[0]); i
++) {
1693 const OT_ScriptList
*scriptlist
;
1694 const GPOS_GSUB_Header
*header
;
1695 const OT_Script
*script
;
1702 hr
= IDWriteFontFace_TryGetFontTable(fontface
, tables
[i
], &ptr
, &size
, &context
, &exists
);
1709 header
= (const GPOS_GSUB_Header
*)ptr
;
1710 scriptlist
= (const OT_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
1712 script
= opentype_get_script(scriptlist
, scripttag
);
1714 const OT_LangSys
*langsys
= opentype_get_langsys(script
, languagetag
);
1716 opentype_add_font_features(header
, langsys
, max_tagcount
, count
, tags
);
1719 IDWriteFontFace_ReleaseFontTable(fontface
, context
);
1722 return *count
> max_tagcount
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
1725 static const struct VDMX_group
*find_vdmx_group(const struct VDMX_Header
*hdr
)
1727 WORD num_ratios
, i
, group_offset
= 0;
1728 struct VDMX_Ratio
*ratios
= (struct VDMX_Ratio
*)(hdr
+ 1);
1729 BYTE dev_x_ratio
= 1, dev_y_ratio
= 1;
1731 num_ratios
= GET_BE_WORD(hdr
->numRatios
);
1733 for (i
= 0; i
< num_ratios
; i
++) {
1735 if (!ratios
[i
].bCharSet
) continue;
1737 if ((ratios
[i
].xRatio
== 0 && ratios
[i
].yStartRatio
== 0 &&
1738 ratios
[i
].yEndRatio
== 0) ||
1739 (ratios
[i
].xRatio
== dev_x_ratio
&& ratios
[i
].yStartRatio
<= dev_y_ratio
&&
1740 ratios
[i
].yEndRatio
>= dev_y_ratio
))
1742 group_offset
= GET_BE_WORD(*((WORD
*)(ratios
+ num_ratios
) + i
));
1747 return (const struct VDMX_group
*)((BYTE
*)hdr
+ group_offset
);
1751 BOOL
opentype_get_vdmx_size(const void *data
, INT emsize
, UINT16
*ascent
, UINT16
*descent
)
1753 const struct VDMX_Header
*hdr
= (const struct VDMX_Header
*)data
;
1754 const struct VDMX_group
*group
;
1755 const struct VDMX_vTable
*tables
;
1761 group
= find_vdmx_group(hdr
);
1765 recs
= GET_BE_WORD(group
->recs
);
1766 if (emsize
< group
->startsz
|| emsize
>= group
->endsz
) return FALSE
;
1768 tables
= (const struct VDMX_vTable
*)(group
+ 1);
1769 for (i
= 0; i
< recs
; i
++) {
1770 WORD ppem
= GET_BE_WORD(tables
[i
].yPelHeight
);
1771 if (ppem
> emsize
) {
1772 FIXME("interpolate %d\n", emsize
);
1776 if (ppem
== emsize
) {
1777 *ascent
= (SHORT
)GET_BE_WORD(tables
[i
].yMax
);
1778 *descent
= -(SHORT
)GET_BE_WORD(tables
[i
].yMin
);
1785 WORD
opentype_get_gasp_flags(const WORD
*ptr
, UINT32 size
, INT emsize
)
1787 WORD num_recs
, version
;
1793 version
= GET_BE_WORD( *ptr
++ );
1794 num_recs
= GET_BE_WORD( *ptr
++ );
1795 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
)) {
1796 ERR("unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
1800 while (num_recs
--) {
1801 flags
= GET_BE_WORD( *(ptr
+ 1) );
1802 if (emsize
<= GET_BE_WORD( *ptr
)) break;
1810 UINT32
opentype_get_cpal_palettecount(const void *cpal
)
1812 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1813 return header
? GET_BE_WORD(header
->numPalette
) : 0;
1816 UINT32
opentype_get_cpal_paletteentrycount(const void *cpal
)
1818 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1819 return header
? GET_BE_WORD(header
->numPaletteEntries
) : 0;
1822 HRESULT
opentype_get_cpal_entries(const void *cpal
, UINT32 palette
, UINT32 first_entry_index
, UINT32 entry_count
,
1823 DWRITE_COLOR_F
*entries
)
1825 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1826 const struct CPAL_ColorRecord
*records
;
1827 UINT32 palettecount
, entrycount
, i
;
1829 if (!header
) return DWRITE_E_NOCOLOR
;
1831 palettecount
= GET_BE_WORD(header
->numPalette
);
1832 if (palette
>= palettecount
)
1833 return DWRITE_E_NOCOLOR
;
1835 entrycount
= GET_BE_WORD(header
->numPaletteEntries
);
1836 if (first_entry_index
+ entry_count
> entrycount
)
1837 return E_INVALIDARG
;
1839 records
= (const struct CPAL_ColorRecord
*)((BYTE
*)cpal
+ GET_BE_DWORD(header
->offsetFirstColorRecord
));
1840 first_entry_index
+= GET_BE_WORD(header
->colorRecordIndices
[palette
]);
1842 for (i
= 0; i
< entry_count
; i
++) {
1843 entries
[i
].r
= records
[first_entry_index
+ i
].red
/ 255.0f
;
1844 entries
[i
].g
= records
[first_entry_index
+ i
].green
/ 255.0f
;
1845 entries
[i
].b
= records
[first_entry_index
+ i
].blue
/ 255.0f
;
1846 entries
[i
].a
= records
[first_entry_index
+ i
].alpha
/ 255.0f
;
1852 static int colr_compare_gid(const void *g
, const void *r
)
1854 const struct COLR_BaseGlyphRecord
*record
= r
;
1855 UINT16 glyph
= *(UINT16
*)g
, GID
= GET_BE_WORD(record
->GID
);
1860 else if (glyph
< GID
)
1866 HRESULT
opentype_get_colr_glyph(const void *colr
, UINT16 glyph
, struct dwrite_colorglyph
*ret
)
1868 const struct COLR_BaseGlyphRecord
*record
;
1869 const struct COLR_Header
*header
= colr
;
1870 const struct COLR_LayerRecord
*layer
;
1871 DWORD layerrecordoffset
= GET_BE_DWORD(header
->offsetLayerRecord
);
1872 DWORD baserecordoffset
= GET_BE_DWORD(header
->offsetBaseGlyphRecord
);
1873 WORD numbaserecords
= GET_BE_WORD(header
->numBaseGlyphRecords
);
1875 record
= bsearch(&glyph
, (BYTE
*)colr
+ baserecordoffset
, numbaserecords
, sizeof(struct COLR_BaseGlyphRecord
),
1879 ret
->first_layer
= 0;
1880 ret
->num_layers
= 0;
1882 ret
->palette_index
= 0xffff;
1887 ret
->first_layer
= GET_BE_WORD(record
->firstLayerIndex
);
1888 ret
->num_layers
= GET_BE_WORD(record
->numLayers
);
1890 layer
= (struct COLR_LayerRecord
*)((BYTE
*)colr
+ layerrecordoffset
) + ret
->first_layer
+ ret
->layer
;
1891 ret
->glyph
= GET_BE_WORD(layer
->GID
);
1892 ret
->palette_index
= GET_BE_WORD(layer
->paletteIndex
);
1897 void opentype_colr_next_glyph(const void *colr
, struct dwrite_colorglyph
*glyph
)
1899 const struct COLR_Header
*header
= colr
;
1900 const struct COLR_LayerRecord
*layer
;
1901 DWORD layerrecordoffset
= GET_BE_DWORD(header
->offsetLayerRecord
);
1903 /* iterated all the way through */
1904 if (glyph
->layer
== glyph
->num_layers
)
1908 layer
= (struct COLR_LayerRecord
*)((BYTE
*)colr
+ layerrecordoffset
) + glyph
->first_layer
+ glyph
->layer
;
1909 glyph
->glyph
= GET_BE_WORD(layer
->GID
);
1910 glyph
->palette_index
= GET_BE_WORD(layer
->paletteIndex
);
1913 HRESULT
opentype_get_font_signature(struct file_stream_desc
*stream_desc
, FONTSIGNATURE
*fontsig
)
1915 const TT_OS2_V2
*tt_os2
;
1919 hr
= opentype_get_font_table(stream_desc
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1921 fontsig
->fsUsb
[0] = GET_BE_DWORD(tt_os2
->ulUnicodeRange1
);
1922 fontsig
->fsUsb
[1] = GET_BE_DWORD(tt_os2
->ulUnicodeRange2
);
1923 fontsig
->fsUsb
[2] = GET_BE_DWORD(tt_os2
->ulUnicodeRange3
);
1924 fontsig
->fsUsb
[3] = GET_BE_DWORD(tt_os2
->ulUnicodeRange4
);
1926 fontsig
->fsCsb
[0] = GET_BE_DWORD(tt_os2
->ulCodePageRange1
);
1927 fontsig
->fsCsb
[1] = GET_BE_DWORD(tt_os2
->ulCodePageRange2
);
1929 IDWriteFontFileStream_ReleaseFileFragment(stream_desc
->stream
, os2_context
);
1935 BOOL
opentype_has_vertical_variants(IDWriteFontFace3
*fontface
)
1937 const OT_FeatureList
*featurelist
;
1938 const OT_LookupList
*lookup_list
;
1939 BOOL exists
= FALSE
, ret
= FALSE
;
1940 const GPOS_GSUB_Header
*header
;
1947 hr
= IDWriteFontFace3_TryGetFontTable(fontface
, MS_GSUB_TAG
, &data
, &size
, &context
, &exists
);
1948 if (FAILED(hr
) || !exists
)
1952 featurelist
= (OT_FeatureList
*)((BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1953 lookup_list
= (const OT_LookupList
*)((BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
1955 for (i
= 0; i
< GET_BE_WORD(featurelist
->FeatureCount
); i
++) {
1956 if (*(UINT32
*)featurelist
->FeatureRecord
[i
].FeatureTag
== DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING
) {
1957 const OT_Feature
*feature
= (const OT_Feature
*)((BYTE
*)featurelist
+ GET_BE_WORD(featurelist
->FeatureRecord
[i
].Feature
));
1958 UINT16 lookup_count
= GET_BE_WORD(feature
->LookupCount
), i
, index
, count
, type
;
1959 const GSUB_SingleSubstFormat2
*subst2
;
1960 const OT_LookupTable
*lookup_table
;
1963 if (lookup_count
== 0)
1966 for (i
= 0; i
< lookup_count
; i
++) {
1967 /* check if lookup is empty */
1968 index
= GET_BE_WORD(feature
->LookupListIndex
[i
]);
1969 lookup_table
= (const OT_LookupTable
*)((BYTE
*)lookup_list
+ GET_BE_WORD(lookup_list
->Lookup
[index
]));
1971 type
= GET_BE_WORD(lookup_table
->LookupType
);
1972 if (type
!= OPENTYPE_GPOS_SINGLE_SUBST
&& type
!= OPENTYPE_GPOS_EXTENSION_SUBST
)
1975 count
= GET_BE_WORD(lookup_table
->SubTableCount
);
1979 offset
= GET_BE_WORD(lookup_table
->SubTable
[0]);
1980 if (type
== OPENTYPE_GPOS_EXTENSION_SUBST
) {
1981 const GSUB_ExtensionPosFormat1
*ext
= (const GSUB_ExtensionPosFormat1
*)((const BYTE
*)lookup_table
+ offset
);
1982 if (GET_BE_WORD(ext
->SubstFormat
) == 1)
1983 offset
+= GET_BE_DWORD(ext
->ExtensionOffset
);
1985 FIXME("Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext
->SubstFormat
));
1988 subst2
= (const GSUB_SingleSubstFormat2
*)((BYTE
*)lookup_table
+ offset
);
1989 index
= GET_BE_WORD(subst2
->SubstFormat
);
1991 FIXME("Validate Single Substitution Format 1\n");
1992 else if (index
== 2) {
1993 /* SimSun-ExtB has 0 glyph count for this substitution */
1994 if (GET_BE_WORD(subst2
->GlyphCount
) > 0) {
2000 WARN("Unknown Single Substitution Format, %u\n", index
);
2005 IDWriteFontFace3_ReleaseFontTable(fontface
, context
);