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
337 enum TT_NAME_WINDOWS_ENCODING_ID
339 TT_NAME_WINDOWS_ENCODING_SYMBOL
= 0,
340 TT_NAME_WINDOWS_ENCODING_UCS2
,
341 TT_NAME_WINDOWS_ENCODING_SJIS
,
342 TT_NAME_WINDOWS_ENCODING_PRC
,
343 TT_NAME_WINDOWS_ENCODING_BIG5
,
344 TT_NAME_WINDOWS_ENCODING_WANSUNG
,
345 TT_NAME_WINDOWS_ENCODING_JOHAB
,
346 TT_NAME_WINDOWS_ENCODING_RESERVED1
,
347 TT_NAME_WINDOWS_ENCODING_RESERVED2
,
348 TT_NAME_WINDOWS_ENCODING_RESERVED3
,
349 TT_NAME_WINDOWS_ENCODING_UCS4
352 enum TT_NAME_MAC_ENCODING_ID
354 TT_NAME_MAC_ENCODING_ROMAN
= 0,
355 TT_NAME_MAC_ENCODING_JAPANESE
,
356 TT_NAME_MAC_ENCODING_TRAD_CHINESE
,
357 TT_NAME_MAC_ENCODING_KOREAN
,
358 TT_NAME_MAC_ENCODING_ARABIC
,
359 TT_NAME_MAC_ENCODING_HEBREW
,
360 TT_NAME_MAC_ENCODING_GREEK
,
361 TT_NAME_MAC_ENCODING_RUSSIAN
,
362 TT_NAME_MAC_ENCODING_RSYMBOL
,
363 TT_NAME_MAC_ENCODING_DEVANAGARI
,
364 TT_NAME_MAC_ENCODING_GURMUKHI
,
365 TT_NAME_MAC_ENCODING_GUJARATI
,
366 TT_NAME_MAC_ENCODING_ORIYA
,
367 TT_NAME_MAC_ENCODING_BENGALI
,
368 TT_NAME_MAC_ENCODING_TAMIL
,
369 TT_NAME_MAC_ENCODING_TELUGU
,
370 TT_NAME_MAC_ENCODING_KANNADA
,
371 TT_NAME_MAC_ENCODING_MALAYALAM
,
372 TT_NAME_MAC_ENCODING_SINHALESE
,
373 TT_NAME_MAC_ENCODING_BURMESE
,
374 TT_NAME_MAC_ENCODING_KHMER
,
375 TT_NAME_MAC_ENCODING_THAI
,
376 TT_NAME_MAC_ENCODING_LAOTIAN
,
377 TT_NAME_MAC_ENCODING_GEORGIAN
,
378 TT_NAME_MAC_ENCODING_ARMENIAN
,
379 TT_NAME_MAC_ENCODING_SIMPL_CHINESE
,
380 TT_NAME_MAC_ENCODING_TIBETAN
,
381 TT_NAME_MAC_ENCODING_MONGOLIAN
,
382 TT_NAME_MAC_ENCODING_GEEZ
,
383 TT_NAME_MAC_ENCODING_SLAVIC
,
384 TT_NAME_MAC_ENCODING_VIETNAMESE
,
385 TT_NAME_MAC_ENCODING_SINDHI
,
386 TT_NAME_MAC_ENCODING_UNINTERPRETED
389 enum TT_NAME_MAC_LANGUAGE_ID
391 TT_NAME_MAC_LANGID_ENGLISH
= 0,
392 TT_NAME_MAC_LANGID_FRENCH
,
393 TT_NAME_MAC_LANGID_GERMAN
,
394 TT_NAME_MAC_LANGID_ITALIAN
,
395 TT_NAME_MAC_LANGID_DUTCH
,
396 TT_NAME_MAC_LANGID_SWEDISH
,
397 TT_NAME_MAC_LANGID_SPANISH
,
398 TT_NAME_MAC_LANGID_DANISH
,
399 TT_NAME_MAC_LANGID_PORTUGUESE
,
400 TT_NAME_MAC_LANGID_NORWEGIAN
,
401 TT_NAME_MAC_LANGID_HEBREW
,
402 TT_NAME_MAC_LANGID_JAPANESE
,
403 TT_NAME_MAC_LANGID_ARABIC
,
404 TT_NAME_MAC_LANGID_FINNISH
,
405 TT_NAME_MAC_LANGID_GREEK
,
406 TT_NAME_MAC_LANGID_ICELANDIC
,
407 TT_NAME_MAC_LANGID_MALTESE
,
408 TT_NAME_MAC_LANGID_TURKISH
,
409 TT_NAME_MAC_LANGID_CROATIAN
,
410 TT_NAME_MAC_LANGID_TRAD_CHINESE
,
411 TT_NAME_MAC_LANGID_URDU
,
412 TT_NAME_MAC_LANGID_HINDI
,
413 TT_NAME_MAC_LANGID_THAI
,
414 TT_NAME_MAC_LANGID_KOREAN
,
415 TT_NAME_MAC_LANGID_LITHUANIAN
,
416 TT_NAME_MAC_LANGID_POLISH
,
417 TT_NAME_MAC_LANGID_HUNGARIAN
,
418 TT_NAME_MAC_LANGID_ESTONIAN
,
419 TT_NAME_MAC_LANGID_LATVIAN
,
420 TT_NAME_MAC_LANGID_SAMI
,
421 TT_NAME_MAC_LANGID_FAROESE
,
422 TT_NAME_MAC_LANGID_FARSI
,
423 TT_NAME_MAC_LANGID_RUSSIAN
,
424 TT_NAME_MAC_LANGID_SIMPL_CHINESE
,
425 TT_NAME_MAC_LANGID_FLEMISH
,
426 TT_NAME_MAC_LANGID_GAELIC
,
427 TT_NAME_MAC_LANGID_ALBANIAN
,
428 TT_NAME_MAC_LANGID_ROMANIAN
,
429 TT_NAME_MAC_LANGID_CZECH
,
430 TT_NAME_MAC_LANGID_SLOVAK
,
431 TT_NAME_MAC_LANGID_SLOVENIAN
,
432 TT_NAME_MAC_LANGID_YIDDISH
,
433 TT_NAME_MAC_LANGID_SERBIAN
,
434 TT_NAME_MAC_LANGID_MACEDONIAN
,
435 TT_NAME_MAC_LANGID_BULGARIAN
,
436 TT_NAME_MAC_LANGID_UKRAINIAN
,
437 TT_NAME_MAC_LANGID_BYELORUSSIAN
,
438 TT_NAME_MAC_LANGID_UZBEK
,
439 TT_NAME_MAC_LANGID_KAZAKH
,
440 TT_NAME_MAC_LANGID_AZERB_CYR
,
441 TT_NAME_MAC_LANGID_AZERB_ARABIC
,
442 TT_NAME_MAC_LANGID_ARMENIAN
,
443 TT_NAME_MAC_LANGID_GEORGIAN
,
444 TT_NAME_MAC_LANGID_MOLDAVIAN
,
445 TT_NAME_MAC_LANGID_KIRGHIZ
,
446 TT_NAME_MAC_LANGID_TAJIKI
,
447 TT_NAME_MAC_LANGID_TURKMEN
,
448 TT_NAME_MAC_LANGID_MONGOLIAN
,
449 TT_NAME_MAC_LANGID_MONGOLIAN_CYR
,
450 TT_NAME_MAC_LANGID_PASHTO
,
451 TT_NAME_MAC_LANGID_KURDISH
,
452 TT_NAME_MAC_LANGID_KASHMIRI
,
453 TT_NAME_MAC_LANGID_SINDHI
,
454 TT_NAME_MAC_LANGID_TIBETAN
,
455 TT_NAME_MAC_LANGID_NEPALI
,
456 TT_NAME_MAC_LANGID_SANSKRIT
,
457 TT_NAME_MAC_LANGID_MARATHI
,
458 TT_NAME_MAC_LANGID_BENGALI
,
459 TT_NAME_MAC_LANGID_ASSAMESE
,
460 TT_NAME_MAC_LANGID_GUJARATI
,
461 TT_NAME_MAC_LANGID_PUNJABI
,
462 TT_NAME_MAC_LANGID_ORIYA
,
463 TT_NAME_MAC_LANGID_MALAYALAM
,
464 TT_NAME_MAC_LANGID_KANNADA
,
465 TT_NAME_MAC_LANGID_TAMIL
,
466 TT_NAME_MAC_LANGID_TELUGU
,
467 TT_NAME_MAC_LANGID_SINHALESE
,
468 TT_NAME_MAC_LANGID_BURMESE
,
469 TT_NAME_MAC_LANGID_KHMER
,
470 TT_NAME_MAC_LANGID_LAO
,
471 TT_NAME_MAC_LANGID_VIETNAMESE
,
472 TT_NAME_MAC_LANGID_INDONESIAN
,
473 TT_NAME_MAC_LANGID_TAGALONG
,
474 TT_NAME_MAC_LANGID_MALAY_ROMAN
,
475 TT_NAME_MAC_LANGID_MALAY_ARABIC
,
476 TT_NAME_MAC_LANGID_AMHARIC
,
477 TT_NAME_MAC_LANGID_TIGRINYA
,
478 TT_NAME_MAC_LANGID_GALLA
,
479 TT_NAME_MAC_LANGID_SOMALI
,
480 TT_NAME_MAC_LANGID_SWAHILI
,
481 TT_NAME_MAC_LANGID_KINYARWANDA
,
482 TT_NAME_MAC_LANGID_RUNDI
,
483 TT_NAME_MAC_LANGID_NYANJA
,
484 TT_NAME_MAC_LANGID_MALAGASY
,
485 TT_NAME_MAC_LANGID_ESPERANTO
,
486 TT_NAME_MAC_LANGID_WELSH
,
487 TT_NAME_MAC_LANGID_BASQUE
,
488 TT_NAME_MAC_LANGID_CATALAN
,
489 TT_NAME_MAC_LANGID_LATIN
,
490 TT_NAME_MAC_LANGID_QUENCHUA
,
491 TT_NAME_MAC_LANGID_GUARANI
,
492 TT_NAME_MAC_LANGID_AYMARA
,
493 TT_NAME_MAC_LANGID_TATAR
,
494 TT_NAME_MAC_LANGID_UIGHUR
,
495 TT_NAME_MAC_LANGID_DZONGKHA
,
496 TT_NAME_MAC_LANGID_JAVANESE
,
497 TT_NAME_MAC_LANGID_SUNDANESE
,
498 TT_NAME_MAC_LANGID_GALICIAN
,
499 TT_NAME_MAC_LANGID_AFRIKAANS
,
500 TT_NAME_MAC_LANGID_BRETON
,
501 TT_NAME_MAC_LANGID_INUKTITUT
,
502 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC
,
503 TT_NAME_MAC_LANGID_MANX_GAELIC
,
504 TT_NAME_MAC_LANGID_IRISH_GAELIC
,
505 TT_NAME_MAC_LANGID_TONGAN
,
506 TT_NAME_MAC_LANGID_GREEK_POLYTONIC
,
507 TT_NAME_MAC_LANGID_GREENLANDIC
,
508 TT_NAME_MAC_LANGID_AZER_ROMAN
511 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
512 static const char name_mac_langid_to_locale
[][10] = {
633 enum OPENTYPE_STRING_ID
635 OPENTYPE_STRING_COPYRIGHT_NOTICE
= 0,
636 OPENTYPE_STRING_FAMILY_NAME
,
637 OPENTYPE_STRING_SUBFAMILY_NAME
,
638 OPENTYPE_STRING_UNIQUE_IDENTIFIER
,
639 OPENTYPE_STRING_FULL_FONTNAME
,
640 OPENTYPE_STRING_VERSION_STRING
,
641 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
642 OPENTYPE_STRING_TRADEMARK
,
643 OPENTYPE_STRING_MANUFACTURER
,
644 OPENTYPE_STRING_DESIGNER
,
645 OPENTYPE_STRING_DESCRIPTION
,
646 OPENTYPE_STRING_VENDOR_URL
,
647 OPENTYPE_STRING_DESIGNER_URL
,
648 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
649 OPENTYPE_STRING_LICENSE_INFO_URL
,
650 OPENTYPE_STRING_RESERVED_ID15
,
651 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
652 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
653 OPENTYPE_STRING_COMPATIBLE_FULLNAME
,
654 OPENTYPE_STRING_SAMPLE_TEXT
,
655 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
656 OPENTYPE_STRING_WWS_FAMILY_NAME
,
657 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
660 static const UINT16 dwriteid_to_opentypeid
[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME
+1] =
662 (UINT16
)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
663 OPENTYPE_STRING_COPYRIGHT_NOTICE
,
664 OPENTYPE_STRING_VERSION_STRING
,
665 OPENTYPE_STRING_TRADEMARK
,
666 OPENTYPE_STRING_MANUFACTURER
,
667 OPENTYPE_STRING_DESIGNER
,
668 OPENTYPE_STRING_DESIGNER_URL
,
669 OPENTYPE_STRING_DESCRIPTION
,
670 OPENTYPE_STRING_VENDOR_URL
,
671 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
672 OPENTYPE_STRING_LICENSE_INFO_URL
,
673 OPENTYPE_STRING_FAMILY_NAME
,
674 OPENTYPE_STRING_SUBFAMILY_NAME
,
675 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
676 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
677 OPENTYPE_STRING_SAMPLE_TEXT
,
678 OPENTYPE_STRING_FULL_FONTNAME
,
679 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
680 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
687 USHORT numPaletteEntries
;
689 USHORT numColorRecords
;
690 ULONG offsetFirstColorRecord
;
691 USHORT colorRecordIndices
[1];
694 /* for version == 1, this comes after full CPAL_Header_0 */
695 struct CPAL_SubHeader_1
697 ULONG offsetPaletteTypeArray
;
698 ULONG offsetPaletteLabelArray
;
699 ULONG offsetPaletteEntryLabelArray
;
702 struct CPAL_ColorRecord
710 BOOL
is_face_type_supported(DWRITE_FONT_FACE_TYPE type
)
712 return (type
== DWRITE_FONT_FACE_TYPE_CFF
) ||
713 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE
) ||
714 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
) ||
715 (type
== DWRITE_FONT_FACE_TYPE_RAW_CFF
);
718 HRESULT
opentype_analyze_font(IDWriteFontFileStream
*stream
, UINT32
* font_count
, DWRITE_FONT_FILE_TYPE
*file_type
, DWRITE_FONT_FACE_TYPE
*face_type
, BOOL
*supported
)
720 /* TODO: Do font validation */
721 DWRITE_FONT_FACE_TYPE face
;
722 const void *font_data
;
727 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, &font_data
, 0, sizeof(TTC_Header_V1
), &context
);
732 *file_type
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
733 face
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
736 if (DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]) == MS_TTCF_TAG
)
738 const TTC_Header_V1
*header
= font_data
;
739 *font_count
= GET_BE_DWORD(header
->numFonts
);
740 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION
;
741 face
= DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
;
743 else if (GET_BE_DWORD(*(DWORD
*)font_data
) == 0x10000)
746 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE
;
747 face
= DWRITE_FONT_FACE_TYPE_TRUETYPE
;
749 else if (DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]) == MS_OTTO_TAG
)
751 *file_type
= DWRITE_FONT_FILE_TYPE_CFF
;
752 face
= DWRITE_FONT_FACE_TYPE_CFF
;
758 *supported
= is_face_type_supported(face
);
760 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
764 HRESULT
opentype_get_font_table(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE type
, UINT32 font_index
, UINT32 tag
,
765 const void **table_data
, void **table_context
, UINT32
*table_size
, BOOL
*found
)
768 TTC_SFNT_V1
*font_header
= NULL
;
770 TT_TableRecord
*table_record
= NULL
;
771 void *table_record_context
;
772 int table_count
, table_offset
= 0;
775 if (found
) *found
= FALSE
;
776 if (table_size
) *table_size
= 0;
778 if (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
) {
779 const TTC_Header_V1
*ttc_header
;
781 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&ttc_header
, 0, sizeof(*ttc_header
), &ttc_context
);
783 if (font_index
>= GET_BE_DWORD(ttc_header
->numFonts
))
786 table_offset
= GET_BE_DWORD(ttc_header
->OffsetTable
[font_index
]);
787 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&font_header
, table_offset
, sizeof(*font_header
), &sfnt_context
);
789 IDWriteFontFileStream_ReleaseFileFragment(stream
, ttc_context
);
793 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&font_header
, 0, sizeof(*font_header
), &sfnt_context
);
798 table_count
= GET_BE_WORD(font_header
->numTables
);
799 table_offset
+= sizeof(*font_header
);
800 for (i
= 0; i
< table_count
; i
++)
802 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&table_record
, table_offset
, sizeof(*table_record
), &table_record_context
);
805 if (DWRITE_MAKE_OPENTYPE_TAG(table_record
->tag
[0], table_record
->tag
[1], table_record
->tag
[2], table_record
->tag
[3]) == tag
)
807 IDWriteFontFileStream_ReleaseFileFragment(stream
, table_record_context
);
808 table_offset
+= sizeof(*table_record
);
811 IDWriteFontFileStream_ReleaseFileFragment(stream
, sfnt_context
);
812 if (SUCCEEDED(hr
) && i
< table_count
)
814 int offset
= GET_BE_DWORD(table_record
->offset
);
815 int length
= GET_BE_DWORD(table_record
->length
);
816 IDWriteFontFileStream_ReleaseFileFragment(stream
, table_record_context
);
818 if (found
) *found
= TRUE
;
819 if (table_size
) *table_size
= length
;
820 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, table_data
, offset
, length
, table_context
);
830 static UINT32
opentype_cmap_get_unicode_ranges_count(const CMAP_Header
*CMAP_Table
)
835 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
); i
++) {
839 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
842 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
843 type
= GET_BE_WORD(*table
);
844 TRACE("table type %i\n", type
);
848 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
850 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
851 count
+= GET_BE_WORD(format
->segCountX2
)/2;
854 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
856 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
857 count
+= GET_BE_DWORD(format
->nGroups
);
861 FIXME("table type %i unhandled.\n", type
);
868 HRESULT
opentype_cmap_get_unicode_ranges(void *data
, UINT32 max_count
, DWRITE_UNICODE_RANGE
*ranges
, UINT32
*count
)
870 CMAP_Header
*CMAP_Table
= data
;
876 *count
= opentype_cmap_get_unicode_ranges_count(CMAP_Table
);
878 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
) && k
< max_count
; i
++)
884 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
887 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
888 type
= GET_BE_WORD(*table
);
889 TRACE("table type %i\n", type
);
893 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
895 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
896 UINT16 segment_count
= GET_BE_WORD(format
->segCountX2
)/2;
897 UINT16
*startCode
= (WORD
*)((BYTE
*)format
+ sizeof(CMAP_SegmentMapping_0
) + (sizeof(WORD
) * segment_count
));
899 for (j
= 0; j
< segment_count
&& GET_BE_WORD(format
->endCode
[j
]) < 0xffff && k
< max_count
; j
++, k
++) {
900 ranges
[k
].first
= GET_BE_WORD(startCode
[j
]);
901 ranges
[k
].last
= GET_BE_WORD(format
->endCode
[j
]);
905 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
907 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
908 for (j
= 0; j
< GET_BE_DWORD(format
->nGroups
) && k
< max_count
; j
++, k
++) {
909 ranges
[k
].first
= GET_BE_DWORD(format
->groups
[j
].startCharCode
);
910 ranges
[k
].last
= GET_BE_DWORD(format
->groups
[j
].endCharCode
);
915 FIXME("table type %i unhandled.\n", type
);
919 return *count
> max_count
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
922 void opentype_get_font_metrics(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE face_type
, UINT32 face_index
,
923 DWRITE_FONT_METRICS1
*metrics
, DWRITE_CARET_METRICS
*caret
)
925 void *os2_context
, *head_context
, *post_context
, *hhea_context
;
926 const TT_OS2_V2
*tt_os2
;
927 const TT_HEAD
*tt_head
;
928 const TT_POST
*tt_post
;
929 const TT_HHEA
*tt_hhea
;
931 memset(metrics
, 0, sizeof(*metrics
));
933 opentype_get_font_table(stream
, face_type
, face_index
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
934 opentype_get_font_table(stream
, face_type
, face_index
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
935 opentype_get_font_table(stream
, face_type
, face_index
, MS_POST_TAG
, (const void**)&tt_post
, &post_context
, NULL
, NULL
);
936 opentype_get_font_table(stream
, face_type
, face_index
, MS_HHEA_TAG
, (const void**)&tt_hhea
, &hhea_context
, NULL
, NULL
);
939 metrics
->designUnitsPerEm
= GET_BE_WORD(tt_head
->unitsPerEm
);
940 metrics
->glyphBoxLeft
= GET_BE_WORD(tt_head
->xMin
);
941 metrics
->glyphBoxTop
= GET_BE_WORD(tt_head
->yMax
);
942 metrics
->glyphBoxRight
= GET_BE_WORD(tt_head
->xMax
);
943 metrics
->glyphBoxBottom
= GET_BE_WORD(tt_head
->yMin
);
948 caret
->slopeRise
= GET_BE_WORD(tt_hhea
->caretSlopeRise
);
949 caret
->slopeRun
= GET_BE_WORD(tt_hhea
->caretSlopeRun
);
950 caret
->offset
= GET_BE_WORD(tt_hhea
->caretOffset
);
953 caret
->slopeRise
= 0;
960 USHORT version
= GET_BE_WORD(tt_os2
->version
);
962 metrics
->ascent
= GET_BE_WORD(tt_os2
->usWinAscent
);
963 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
964 interpreted as large unsigned value. */
965 metrics
->descent
= abs((SHORT
)GET_BE_WORD(tt_os2
->usWinDescent
));
967 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
969 SHORT descender
= (SHORT
)GET_BE_WORD(tt_hhea
->descender
);
972 linegap
= GET_BE_WORD(tt_hhea
->ascender
) + abs(descender
) + GET_BE_WORD(tt_hhea
->linegap
) -
973 metrics
->ascent
- metrics
->descent
;
974 metrics
->lineGap
= linegap
> 0 ? linegap
: 0;
977 metrics
->strikethroughPosition
= GET_BE_WORD(tt_os2
->yStrikeoutPosition
);
978 metrics
->strikethroughThickness
= GET_BE_WORD(tt_os2
->yStrikeoutSize
);
979 metrics
->subscriptPositionX
= GET_BE_WORD(tt_os2
->ySubscriptXOffset
);
980 /* Y offset is stored as positive offset below baseline */
981 metrics
->subscriptPositionY
= -GET_BE_WORD(tt_os2
->ySubscriptYOffset
);
982 metrics
->subscriptSizeX
= GET_BE_WORD(tt_os2
->ySubscriptXSize
);
983 metrics
->subscriptSizeY
= GET_BE_WORD(tt_os2
->ySubscriptYSize
);
984 metrics
->superscriptPositionX
= GET_BE_WORD(tt_os2
->ySuperscriptXOffset
);
985 metrics
->superscriptPositionY
= GET_BE_WORD(tt_os2
->ySuperscriptYOffset
);
986 metrics
->superscriptSizeX
= GET_BE_WORD(tt_os2
->ySuperscriptXSize
);
987 metrics
->superscriptSizeY
= GET_BE_WORD(tt_os2
->ySuperscriptYSize
);
989 /* version 2 fields */
991 metrics
->capHeight
= GET_BE_WORD(tt_os2
->sCapHeight
);
992 metrics
->xHeight
= GET_BE_WORD(tt_os2
->sxHeight
);
995 /* version 4 fields */
997 if (GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_USE_TYPO_METRICS
) {
998 SHORT descent
= GET_BE_WORD(tt_os2
->sTypoDescender
);
999 metrics
->ascent
= GET_BE_WORD(tt_os2
->sTypoAscender
);
1000 metrics
->descent
= descent
< 0 ? -descent
: 0;
1001 metrics
->lineGap
= GET_BE_WORD(tt_os2
->sTypoLineGap
);
1002 metrics
->hasTypographicMetrics
= TRUE
;
1008 metrics
->underlinePosition
= GET_BE_WORD(tt_post
->underlinePosition
);
1009 metrics
->underlineThickness
= GET_BE_WORD(tt_post
->underlineThickness
);
1012 /* estimate missing metrics */
1013 if (metrics
->xHeight
== 0)
1014 metrics
->xHeight
= metrics
->designUnitsPerEm
/ 2;
1015 if (metrics
->capHeight
== 0)
1016 metrics
->capHeight
= metrics
->designUnitsPerEm
* 7 / 10;
1019 IDWriteFontFileStream_ReleaseFileFragment(stream
, os2_context
);
1021 IDWriteFontFileStream_ReleaseFileFragment(stream
, head_context
);
1023 IDWriteFontFileStream_ReleaseFileFragment(stream
, post_context
);
1025 IDWriteFontFileStream_ReleaseFileFragment(stream
, hhea_context
);
1028 void opentype_get_font_properties(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE type
, UINT32 index
,
1029 struct dwrite_font_props
*props
)
1031 void *os2_context
, *head_context
;
1032 const TT_OS2_V2
*tt_os2
;
1033 const TT_HEAD
*tt_head
;
1035 opentype_get_font_table(stream
, type
, index
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1036 opentype_get_font_table(stream
, type
, index
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
1038 /* default stretch, weight and style to normal */
1039 props
->stretch
= DWRITE_FONT_STRETCH_NORMAL
;
1040 props
->weight
= DWRITE_FONT_WEIGHT_NORMAL
;
1041 props
->style
= DWRITE_FONT_STYLE_NORMAL
;
1042 memset(&props
->panose
, 0, sizeof(props
->panose
));
1044 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1046 USHORT version
= GET_BE_WORD(tt_os2
->version
);
1047 USHORT fsSelection
= GET_BE_WORD(tt_os2
->fsSelection
);
1048 USHORT usWeightClass
= GET_BE_WORD(tt_os2
->usWeightClass
);
1050 if (GET_BE_WORD(tt_os2
->usWidthClass
) <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
1051 props
->stretch
= GET_BE_WORD(tt_os2
->usWidthClass
);
1053 if (usWeightClass
>= 1 && usWeightClass
<= 9)
1054 usWeightClass
*= 100;
1056 if (usWeightClass
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
1057 props
->weight
= DWRITE_FONT_WEIGHT_ULTRA_BLACK
;
1059 props
->weight
= usWeightClass
;
1061 if (version
>= 4 && (fsSelection
& OS2_FSSELECTION_OBLIQUE
))
1062 props
->style
= DWRITE_FONT_STYLE_OBLIQUE
;
1063 else if (fsSelection
& OS2_FSSELECTION_ITALIC
)
1064 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
1065 memcpy(&props
->panose
, &tt_os2
->panose
, sizeof(props
->panose
));
1068 USHORT macStyle
= GET_BE_WORD(tt_head
->macStyle
);
1070 if (macStyle
& TT_HEAD_MACSTYLE_CONDENSED
)
1071 props
->stretch
= DWRITE_FONT_STRETCH_CONDENSED
;
1072 else if (macStyle
& TT_HEAD_MACSTYLE_EXTENDED
)
1073 props
->stretch
= DWRITE_FONT_STRETCH_EXPANDED
;
1075 if (macStyle
& TT_HEAD_MACSTYLE_BOLD
)
1076 props
->weight
= DWRITE_FONT_WEIGHT_BOLD
;
1078 if (macStyle
& TT_HEAD_MACSTYLE_ITALIC
)
1079 props
->style
= DWRITE_FONT_STYLE_ITALIC
;
1082 TRACE("stretch=%d, weight=%d, style %d\n", props
->stretch
, props
->weight
, props
->style
);
1085 IDWriteFontFileStream_ReleaseFileFragment(stream
, os2_context
);
1087 IDWriteFontFileStream_ReleaseFileFragment(stream
, head_context
);
1090 static UINT
get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform
, USHORT encoding
)
1095 case OPENTYPE_PLATFORM_UNICODE
:
1097 case OPENTYPE_PLATFORM_MAC
:
1100 case TT_NAME_MAC_ENCODING_ROMAN
:
1103 case TT_NAME_MAC_ENCODING_JAPANESE
:
1106 case TT_NAME_MAC_ENCODING_TRAD_CHINESE
:
1109 case TT_NAME_MAC_ENCODING_KOREAN
:
1112 case TT_NAME_MAC_ENCODING_ARABIC
:
1115 case TT_NAME_MAC_ENCODING_HEBREW
:
1118 case TT_NAME_MAC_ENCODING_GREEK
:
1121 case TT_NAME_MAC_ENCODING_RUSSIAN
:
1124 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE
:
1127 case TT_NAME_MAC_ENCODING_THAI
:
1131 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1135 case OPENTYPE_PLATFORM_WIN
:
1138 case TT_NAME_WINDOWS_ENCODING_SYMBOL
:
1139 case TT_NAME_WINDOWS_ENCODING_UCS2
:
1141 case TT_NAME_WINDOWS_ENCODING_SJIS
:
1144 case TT_NAME_WINDOWS_ENCODING_PRC
:
1147 case TT_NAME_WINDOWS_ENCODING_BIG5
:
1150 case TT_NAME_WINDOWS_ENCODING_WANSUNG
:
1153 case TT_NAME_WINDOWS_ENCODING_JOHAB
:
1157 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1162 FIXME("unknown platform %d\n", platform
);
1168 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform
, USHORT lang_id
, WCHAR
*locale
, USHORT locale_len
)
1170 static const WCHAR enusW
[] = {'e','n','-','U','S',0};
1173 case OPENTYPE_PLATFORM_MAC
:
1175 const char *locale_name
= NULL
;
1177 if (lang_id
> TT_NAME_MAC_LANGID_AZER_ROMAN
)
1178 ERR("invalid mac lang id %d\n", lang_id
);
1179 else if (!name_mac_langid_to_locale
[lang_id
][0])
1180 FIXME("failed to map mac lang id %d to locale name\n", lang_id
);
1182 locale_name
= name_mac_langid_to_locale
[lang_id
];
1185 MultiByteToWideChar(CP_ACP
, 0, name_mac_langid_to_locale
[lang_id
], -1, locale
, locale_len
);
1187 strcpyW(locale
, enusW
);
1190 case OPENTYPE_PLATFORM_WIN
:
1191 if (!LCIDToLocaleName(MAKELCID(lang_id
, SORT_DEFAULT
), locale
, locale_len
, 0)) {
1192 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id
, SORT_DEFAULT
));
1193 strcpyW(locale
, enusW
);
1197 FIXME("unknown platform %d\n", platform
);
1201 static HRESULT
opentype_get_font_strings_from_id(const void *table_data
, enum OPENTYPE_STRING_ID id
, IDWriteLocalizedStrings
**strings
)
1203 const TT_NAME_V0
*header
;
1204 BYTE
*storage_area
= 0;
1214 hr
= create_localizedstrings(strings
);
1215 if (FAILED(hr
)) return hr
;
1217 header
= table_data
;
1218 format
= GET_BE_WORD(header
->format
);
1225 FIXME("unsupported NAME format %d\n", format
);
1229 storage_area
= (LPBYTE
)table_data
+ GET_BE_WORD(header
->stringOffset
);
1230 count
= GET_BE_WORD(header
->count
);
1233 for (i
= 0; i
< count
; i
++) {
1234 const TT_NameRecord
*record
= &header
->nameRecord
[i
];
1235 USHORT lang_id
, length
, offset
, encoding
, platform
;
1237 if (GET_BE_WORD(record
->nameID
) != id
)
1242 /* Right now only accept unicode and windows encoded fonts */
1243 platform
= GET_BE_WORD(record
->platformID
);
1244 if (platform
!= OPENTYPE_PLATFORM_UNICODE
&&
1245 platform
!= OPENTYPE_PLATFORM_MAC
&&
1246 platform
!= OPENTYPE_PLATFORM_WIN
)
1248 FIXME("platform %i not supported\n", platform
);
1252 /* Skip such entries for now, as it's not clear which locale is implied when
1253 unicode platform is used. Also fonts tend to duplicate those strings as
1254 WIN platform entries. */
1255 if (platform
== OPENTYPE_PLATFORM_UNICODE
)
1258 lang_id
= GET_BE_WORD(record
->languageID
);
1259 length
= GET_BE_WORD(record
->length
);
1260 offset
= GET_BE_WORD(record
->offset
);
1261 encoding
= GET_BE_WORD(record
->encodingID
);
1263 if (lang_id
< 0x8000) {
1264 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
1268 codepage
= get_name_record_codepage(platform
, encoding
);
1269 get_name_record_locale(platform
, lang_id
, locale
, sizeof(locale
)/sizeof(WCHAR
));
1272 DWORD len
= MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, NULL
, 0);
1273 name_string
= heap_alloc(sizeof(WCHAR
) * (len
+1));
1274 MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, name_string
, len
);
1275 name_string
[len
] = 0;
1280 length
/= sizeof(WCHAR
);
1281 name_string
= heap_strdupnW((LPWSTR
)(storage_area
+ offset
), length
);
1282 for (i
= 0; i
< length
; i
++)
1283 name_string
[i
] = GET_BE_WORD(name_string
[i
]);
1286 TRACE("string %s for locale %s found\n", debugstr_w(name_string
), debugstr_w(locale
));
1287 add_localizedstring(*strings
, locale
, name_string
);
1288 heap_free(name_string
);
1291 FIXME("handle NAME format 1\n");
1297 IDWriteLocalizedStrings_Release(*strings
);
1301 return exists
? S_OK
: E_FAIL
;
1304 /* Provides a conversion from DWRITE to OpenType name ids, input id be valid, it's not checked. */
1305 HRESULT
opentype_get_font_info_strings(const void *table_data
, DWRITE_INFORMATIONAL_STRING_ID id
, IDWriteLocalizedStrings
**strings
)
1307 return opentype_get_font_strings_from_id(table_data
, dwriteid_to_opentypeid
[id
], strings
);
1310 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
1311 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
1312 HRESULT
opentype_get_font_familyname(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE facetype
, UINT32 index
,
1313 IDWriteLocalizedStrings
**names
)
1315 const TT_OS2_V2
*tt_os2
;
1316 void *os2_context
, *name_context
;
1317 const void *name_table
;
1320 opentype_get_font_table(stream
, facetype
, index
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1321 opentype_get_font_table(stream
, facetype
, index
, MS_NAME_TAG
, &name_table
, &name_context
, NULL
, NULL
);
1325 /* if Preferred Family doesn't conform to WWS model try WWS name */
1326 if (tt_os2
&& !(GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_WWS
))
1327 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_WWS_FAMILY_NAME
, names
);
1332 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_PREFERRED_FAMILY_NAME
, names
);
1334 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_FAMILY_NAME
, names
);
1337 IDWriteFontFileStream_ReleaseFileFragment(stream
, os2_context
);
1339 IDWriteFontFileStream_ReleaseFileFragment(stream
, name_context
);
1344 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
1345 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
1346 HRESULT
opentype_get_font_facename(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE facetype
, UINT32 index
,
1347 IDWriteLocalizedStrings
**names
)
1349 const TT_OS2_V2
*tt_os2
;
1350 void *os2_context
, *name_context
;
1351 const void *name_table
;
1354 opentype_get_font_table(stream
, facetype
, index
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
1355 opentype_get_font_table(stream
, facetype
, index
, MS_NAME_TAG
, &name_table
, &name_context
, NULL
, NULL
);
1359 /* if Preferred Family doesn't conform to WWS model try WWS name */
1360 if (tt_os2
&& !(GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_WWS
))
1361 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_WWS_SUBFAMILY_NAME
, names
);
1366 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
, names
);
1368 hr
= opentype_get_font_strings_from_id(name_table
, OPENTYPE_STRING_SUBFAMILY_NAME
, names
);
1371 IDWriteFontFileStream_ReleaseFileFragment(stream
, os2_context
);
1373 IDWriteFontFileStream_ReleaseFileFragment(stream
, name_context
);
1378 static inline const OT_Script
*opentype_get_script(const OT_ScriptList
*scriptlist
, UINT32 scripttag
)
1382 for (j
= 0; j
< GET_BE_WORD(scriptlist
->ScriptCount
); j
++) {
1383 const char *tag
= scriptlist
->ScriptRecord
[j
].ScriptTag
;
1384 if (scripttag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1385 return (OT_Script
*)((BYTE
*)scriptlist
+ GET_BE_WORD(scriptlist
->ScriptRecord
[j
].Script
));
1391 static inline const OT_LangSys
*opentype_get_langsys(const OT_Script
*script
, UINT32 languagetag
)
1395 for (j
= 0; j
< GET_BE_WORD(script
->LangSysCount
); j
++) {
1396 const char *tag
= script
->LangSysRecord
[j
].LangSysTag
;
1397 if (languagetag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1398 return (OT_LangSys
*)((BYTE
*)script
+ GET_BE_WORD(script
->LangSysRecord
[j
].LangSys
));
1404 static void opentype_add_font_features(const GPOS_GSUB_Header
*header
, const OT_LangSys
*langsys
,
1405 UINT32 max_tagcount
, UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1407 const OT_FeatureList
*features
= (const OT_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1410 for (j
= 0; j
< GET_BE_WORD(langsys
->FeatureCount
); j
++) {
1411 const OT_FeatureRecord
*feature
= &features
->FeatureRecord
[langsys
->FeatureIndex
[j
]];
1412 const char *tag
= feature
->FeatureTag
;
1414 if (*count
< max_tagcount
)
1415 tags
[*count
] = DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]);
1421 HRESULT
opentype_get_typographic_features(IDWriteFontFace
*fontface
, UINT32 scripttag
, UINT32 languagetag
, UINT32 max_tagcount
,
1422 UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1424 UINT32 tables
[2] = { MS_GSUB_TAG
, MS_GPOS_TAG
};
1429 for (i
= 0; i
< sizeof(tables
)/sizeof(tables
[0]); i
++) {
1430 const OT_ScriptList
*scriptlist
;
1431 const GPOS_GSUB_Header
*header
;
1432 const OT_Script
*script
;
1439 hr
= IDWriteFontFace_TryGetFontTable(fontface
, tables
[i
], &ptr
, &size
, &context
, &exists
);
1446 header
= (const GPOS_GSUB_Header
*)ptr
;
1447 scriptlist
= (const OT_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
1449 script
= opentype_get_script(scriptlist
, scripttag
);
1451 const OT_LangSys
*langsys
= opentype_get_langsys(script
, languagetag
);
1453 opentype_add_font_features(header
, langsys
, max_tagcount
, count
, tags
);
1456 IDWriteFontFace_ReleaseFontTable(fontface
, context
);
1459 return *count
> max_tagcount
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
1462 static const struct VDMX_group
*find_vdmx_group(const struct VDMX_Header
*hdr
)
1464 WORD num_ratios
, i
, group_offset
= 0;
1465 struct VDMX_Ratio
*ratios
= (struct VDMX_Ratio
*)(hdr
+ 1);
1466 BYTE dev_x_ratio
= 1, dev_y_ratio
= 1;
1468 num_ratios
= GET_BE_WORD(hdr
->numRatios
);
1470 for (i
= 0; i
< num_ratios
; i
++) {
1472 if (!ratios
[i
].bCharSet
) continue;
1474 if ((ratios
[i
].xRatio
== 0 && ratios
[i
].yStartRatio
== 0 &&
1475 ratios
[i
].yEndRatio
== 0) ||
1476 (ratios
[i
].xRatio
== dev_x_ratio
&& ratios
[i
].yStartRatio
<= dev_y_ratio
&&
1477 ratios
[i
].yEndRatio
>= dev_y_ratio
))
1479 group_offset
= GET_BE_WORD(*((WORD
*)(ratios
+ num_ratios
) + i
));
1484 return (const struct VDMX_group
*)((BYTE
*)hdr
+ group_offset
);
1488 BOOL
opentype_get_vdmx_size(const void *data
, INT emsize
, UINT16
*ascent
, UINT16
*descent
)
1490 const struct VDMX_Header
*hdr
= (const struct VDMX_Header
*)data
;
1491 const struct VDMX_group
*group
;
1492 const struct VDMX_vTable
*tables
;
1498 group
= find_vdmx_group(hdr
);
1502 recs
= GET_BE_WORD(group
->recs
);
1503 if (emsize
< group
->startsz
|| emsize
>= group
->endsz
) return FALSE
;
1505 tables
= (const struct VDMX_vTable
*)(group
+ 1);
1506 for (i
= 0; i
< recs
; i
++) {
1507 WORD ppem
= GET_BE_WORD(tables
[i
].yPelHeight
);
1508 if (ppem
> emsize
) {
1509 FIXME("interpolate %d\n", emsize
);
1513 if (ppem
== emsize
) {
1514 *ascent
= (SHORT
)GET_BE_WORD(tables
[i
].yMax
);
1515 *descent
= -(SHORT
)GET_BE_WORD(tables
[i
].yMin
);
1522 WORD
opentype_get_gasp_flags(const WORD
*ptr
, UINT32 size
, INT emsize
)
1524 WORD num_recs
, version
;
1530 version
= GET_BE_WORD( *ptr
++ );
1531 num_recs
= GET_BE_WORD( *ptr
++ );
1532 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
)) {
1533 ERR("unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
1537 while (num_recs
--) {
1538 flags
= GET_BE_WORD( *(ptr
+ 1) );
1539 if (emsize
<= GET_BE_WORD( *ptr
)) break;
1547 UINT32
opentype_get_cpal_palettecount(const void *cpal
)
1549 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1550 return header
? GET_BE_WORD(header
->numPalette
) : 0;
1553 UINT32
opentype_get_cpal_paletteentrycount(const void *cpal
)
1555 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1556 return header
? GET_BE_WORD(header
->numPaletteEntries
) : 0;
1559 HRESULT
opentype_get_cpal_entries(const void *cpal
, UINT32 palette
, UINT32 first_entry_index
, UINT32 entry_count
,
1560 DWRITE_COLOR_F
*entries
)
1562 const struct CPAL_Header_0
*header
= (const struct CPAL_Header_0
*)cpal
;
1563 const struct CPAL_ColorRecord
*records
;
1564 UINT32 palettecount
, entrycount
, i
;
1566 if (!header
) return DWRITE_E_NOCOLOR
;
1568 palettecount
= GET_BE_WORD(header
->numPalette
);
1569 if (palette
>= palettecount
)
1570 return DWRITE_E_NOCOLOR
;
1572 entrycount
= GET_BE_WORD(header
->numPaletteEntries
);
1573 if (first_entry_index
+ entry_count
> entrycount
)
1574 return E_INVALIDARG
;
1576 records
= (const struct CPAL_ColorRecord
*)((BYTE
*)cpal
+ GET_BE_DWORD(header
->offsetFirstColorRecord
));
1577 first_entry_index
+= GET_BE_WORD(header
->colorRecordIndices
[palette
]);
1579 for (i
= 0; i
< entry_count
; i
++) {
1580 entries
[i
].r
= records
[first_entry_index
+ i
].red
/ 255.0f
;
1581 entries
[i
].g
= records
[first_entry_index
+ i
].green
/ 255.0f
;
1582 entries
[i
].b
= records
[first_entry_index
+ i
].blue
/ 255.0f
;
1583 entries
[i
].a
= records
[first_entry_index
+ i
].alpha
/ 255.0f
;