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')
37 #ifdef WORDS_BIGENDIAN
38 #define GET_BE_WORD(x) (x)
39 #define GET_BE_DWORD(x) (x)
41 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
42 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
71 } CMAP_EncodingRecord
;
76 CMAP_EncodingRecord tables
[1];
83 } CMAP_SegmentedCoverage_group
;
91 CMAP_SegmentedCoverage_group groups
[1];
92 } CMAP_SegmentedCoverage
;
103 } CMAP_SegmentMapping_0
;
105 enum OPENTYPE_CMAP_TABLE_FORMAT
107 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
= 4,
108 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
= 12
111 /* PANOSE is 10 bytes in size, need to pack the structure properly */
112 #include "pshpack2.h"
128 USHORT lowestRecPPEM
;
129 SHORT direction_hint
;
131 SHORT glyphdata_format
;
138 SHORT underlinePosition
;
139 SHORT underlineThickness
;
151 USHORT usWeightClass
;
154 SHORT ySubscriptXSize
;
155 SHORT ySubscriptYSize
;
156 SHORT ySubscriptXOffset
;
157 SHORT ySubscriptYOffset
;
158 SHORT ySuperscriptXSize
;
159 SHORT ySuperscriptYSize
;
160 SHORT ySuperscriptXOffset
;
161 SHORT ySuperscriptYOffset
;
162 SHORT yStrikeoutSize
;
163 SHORT yStrikeoutPosition
;
166 ULONG ulUnicodeRange1
;
167 ULONG ulUnicodeRange2
;
168 ULONG ulUnicodeRange3
;
169 ULONG ulUnicodeRange4
;
172 USHORT usFirstCharIndex
;
173 USHORT usLastCharIndex
;
174 /* According to the Apple spec, original version didn't have the below fields,
175 * version numbers were taken from the OpenType spec.
177 /* version 0 (TrueType 1.5) */
178 USHORT sTypoAscender
;
179 USHORT sTypoDescender
;
183 /* version 1 (TrueType 1.66) */
184 ULONG ulCodePageRange1
;
185 ULONG ulCodePageRange2
;
186 /* version 2 (OpenType 1.2) */
189 USHORT usDefaultChar
;
199 USHORT advanceWidthMax
;
200 SHORT minLeftSideBearing
;
201 SHORT minRightSideBearing
;
203 SHORT caretSlopeRise
;
207 SHORT metricDataFormat
;
208 USHORT numberOfHMetrics
;
213 enum OS2_FSSELECTION
{
214 OS2_FSSELECTION_ITALIC
= 1 << 0,
215 OS2_FSSELECTION_UNDERSCORE
= 1 << 1,
216 OS2_FSSELECTION_NEGATIVE
= 1 << 2,
217 OS2_FSSELECTION_OUTLINED
= 1 << 3,
218 OS2_FSSELECTION_STRIKEOUT
= 1 << 4,
219 OS2_FSSELECTION_BOLD
= 1 << 5,
220 OS2_FSSELECTION_REGULAR
= 1 << 6,
221 OS2_FSSELECTION_USE_TYPO_METRICS
= 1 << 7,
222 OS2_FSSELECTION_WWS
= 1 << 8,
223 OS2_FSSELECTION_OBLIQUE
= 1 << 9
239 TT_NameRecord nameRecord
[1];
278 OT_FeatureRecord FeatureRecord
[1];
282 WORD LookupOrder
; /* Reserved */
283 WORD ReqFeatureIndex
;
285 WORD FeatureIndex
[1];
296 OT_LangSysRecord LangSysRecord
[1];
306 OT_ScriptRecord ScriptRecord
[1];
316 enum OPENTYPE_PLATFORM_ID
318 OPENTYPE_PLATFORM_UNICODE
= 0,
319 OPENTYPE_PLATFORM_MAC
,
320 OPENTYPE_PLATFORM_ISO
,
321 OPENTYPE_PLATFORM_WIN
,
322 OPENTYPE_PLATFORM_CUSTOM
325 enum TT_NAME_WINDOWS_ENCODING_ID
327 TT_NAME_WINDOWS_ENCODING_SYMBOL
= 0,
328 TT_NAME_WINDOWS_ENCODING_UCS2
,
329 TT_NAME_WINDOWS_ENCODING_SJIS
,
330 TT_NAME_WINDOWS_ENCODING_PRC
,
331 TT_NAME_WINDOWS_ENCODING_BIG5
,
332 TT_NAME_WINDOWS_ENCODING_WANSUNG
,
333 TT_NAME_WINDOWS_ENCODING_JOHAB
,
334 TT_NAME_WINDOWS_ENCODING_RESERVED1
,
335 TT_NAME_WINDOWS_ENCODING_RESERVED2
,
336 TT_NAME_WINDOWS_ENCODING_RESERVED3
,
337 TT_NAME_WINDOWS_ENCODING_UCS4
340 enum TT_NAME_MAC_ENCODING_ID
342 TT_NAME_MAC_ENCODING_ROMAN
= 0,
343 TT_NAME_MAC_ENCODING_JAPANESE
,
344 TT_NAME_MAC_ENCODING_TRAD_CHINESE
,
345 TT_NAME_MAC_ENCODING_KOREAN
,
346 TT_NAME_MAC_ENCODING_ARABIC
,
347 TT_NAME_MAC_ENCODING_HEBREW
,
348 TT_NAME_MAC_ENCODING_GREEK
,
349 TT_NAME_MAC_ENCODING_RUSSIAN
,
350 TT_NAME_MAC_ENCODING_RSYMBOL
,
351 TT_NAME_MAC_ENCODING_DEVANAGARI
,
352 TT_NAME_MAC_ENCODING_GURMUKHI
,
353 TT_NAME_MAC_ENCODING_GUJARATI
,
354 TT_NAME_MAC_ENCODING_ORIYA
,
355 TT_NAME_MAC_ENCODING_BENGALI
,
356 TT_NAME_MAC_ENCODING_TAMIL
,
357 TT_NAME_MAC_ENCODING_TELUGU
,
358 TT_NAME_MAC_ENCODING_KANNADA
,
359 TT_NAME_MAC_ENCODING_MALAYALAM
,
360 TT_NAME_MAC_ENCODING_SINHALESE
,
361 TT_NAME_MAC_ENCODING_BURMESE
,
362 TT_NAME_MAC_ENCODING_KHMER
,
363 TT_NAME_MAC_ENCODING_THAI
,
364 TT_NAME_MAC_ENCODING_LAOTIAN
,
365 TT_NAME_MAC_ENCODING_GEORGIAN
,
366 TT_NAME_MAC_ENCODING_ARMENIAN
,
367 TT_NAME_MAC_ENCODING_SIMPL_CHINESE
,
368 TT_NAME_MAC_ENCODING_TIBETAN
,
369 TT_NAME_MAC_ENCODING_MONGOLIAN
,
370 TT_NAME_MAC_ENCODING_GEEZ
,
371 TT_NAME_MAC_ENCODING_SLAVIC
,
372 TT_NAME_MAC_ENCODING_VIETNAMESE
,
373 TT_NAME_MAC_ENCODING_SINDHI
,
374 TT_NAME_MAC_ENCODING_UNINTERPRETED
377 enum TT_NAME_MAC_LANGUAGE_ID
379 TT_NAME_MAC_LANGID_ENGLISH
= 0,
380 TT_NAME_MAC_LANGID_FRENCH
,
381 TT_NAME_MAC_LANGID_GERMAN
,
382 TT_NAME_MAC_LANGID_ITALIAN
,
383 TT_NAME_MAC_LANGID_DUTCH
,
384 TT_NAME_MAC_LANGID_SWEDISH
,
385 TT_NAME_MAC_LANGID_SPANISH
,
386 TT_NAME_MAC_LANGID_DANISH
,
387 TT_NAME_MAC_LANGID_PORTUGUESE
,
388 TT_NAME_MAC_LANGID_NORWEGIAN
,
389 TT_NAME_MAC_LANGID_HEBREW
,
390 TT_NAME_MAC_LANGID_JAPANESE
,
391 TT_NAME_MAC_LANGID_ARABIC
,
392 TT_NAME_MAC_LANGID_FINNISH
,
393 TT_NAME_MAC_LANGID_GREEK
,
394 TT_NAME_MAC_LANGID_ICELANDIC
,
395 TT_NAME_MAC_LANGID_MALTESE
,
396 TT_NAME_MAC_LANGID_TURKISH
,
397 TT_NAME_MAC_LANGID_CROATIAN
,
398 TT_NAME_MAC_LANGID_TRAD_CHINESE
,
399 TT_NAME_MAC_LANGID_URDU
,
400 TT_NAME_MAC_LANGID_HINDI
,
401 TT_NAME_MAC_LANGID_THAI
,
402 TT_NAME_MAC_LANGID_KOREAN
,
403 TT_NAME_MAC_LANGID_LITHUANIAN
,
404 TT_NAME_MAC_LANGID_POLISH
,
405 TT_NAME_MAC_LANGID_HUNGARIAN
,
406 TT_NAME_MAC_LANGID_ESTONIAN
,
407 TT_NAME_MAC_LANGID_LATVIAN
,
408 TT_NAME_MAC_LANGID_SAMI
,
409 TT_NAME_MAC_LANGID_FAROESE
,
410 TT_NAME_MAC_LANGID_FARSI
,
411 TT_NAME_MAC_LANGID_RUSSIAN
,
412 TT_NAME_MAC_LANGID_SIMPL_CHINESE
,
413 TT_NAME_MAC_LANGID_FLEMISH
,
414 TT_NAME_MAC_LANGID_GAELIC
,
415 TT_NAME_MAC_LANGID_ALBANIAN
,
416 TT_NAME_MAC_LANGID_ROMANIAN
,
417 TT_NAME_MAC_LANGID_CZECH
,
418 TT_NAME_MAC_LANGID_SLOVAK
,
419 TT_NAME_MAC_LANGID_SLOVENIAN
,
420 TT_NAME_MAC_LANGID_YIDDISH
,
421 TT_NAME_MAC_LANGID_SERBIAN
,
422 TT_NAME_MAC_LANGID_MACEDONIAN
,
423 TT_NAME_MAC_LANGID_BULGARIAN
,
424 TT_NAME_MAC_LANGID_UKRAINIAN
,
425 TT_NAME_MAC_LANGID_BYELORUSSIAN
,
426 TT_NAME_MAC_LANGID_UZBEK
,
427 TT_NAME_MAC_LANGID_KAZAKH
,
428 TT_NAME_MAC_LANGID_AZERB_CYR
,
429 TT_NAME_MAC_LANGID_AZERB_ARABIC
,
430 TT_NAME_MAC_LANGID_ARMENIAN
,
431 TT_NAME_MAC_LANGID_GEORGIAN
,
432 TT_NAME_MAC_LANGID_MOLDAVIAN
,
433 TT_NAME_MAC_LANGID_KIRGHIZ
,
434 TT_NAME_MAC_LANGID_TAJIKI
,
435 TT_NAME_MAC_LANGID_TURKMEN
,
436 TT_NAME_MAC_LANGID_MONGOLIAN
,
437 TT_NAME_MAC_LANGID_MONGOLIAN_CYR
,
438 TT_NAME_MAC_LANGID_PASHTO
,
439 TT_NAME_MAC_LANGID_KURDISH
,
440 TT_NAME_MAC_LANGID_KASHMIRI
,
441 TT_NAME_MAC_LANGID_SINDHI
,
442 TT_NAME_MAC_LANGID_TIBETAN
,
443 TT_NAME_MAC_LANGID_NEPALI
,
444 TT_NAME_MAC_LANGID_SANSKRIT
,
445 TT_NAME_MAC_LANGID_MARATHI
,
446 TT_NAME_MAC_LANGID_BENGALI
,
447 TT_NAME_MAC_LANGID_ASSAMESE
,
448 TT_NAME_MAC_LANGID_GUJARATI
,
449 TT_NAME_MAC_LANGID_PUNJABI
,
450 TT_NAME_MAC_LANGID_ORIYA
,
451 TT_NAME_MAC_LANGID_MALAYALAM
,
452 TT_NAME_MAC_LANGID_KANNADA
,
453 TT_NAME_MAC_LANGID_TAMIL
,
454 TT_NAME_MAC_LANGID_TELUGU
,
455 TT_NAME_MAC_LANGID_SINHALESE
,
456 TT_NAME_MAC_LANGID_BURMESE
,
457 TT_NAME_MAC_LANGID_KHMER
,
458 TT_NAME_MAC_LANGID_LAO
,
459 TT_NAME_MAC_LANGID_VIETNAMESE
,
460 TT_NAME_MAC_LANGID_INDONESIAN
,
461 TT_NAME_MAC_LANGID_TAGALONG
,
462 TT_NAME_MAC_LANGID_MALAY_ROMAN
,
463 TT_NAME_MAC_LANGID_MALAY_ARABIC
,
464 TT_NAME_MAC_LANGID_AMHARIC
,
465 TT_NAME_MAC_LANGID_TIGRINYA
,
466 TT_NAME_MAC_LANGID_GALLA
,
467 TT_NAME_MAC_LANGID_SOMALI
,
468 TT_NAME_MAC_LANGID_SWAHILI
,
469 TT_NAME_MAC_LANGID_KINYARWANDA
,
470 TT_NAME_MAC_LANGID_RUNDI
,
471 TT_NAME_MAC_LANGID_NYANJA
,
472 TT_NAME_MAC_LANGID_MALAGASY
,
473 TT_NAME_MAC_LANGID_ESPERANTO
,
474 TT_NAME_MAC_LANGID_WELSH
,
475 TT_NAME_MAC_LANGID_BASQUE
,
476 TT_NAME_MAC_LANGID_CATALAN
,
477 TT_NAME_MAC_LANGID_LATIN
,
478 TT_NAME_MAC_LANGID_QUENCHUA
,
479 TT_NAME_MAC_LANGID_GUARANI
,
480 TT_NAME_MAC_LANGID_AYMARA
,
481 TT_NAME_MAC_LANGID_TATAR
,
482 TT_NAME_MAC_LANGID_UIGHUR
,
483 TT_NAME_MAC_LANGID_DZONGKHA
,
484 TT_NAME_MAC_LANGID_JAVANESE
,
485 TT_NAME_MAC_LANGID_SUNDANESE
,
486 TT_NAME_MAC_LANGID_GALICIAN
,
487 TT_NAME_MAC_LANGID_AFRIKAANS
,
488 TT_NAME_MAC_LANGID_BRETON
,
489 TT_NAME_MAC_LANGID_INUKTITUT
,
490 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC
,
491 TT_NAME_MAC_LANGID_MANX_GAELIC
,
492 TT_NAME_MAC_LANGID_IRISH_GAELIC
,
493 TT_NAME_MAC_LANGID_TONGAN
,
494 TT_NAME_MAC_LANGID_GREEK_POLYTONIC
,
495 TT_NAME_MAC_LANGID_GREENLANDIC
,
496 TT_NAME_MAC_LANGID_AZER_ROMAN
499 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
500 static const char name_mac_langid_to_locale
[][10] = {
621 enum OPENTYPE_STRING_ID
623 OPENTYPE_STRING_COPYRIGHT_NOTICE
= 0,
624 OPENTYPE_STRING_FAMILY_NAME
,
625 OPENTYPE_STRING_SUBFAMILY_NAME
,
626 OPENTYPE_STRING_UNIQUE_IDENTIFIER
,
627 OPENTYPE_STRING_FULL_FONTNAME
,
628 OPENTYPE_STRING_VERSION_STRING
,
629 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
630 OPENTYPE_STRING_TRADEMARK
,
631 OPENTYPE_STRING_MANUFACTURER
,
632 OPENTYPE_STRING_DESIGNER
,
633 OPENTYPE_STRING_DESCRIPTION
,
634 OPENTYPE_STRING_VENDOR_URL
,
635 OPENTYPE_STRING_DESIGNER_URL
,
636 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
637 OPENTYPE_STRING_LICENSE_INFO_URL
,
638 OPENTYPE_STRING_RESERVED_ID15
,
639 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
640 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
641 OPENTYPE_STRING_COMPATIBLE_FULLNAME
,
642 OPENTYPE_STRING_SAMPLE_TEXT
,
643 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
644 OPENTYPE_STRING_WWS_FAMILY_NAME
,
645 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
648 static const UINT16 dwriteid_to_opentypeid
[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME
+1] =
650 (UINT16
)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
651 OPENTYPE_STRING_COPYRIGHT_NOTICE
,
652 OPENTYPE_STRING_VERSION_STRING
,
653 OPENTYPE_STRING_TRADEMARK
,
654 OPENTYPE_STRING_MANUFACTURER
,
655 OPENTYPE_STRING_DESIGNER
,
656 OPENTYPE_STRING_DESIGNER_URL
,
657 OPENTYPE_STRING_DESCRIPTION
,
658 OPENTYPE_STRING_VENDOR_URL
,
659 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
660 OPENTYPE_STRING_LICENSE_INFO_URL
,
661 OPENTYPE_STRING_FAMILY_NAME
,
662 OPENTYPE_STRING_SUBFAMILY_NAME
,
663 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
664 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
665 OPENTYPE_STRING_SAMPLE_TEXT
,
666 OPENTYPE_STRING_FULL_FONTNAME
,
667 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
668 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
671 BOOL
is_face_type_supported(DWRITE_FONT_FACE_TYPE type
)
673 return (type
== DWRITE_FONT_FACE_TYPE_CFF
) ||
674 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE
) ||
675 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
) ||
676 (type
== DWRITE_FONT_FACE_TYPE_RAW_CFF
);
679 HRESULT
opentype_analyze_font(IDWriteFontFileStream
*stream
, UINT32
* font_count
, DWRITE_FONT_FILE_TYPE
*file_type
, DWRITE_FONT_FACE_TYPE
*face_type
, BOOL
*supported
)
681 /* TODO: Do font validation */
682 DWRITE_FONT_FACE_TYPE face
;
683 const void *font_data
;
688 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, &font_data
, 0, sizeof(TTC_Header_V1
), &context
);
693 *file_type
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
694 face
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
697 if (DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]) == MS_TTCF_TAG
)
699 const TTC_Header_V1
*header
= font_data
;
700 *font_count
= GET_BE_DWORD(header
->numFonts
);
701 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION
;
702 face
= DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
;
704 else if (GET_BE_DWORD(*(DWORD
*)font_data
) == 0x10000)
707 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE
;
708 face
= DWRITE_FONT_FACE_TYPE_TRUETYPE
;
710 else if (DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]) == MS_OTTO_TAG
)
712 *file_type
= DWRITE_FONT_FILE_TYPE_CFF
;
713 face
= DWRITE_FONT_FACE_TYPE_CFF
;
719 *supported
= is_face_type_supported(face
);
721 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
725 HRESULT
opentype_get_font_table(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE type
, UINT32 font_index
, UINT32 tag
,
726 const void **table_data
, void **table_context
, UINT32
*table_size
, BOOL
*found
)
729 TTC_SFNT_V1
*font_header
= NULL
;
731 TT_TableRecord
*table_record
= NULL
;
732 void *table_record_context
;
733 int table_count
, table_offset
= 0;
736 if (found
) *found
= FALSE
;
737 if (table_size
) *table_size
= 0;
739 if (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
) {
740 const TTC_Header_V1
*ttc_header
;
742 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&ttc_header
, 0, sizeof(*ttc_header
), &ttc_context
);
744 table_offset
= GET_BE_DWORD(ttc_header
->OffsetTable
[0]);
745 if (font_index
>= GET_BE_DWORD(ttc_header
->numFonts
))
748 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&font_header
, table_offset
, sizeof(*font_header
), &sfnt_context
);
749 IDWriteFontFileStream_ReleaseFileFragment(stream
, ttc_context
);
753 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&font_header
, 0, sizeof(*font_header
), &sfnt_context
);
758 table_count
= GET_BE_WORD(font_header
->numTables
);
759 table_offset
+= sizeof(*font_header
);
760 for (i
= 0; i
< table_count
; i
++)
762 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&table_record
, table_offset
, sizeof(*table_record
), &table_record_context
);
765 if (DWRITE_MAKE_OPENTYPE_TAG(table_record
->tag
[0], table_record
->tag
[1], table_record
->tag
[2], table_record
->tag
[3]) == tag
)
767 IDWriteFontFileStream_ReleaseFileFragment(stream
, table_record_context
);
768 table_offset
+= sizeof(*table_record
);
771 IDWriteFontFileStream_ReleaseFileFragment(stream
, sfnt_context
);
772 if (SUCCEEDED(hr
) && i
< table_count
)
774 int offset
= GET_BE_DWORD(table_record
->offset
);
775 int length
= GET_BE_DWORD(table_record
->length
);
776 IDWriteFontFileStream_ReleaseFileFragment(stream
, table_record_context
);
778 if (found
) *found
= TRUE
;
779 if (table_size
) *table_size
= length
;
780 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, table_data
, offset
, length
, table_context
);
790 static UINT32
opentype_cmap_get_unicode_ranges_count(const CMAP_Header
*CMAP_Table
)
795 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
); i
++) {
799 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
802 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
803 type
= GET_BE_WORD(*table
);
804 TRACE("table type %i\n", type
);
808 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
810 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
811 count
+= GET_BE_WORD(format
->segCountX2
)/2;
814 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
816 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
817 count
+= GET_BE_DWORD(format
->nGroups
);
821 FIXME("table type %i unhandled.\n", type
);
828 HRESULT
opentype_cmap_get_unicode_ranges(void *data
, UINT32 max_count
, DWRITE_UNICODE_RANGE
*ranges
, UINT32
*count
)
830 CMAP_Header
*CMAP_Table
= data
;
836 *count
= opentype_cmap_get_unicode_ranges_count(CMAP_Table
);
838 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
) && k
< max_count
; i
++)
844 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
847 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
848 type
= GET_BE_WORD(*table
);
849 TRACE("table type %i\n", type
);
853 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
855 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
856 UINT16 segment_count
= GET_BE_WORD(format
->segCountX2
)/2;
857 UINT16
*startCode
= (WORD
*)((BYTE
*)format
+ sizeof(CMAP_SegmentMapping_0
) + (sizeof(WORD
) * segment_count
));
859 for (j
= 0; j
< segment_count
&& GET_BE_WORD(format
->endCode
[j
]) < 0xffff && k
< max_count
; j
++, k
++) {
860 ranges
[k
].first
= GET_BE_WORD(startCode
[j
]);
861 ranges
[k
].last
= GET_BE_WORD(format
->endCode
[j
]);
865 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
867 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
868 for (j
= 0; j
< GET_BE_DWORD(format
->nGroups
) && k
< max_count
; j
++, k
++) {
869 ranges
[k
].first
= GET_BE_DWORD(format
->groups
[j
].startCharCode
);
870 ranges
[k
].last
= GET_BE_DWORD(format
->groups
[j
].endCharCode
);
875 FIXME("table type %i unhandled.\n", type
);
879 return *count
> max_count
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
882 void opentype_get_font_metrics(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE face_type
, UINT32 face_index
,
883 DWRITE_FONT_METRICS1
*metrics
, DWRITE_CARET_METRICS
*caret
)
885 void *os2_context
, *head_context
, *post_context
, *hhea_context
;
886 const TT_OS2_V2
*tt_os2
;
887 const TT_HEAD
*tt_head
;
888 const TT_POST
*tt_post
;
889 const TT_HHEA
*tt_hhea
;
891 memset(metrics
, 0, sizeof(*metrics
));
893 opentype_get_font_table(stream
, face_type
, face_index
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
894 opentype_get_font_table(stream
, face_type
, face_index
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
895 opentype_get_font_table(stream
, face_type
, face_index
, MS_POST_TAG
, (const void**)&tt_post
, &post_context
, NULL
, NULL
);
896 opentype_get_font_table(stream
, face_type
, face_index
, MS_HHEA_TAG
, (const void**)&tt_hhea
, &hhea_context
, NULL
, NULL
);
899 metrics
->designUnitsPerEm
= GET_BE_WORD(tt_head
->unitsPerEm
);
900 metrics
->glyphBoxLeft
= GET_BE_WORD(tt_head
->xMin
);
901 metrics
->glyphBoxTop
= GET_BE_WORD(tt_head
->yMax
);
902 metrics
->glyphBoxRight
= GET_BE_WORD(tt_head
->xMax
);
903 metrics
->glyphBoxBottom
= GET_BE_WORD(tt_head
->yMin
);
908 caret
->slopeRise
= GET_BE_WORD(tt_hhea
->caretSlopeRise
);
909 caret
->slopeRun
= GET_BE_WORD(tt_hhea
->caretSlopeRun
);
910 caret
->offset
= GET_BE_WORD(tt_hhea
->caretOffset
);
913 caret
->slopeRise
= 0;
920 USHORT version
= GET_BE_WORD(tt_os2
->version
);
922 metrics
->ascent
= GET_BE_WORD(tt_os2
->usWinAscent
);
923 metrics
->descent
= GET_BE_WORD(tt_os2
->usWinDescent
);
925 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
927 SHORT descender
= (SHORT
)GET_BE_WORD(tt_hhea
->descender
);
930 linegap
= GET_BE_WORD(tt_hhea
->ascender
) + abs(descender
) + GET_BE_WORD(tt_hhea
->linegap
) -
931 metrics
->ascent
- metrics
->descent
;
932 metrics
->lineGap
= linegap
> 0 ? linegap
: 0;
935 metrics
->strikethroughPosition
= GET_BE_WORD(tt_os2
->yStrikeoutPosition
);
936 metrics
->strikethroughThickness
= GET_BE_WORD(tt_os2
->yStrikeoutSize
);
937 metrics
->subscriptPositionX
= GET_BE_WORD(tt_os2
->ySubscriptXOffset
);
938 /* Y offset is stored as positive offset below baseline */
939 metrics
->subscriptPositionY
= -GET_BE_WORD(tt_os2
->ySubscriptYOffset
);
940 metrics
->subscriptSizeX
= GET_BE_WORD(tt_os2
->ySubscriptXSize
);
941 metrics
->subscriptSizeY
= GET_BE_WORD(tt_os2
->ySubscriptYSize
);
942 metrics
->superscriptPositionX
= GET_BE_WORD(tt_os2
->ySuperscriptXOffset
);
943 metrics
->superscriptPositionY
= GET_BE_WORD(tt_os2
->ySuperscriptYOffset
);
944 metrics
->superscriptSizeX
= GET_BE_WORD(tt_os2
->ySuperscriptXSize
);
945 metrics
->superscriptSizeY
= GET_BE_WORD(tt_os2
->ySuperscriptYSize
);
947 /* version 2 fields */
949 metrics
->capHeight
= GET_BE_WORD(tt_os2
->sCapHeight
);
950 metrics
->xHeight
= GET_BE_WORD(tt_os2
->sxHeight
);
953 /* version 4 fields */
955 if (GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_USE_TYPO_METRICS
) {
956 SHORT descent
= GET_BE_WORD(tt_os2
->sTypoDescender
);
957 metrics
->ascent
= GET_BE_WORD(tt_os2
->sTypoAscender
);
958 metrics
->descent
= descent
< 0 ? -descent
: 0;
959 metrics
->lineGap
= GET_BE_WORD(tt_os2
->sTypoLineGap
);
960 metrics
->hasTypographicMetrics
= TRUE
;
966 metrics
->underlinePosition
= GET_BE_WORD(tt_post
->underlinePosition
);
967 metrics
->underlineThickness
= GET_BE_WORD(tt_post
->underlineThickness
);
970 /* estimate missing metrics */
971 if (metrics
->xHeight
== 0)
972 metrics
->xHeight
= metrics
->designUnitsPerEm
/ 2;
973 if (metrics
->capHeight
== 0)
974 metrics
->capHeight
= metrics
->designUnitsPerEm
* 7 / 10;
977 IDWriteFontFileStream_ReleaseFileFragment(stream
, os2_context
);
979 IDWriteFontFileStream_ReleaseFileFragment(stream
, head_context
);
981 IDWriteFontFileStream_ReleaseFileFragment(stream
, post_context
);
983 IDWriteFontFileStream_ReleaseFileFragment(stream
, hhea_context
);
986 void opentype_get_font_properties(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE type
, UINT32 index
,
987 struct dwrite_font_props
*props
)
989 void *os2_context
, *head_context
;
990 const TT_OS2_V2
*tt_os2
;
991 const TT_HEAD
*tt_head
;
993 opentype_get_font_table(stream
, type
, index
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
994 opentype_get_font_table(stream
, type
, index
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
996 /* default stretch, weight and style to normal */
997 props
->stretch
= DWRITE_FONT_STRETCH_NORMAL
;
998 props
->weight
= DWRITE_FONT_WEIGHT_NORMAL
;
999 props
->style
= DWRITE_FONT_STYLE_NORMAL
;
1000 memset(&props
->panose
, 0, sizeof(props
->panose
));
1002 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1004 if (GET_BE_WORD(tt_os2
->usWidthClass
) <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
1005 props
->stretch
= GET_BE_WORD(tt_os2
->usWidthClass
);
1007 props
->weight
= GET_BE_WORD(tt_os2
->usWeightClass
);
1008 memcpy(&props
->panose
, &tt_os2
->panose
, sizeof(props
->panose
));
1010 TRACE("stretch=%d, weight=%d\n", props
->stretch
, props
->weight
);
1014 USHORT macStyle
= GET_BE_WORD(tt_head
->macStyle
);
1015 if (macStyle
& 0x0002)
1016 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
1020 IDWriteFontFileStream_ReleaseFileFragment(stream
, os2_context
);
1022 IDWriteFontFileStream_ReleaseFileFragment(stream
, head_context
);
1025 static UINT
get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform
, USHORT encoding
)
1030 case OPENTYPE_PLATFORM_UNICODE
:
1032 case OPENTYPE_PLATFORM_MAC
:
1035 case TT_NAME_MAC_ENCODING_ROMAN
:
1038 case TT_NAME_MAC_ENCODING_JAPANESE
:
1041 case TT_NAME_MAC_ENCODING_TRAD_CHINESE
:
1044 case TT_NAME_MAC_ENCODING_KOREAN
:
1047 case TT_NAME_MAC_ENCODING_ARABIC
:
1050 case TT_NAME_MAC_ENCODING_HEBREW
:
1053 case TT_NAME_MAC_ENCODING_GREEK
:
1056 case TT_NAME_MAC_ENCODING_RUSSIAN
:
1059 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE
:
1062 case TT_NAME_MAC_ENCODING_THAI
:
1066 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1070 case OPENTYPE_PLATFORM_WIN
:
1073 case TT_NAME_WINDOWS_ENCODING_SYMBOL
:
1074 case TT_NAME_WINDOWS_ENCODING_UCS2
:
1076 case TT_NAME_WINDOWS_ENCODING_SJIS
:
1079 case TT_NAME_WINDOWS_ENCODING_PRC
:
1082 case TT_NAME_WINDOWS_ENCODING_BIG5
:
1085 case TT_NAME_WINDOWS_ENCODING_WANSUNG
:
1088 case TT_NAME_WINDOWS_ENCODING_JOHAB
:
1092 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1097 FIXME("unknown platform %d\n", platform
);
1103 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform
, USHORT lang_id
, WCHAR
*locale
, USHORT locale_len
)
1105 static const WCHAR enusW
[] = {'e','n','-','U','S',0};
1108 case OPENTYPE_PLATFORM_MAC
:
1110 const char *locale_name
= NULL
;
1112 if (lang_id
> TT_NAME_MAC_LANGID_AZER_ROMAN
)
1113 ERR("invalid mac lang id %d\n", lang_id
);
1114 else if (!name_mac_langid_to_locale
[lang_id
][0])
1115 FIXME("failed to map mac lang id %d to locale name\n", lang_id
);
1117 locale_name
= name_mac_langid_to_locale
[lang_id
];
1120 MultiByteToWideChar(CP_ACP
, 0, name_mac_langid_to_locale
[lang_id
], -1, locale
, locale_len
);
1122 strcpyW(locale
, enusW
);
1125 case OPENTYPE_PLATFORM_WIN
:
1126 if (!LCIDToLocaleName(MAKELCID(lang_id
, SORT_DEFAULT
), locale
, locale_len
, 0)) {
1127 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id
, SORT_DEFAULT
));
1128 strcpyW(locale
, enusW
);
1132 FIXME("unknown platform %d\n", platform
);
1136 HRESULT
opentype_get_font_strings_from_id(const void *table_data
, DWRITE_INFORMATIONAL_STRING_ID id
, IDWriteLocalizedStrings
**strings
)
1138 const TT_NAME_V0
*header
;
1139 BYTE
*storage_area
= 0;
1149 hr
= create_localizedstrings(strings
);
1150 if (FAILED(hr
)) return hr
;
1152 header
= table_data
;
1154 switch (header
->format
) {
1158 FIXME("unsupported NAME format %d\n", header
->format
);
1161 storage_area
= (LPBYTE
)table_data
+ GET_BE_WORD(header
->stringOffset
);
1162 count
= GET_BE_WORD(header
->count
);
1164 name_id
= dwriteid_to_opentypeid
[id
];
1167 for (i
= 0; i
< count
; i
++) {
1168 const TT_NameRecord
*record
= &header
->nameRecord
[i
];
1169 USHORT lang_id
, length
, offset
, encoding
, platform
;
1171 if (GET_BE_WORD(record
->nameID
) != name_id
)
1176 /* Right now only accept unicode and windows encoded fonts */
1177 platform
= GET_BE_WORD(record
->platformID
);
1178 if (platform
!= OPENTYPE_PLATFORM_UNICODE
&&
1179 platform
!= OPENTYPE_PLATFORM_MAC
&&
1180 platform
!= OPENTYPE_PLATFORM_WIN
)
1182 FIXME("platform %i not supported\n", platform
);
1186 /* Skip such entries for now, as it's not clear which locale is implied when
1187 unicode platform is used. Also fonts tend to duplicate those strings as
1188 WIN platform entries. */
1189 if (platform
== OPENTYPE_PLATFORM_UNICODE
)
1192 lang_id
= GET_BE_WORD(record
->languageID
);
1193 length
= GET_BE_WORD(record
->length
);
1194 offset
= GET_BE_WORD(record
->offset
);
1195 encoding
= GET_BE_WORD(record
->encodingID
);
1197 if (lang_id
< 0x8000) {
1198 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
1202 codepage
= get_name_record_codepage(platform
, encoding
);
1203 get_name_record_locale(platform
, lang_id
, locale
, sizeof(locale
)/sizeof(WCHAR
));
1206 DWORD len
= MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, NULL
, 0);
1207 name_string
= heap_alloc(sizeof(WCHAR
) * (len
+1));
1208 MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, name_string
, len
);
1209 name_string
[len
] = 0;
1214 length
/= sizeof(WCHAR
);
1215 name_string
= heap_strdupnW((LPWSTR
)(storage_area
+ offset
), length
);
1216 for (i
= 0; i
< length
; i
++)
1217 name_string
[i
] = GET_BE_WORD(name_string
[i
]);
1220 TRACE("string %s for locale %s found\n", debugstr_w(name_string
), debugstr_w(locale
));
1221 add_localizedstring(*strings
, locale
, name_string
);
1222 heap_free(name_string
);
1225 FIXME("handle NAME format 1\n");
1231 IDWriteLocalizedStrings_Release(*strings
);
1238 static inline const OT_Script
*opentype_get_script(const OT_ScriptList
*scriptlist
, UINT32 scripttag
)
1242 for (j
= 0; j
< GET_BE_WORD(scriptlist
->ScriptCount
); j
++) {
1243 const char *tag
= scriptlist
->ScriptRecord
[j
].ScriptTag
;
1244 if (scripttag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1245 return (OT_Script
*)((BYTE
*)scriptlist
+ GET_BE_WORD(scriptlist
->ScriptRecord
[j
].Script
));
1251 static inline const OT_LangSys
*opentype_get_langsys(const OT_Script
*script
, UINT32 languagetag
)
1255 for (j
= 0; j
< GET_BE_WORD(script
->LangSysCount
); j
++) {
1256 const char *tag
= script
->LangSysRecord
[j
].LangSysTag
;
1257 if (languagetag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1258 return (OT_LangSys
*)((BYTE
*)script
+ GET_BE_WORD(script
->LangSysRecord
[j
].LangSys
));
1264 static void opentype_add_font_features(const GPOS_GSUB_Header
*header
, const OT_LangSys
*langsys
,
1265 UINT32 max_tagcount
, UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1267 const OT_FeatureList
*features
= (const OT_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1270 for (j
= 0; j
< GET_BE_WORD(langsys
->FeatureCount
); j
++) {
1271 const OT_FeatureRecord
*feature
= &features
->FeatureRecord
[langsys
->FeatureIndex
[j
]];
1272 const char *tag
= feature
->FeatureTag
;
1274 if (*count
< max_tagcount
)
1275 tags
[*count
] = DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]);
1281 HRESULT
opentype_get_typographic_features(IDWriteFontFace
*fontface
, UINT32 scripttag
, UINT32 languagetag
, UINT32 max_tagcount
,
1282 UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1284 UINT32 tables
[2] = { MS_GSUB_TAG
, MS_GPOS_TAG
};
1289 for (i
= 0; i
< sizeof(tables
)/sizeof(tables
[0]); i
++) {
1290 const OT_ScriptList
*scriptlist
;
1291 const GPOS_GSUB_Header
*header
;
1292 const OT_Script
*script
;
1299 hr
= IDWriteFontFace_TryGetFontTable(fontface
, tables
[i
], &ptr
, &size
, &context
, &exists
);
1306 header
= (const GPOS_GSUB_Header
*)ptr
;
1307 scriptlist
= (const OT_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
1309 script
= opentype_get_script(scriptlist
, scripttag
);
1311 const OT_LangSys
*langsys
= opentype_get_langsys(script
, languagetag
);
1313 opentype_add_font_features(header
, langsys
, max_tagcount
, count
, tags
);
1316 IDWriteFontFace_ReleaseFontTable(fontface
, context
);
1319 return *count
> max_tagcount
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
1322 static const struct VDMX_group
*find_vdmx_group(const struct VDMX_Header
*hdr
)
1324 WORD num_ratios
, i
, group_offset
= 0;
1325 struct VDMX_Ratio
*ratios
= (struct VDMX_Ratio
*)(hdr
+ 1);
1326 BYTE dev_x_ratio
= 1, dev_y_ratio
= 1;
1328 num_ratios
= GET_BE_WORD(hdr
->numRatios
);
1330 for (i
= 0; i
< num_ratios
; i
++) {
1332 if (!ratios
[i
].bCharSet
) continue;
1334 if ((ratios
[i
].xRatio
== 0 && ratios
[i
].yStartRatio
== 0 &&
1335 ratios
[i
].yEndRatio
== 0) ||
1336 (ratios
[i
].xRatio
== dev_x_ratio
&& ratios
[i
].yStartRatio
<= dev_y_ratio
&&
1337 ratios
[i
].yEndRatio
>= dev_y_ratio
))
1339 group_offset
= GET_BE_WORD(*((WORD
*)(ratios
+ num_ratios
) + i
));
1344 return (const struct VDMX_group
*)((BYTE
*)hdr
+ group_offset
);
1348 BOOL
opentype_get_vdmx_size(const void *data
, INT emsize
, UINT16
*ascent
, UINT16
*descent
)
1350 const struct VDMX_Header
*hdr
= (const struct VDMX_Header
*)data
;
1351 const struct VDMX_group
*group
;
1352 const struct VDMX_vTable
*tables
;
1358 group
= find_vdmx_group(hdr
);
1362 recs
= GET_BE_WORD(group
->recs
);
1363 if (emsize
< group
->startsz
|| emsize
>= group
->endsz
) return FALSE
;
1365 tables
= (const struct VDMX_vTable
*)(group
+ 1);
1366 for (i
= 0; i
< recs
; i
++) {
1367 WORD ppem
= GET_BE_WORD(tables
[i
].yPelHeight
);
1368 if (ppem
> emsize
) {
1369 FIXME("interpolate %d\n", emsize
);
1373 if (ppem
== emsize
) {
1374 *ascent
= (SHORT
)GET_BE_WORD(tables
[i
].yMax
);
1375 *descent
= -(SHORT
)GET_BE_WORD(tables
[i
].yMin
);
1382 WORD
opentype_get_gasp_flags(const WORD
*ptr
, UINT32 size
, INT emsize
)
1384 WORD num_recs
, version
;
1390 version
= GET_BE_WORD( *ptr
++ );
1391 num_recs
= GET_BE_WORD( *ptr
++ );
1392 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
)) {
1393 ERR("unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
1397 while (num_recs
--) {
1398 flags
= GET_BE_WORD( *(ptr
+ 1) );
1399 if (emsize
<= GET_BE_WORD( *ptr
)) break;