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"
25 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
27 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
28 #define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
29 #define MS_OTTO_TAG DWRITE_MAKE_OPENTYPE_TAG('O','T','T','O')
30 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
31 #define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
32 #define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f')
33 #define MS_GPOS_TAG DWRITE_MAKE_OPENTYPE_TAG('G','P','O','S')
34 #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B')
36 #ifdef WORDS_BIGENDIAN
37 #define GET_BE_WORD(x) (x)
38 #define GET_BE_DWORD(x) (x)
40 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
41 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)))
70 } CMAP_EncodingRecord
;
75 CMAP_EncodingRecord tables
[1];
82 } CMAP_SegmentedCoverage_group
;
90 CMAP_SegmentedCoverage_group groups
[1];
91 } CMAP_SegmentedCoverage
;
102 } CMAP_SegmentMapping_0
;
104 enum OPENTYPE_CMAP_TABLE_FORMAT
106 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
= 4,
107 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
= 12
110 /* PANOSE is 10 bytes in size, need to pack the structure properly */
111 #include "pshpack2.h"
127 USHORT lowestRecPPEM
;
128 SHORT direction_hint
;
130 SHORT glyphdata_format
;
137 SHORT underlinePosition
;
138 SHORT underlineThickness
;
150 USHORT usWeightClass
;
153 SHORT ySubscriptXSize
;
154 SHORT ySubscriptYSize
;
155 SHORT ySubscriptXOffset
;
156 SHORT ySubscriptYOffset
;
157 SHORT ySuperscriptXSize
;
158 SHORT ySuperscriptYSize
;
159 SHORT ySuperscriptXOffset
;
160 SHORT ySuperscriptYOffset
;
161 SHORT yStrikeoutSize
;
162 SHORT yStrikeoutPosition
;
165 ULONG ulUnicodeRange1
;
166 ULONG ulUnicodeRange2
;
167 ULONG ulUnicodeRange3
;
168 ULONG ulUnicodeRange4
;
171 USHORT usFirstCharIndex
;
172 USHORT usLastCharIndex
;
173 /* According to the Apple spec, original version didn't have the below fields,
174 * version numbers were taken from the OpenType spec.
176 /* version 0 (TrueType 1.5) */
177 USHORT sTypoAscender
;
178 USHORT sTypoDescender
;
182 /* version 1 (TrueType 1.66) */
183 ULONG ulCodePageRange1
;
184 ULONG ulCodePageRange2
;
185 /* version 2 (OpenType 1.2) */
188 USHORT usDefaultChar
;
198 USHORT advanceWidthMax
;
199 SHORT minLeftSideBearing
;
200 SHORT minRightSideBearing
;
202 SHORT caretSlopeRise
;
206 SHORT metricDataFormat
;
207 USHORT numberOfHMetrics
;
212 enum OS2_FSSELECTION
{
213 OS2_FSSELECTION_ITALIC
= 1 << 0,
214 OS2_FSSELECTION_UNDERSCORE
= 1 << 1,
215 OS2_FSSELECTION_NEGATIVE
= 1 << 2,
216 OS2_FSSELECTION_OUTLINED
= 1 << 3,
217 OS2_FSSELECTION_STRIKEOUT
= 1 << 4,
218 OS2_FSSELECTION_BOLD
= 1 << 5,
219 OS2_FSSELECTION_REGULAR
= 1 << 6,
220 OS2_FSSELECTION_USE_TYPO_METRICS
= 1 << 7,
221 OS2_FSSELECTION_WWS
= 1 << 8,
222 OS2_FSSELECTION_OBLIQUE
= 1 << 9
238 TT_NameRecord nameRecord
[1];
248 OT_FeatureRecord FeatureRecord
[1];
252 WORD LookupOrder
; /* Reserved */
253 WORD ReqFeatureIndex
;
255 WORD FeatureIndex
[1];
266 OT_LangSysRecord LangSysRecord
[1];
276 OT_ScriptRecord ScriptRecord
[1];
286 enum OPENTYPE_PLATFORM_ID
288 OPENTYPE_PLATFORM_UNICODE
= 0,
289 OPENTYPE_PLATFORM_MAC
,
290 OPENTYPE_PLATFORM_ISO
,
291 OPENTYPE_PLATFORM_WIN
,
292 OPENTYPE_PLATFORM_CUSTOM
295 enum TT_NAME_WINDOWS_ENCODING_ID
297 TT_NAME_WINDOWS_ENCODING_SYMBOL
= 0,
298 TT_NAME_WINDOWS_ENCODING_UCS2
,
299 TT_NAME_WINDOWS_ENCODING_SJIS
,
300 TT_NAME_WINDOWS_ENCODING_PRC
,
301 TT_NAME_WINDOWS_ENCODING_BIG5
,
302 TT_NAME_WINDOWS_ENCODING_WANSUNG
,
303 TT_NAME_WINDOWS_ENCODING_JOHAB
,
304 TT_NAME_WINDOWS_ENCODING_RESERVED1
,
305 TT_NAME_WINDOWS_ENCODING_RESERVED2
,
306 TT_NAME_WINDOWS_ENCODING_RESERVED3
,
307 TT_NAME_WINDOWS_ENCODING_UCS4
310 enum TT_NAME_MAC_ENCODING_ID
312 TT_NAME_MAC_ENCODING_ROMAN
= 0,
313 TT_NAME_MAC_ENCODING_JAPANESE
,
314 TT_NAME_MAC_ENCODING_TRAD_CHINESE
,
315 TT_NAME_MAC_ENCODING_KOREAN
,
316 TT_NAME_MAC_ENCODING_ARABIC
,
317 TT_NAME_MAC_ENCODING_HEBREW
,
318 TT_NAME_MAC_ENCODING_GREEK
,
319 TT_NAME_MAC_ENCODING_RUSSIAN
,
320 TT_NAME_MAC_ENCODING_RSYMBOL
,
321 TT_NAME_MAC_ENCODING_DEVANAGARI
,
322 TT_NAME_MAC_ENCODING_GURMUKHI
,
323 TT_NAME_MAC_ENCODING_GUJARATI
,
324 TT_NAME_MAC_ENCODING_ORIYA
,
325 TT_NAME_MAC_ENCODING_BENGALI
,
326 TT_NAME_MAC_ENCODING_TAMIL
,
327 TT_NAME_MAC_ENCODING_TELUGU
,
328 TT_NAME_MAC_ENCODING_KANNADA
,
329 TT_NAME_MAC_ENCODING_MALAYALAM
,
330 TT_NAME_MAC_ENCODING_SINHALESE
,
331 TT_NAME_MAC_ENCODING_BURMESE
,
332 TT_NAME_MAC_ENCODING_KHMER
,
333 TT_NAME_MAC_ENCODING_THAI
,
334 TT_NAME_MAC_ENCODING_LAOTIAN
,
335 TT_NAME_MAC_ENCODING_GEORGIAN
,
336 TT_NAME_MAC_ENCODING_ARMENIAN
,
337 TT_NAME_MAC_ENCODING_SIMPL_CHINESE
,
338 TT_NAME_MAC_ENCODING_TIBETAN
,
339 TT_NAME_MAC_ENCODING_MONGOLIAN
,
340 TT_NAME_MAC_ENCODING_GEEZ
,
341 TT_NAME_MAC_ENCODING_SLAVIC
,
342 TT_NAME_MAC_ENCODING_VIETNAMESE
,
343 TT_NAME_MAC_ENCODING_SINDHI
,
344 TT_NAME_MAC_ENCODING_UNINTERPRETED
347 enum TT_NAME_MAC_LANGUAGE_ID
349 TT_NAME_MAC_LANGID_ENGLISH
= 0,
350 TT_NAME_MAC_LANGID_FRENCH
,
351 TT_NAME_MAC_LANGID_GERMAN
,
352 TT_NAME_MAC_LANGID_ITALIAN
,
353 TT_NAME_MAC_LANGID_DUTCH
,
354 TT_NAME_MAC_LANGID_SWEDISH
,
355 TT_NAME_MAC_LANGID_SPANISH
,
356 TT_NAME_MAC_LANGID_DANISH
,
357 TT_NAME_MAC_LANGID_PORTUGUESE
,
358 TT_NAME_MAC_LANGID_NORWEGIAN
,
359 TT_NAME_MAC_LANGID_HEBREW
,
360 TT_NAME_MAC_LANGID_JAPANESE
,
361 TT_NAME_MAC_LANGID_ARABIC
,
362 TT_NAME_MAC_LANGID_FINNISH
,
363 TT_NAME_MAC_LANGID_GREEK
,
364 TT_NAME_MAC_LANGID_ICELANDIC
,
365 TT_NAME_MAC_LANGID_MALTESE
,
366 TT_NAME_MAC_LANGID_TURKISH
,
367 TT_NAME_MAC_LANGID_CROATIAN
,
368 TT_NAME_MAC_LANGID_TRAD_CHINESE
,
369 TT_NAME_MAC_LANGID_URDU
,
370 TT_NAME_MAC_LANGID_HINDI
,
371 TT_NAME_MAC_LANGID_THAI
,
372 TT_NAME_MAC_LANGID_KOREAN
,
373 TT_NAME_MAC_LANGID_LITHUANIAN
,
374 TT_NAME_MAC_LANGID_POLISH
,
375 TT_NAME_MAC_LANGID_HUNGARIAN
,
376 TT_NAME_MAC_LANGID_ESTONIAN
,
377 TT_NAME_MAC_LANGID_LATVIAN
,
378 TT_NAME_MAC_LANGID_SAMI
,
379 TT_NAME_MAC_LANGID_FAROESE
,
380 TT_NAME_MAC_LANGID_FARSI
,
381 TT_NAME_MAC_LANGID_RUSSIAN
,
382 TT_NAME_MAC_LANGID_SIMPL_CHINESE
,
383 TT_NAME_MAC_LANGID_FLEMISH
,
384 TT_NAME_MAC_LANGID_GAELIC
,
385 TT_NAME_MAC_LANGID_ALBANIAN
,
386 TT_NAME_MAC_LANGID_ROMANIAN
,
387 TT_NAME_MAC_LANGID_CZECH
,
388 TT_NAME_MAC_LANGID_SLOVAK
,
389 TT_NAME_MAC_LANGID_SLOVENIAN
,
390 TT_NAME_MAC_LANGID_YIDDISH
,
391 TT_NAME_MAC_LANGID_SERBIAN
,
392 TT_NAME_MAC_LANGID_MACEDONIAN
,
393 TT_NAME_MAC_LANGID_BULGARIAN
,
394 TT_NAME_MAC_LANGID_UKRAINIAN
,
395 TT_NAME_MAC_LANGID_BYELORUSSIAN
,
396 TT_NAME_MAC_LANGID_UZBEK
,
397 TT_NAME_MAC_LANGID_KAZAKH
,
398 TT_NAME_MAC_LANGID_AZERB_CYR
,
399 TT_NAME_MAC_LANGID_AZERB_ARABIC
,
400 TT_NAME_MAC_LANGID_ARMENIAN
,
401 TT_NAME_MAC_LANGID_GEORGIAN
,
402 TT_NAME_MAC_LANGID_MOLDAVIAN
,
403 TT_NAME_MAC_LANGID_KIRGHIZ
,
404 TT_NAME_MAC_LANGID_TAJIKI
,
405 TT_NAME_MAC_LANGID_TURKMEN
,
406 TT_NAME_MAC_LANGID_MONGOLIAN
,
407 TT_NAME_MAC_LANGID_MONGOLIAN_CYR
,
408 TT_NAME_MAC_LANGID_PASHTO
,
409 TT_NAME_MAC_LANGID_KURDISH
,
410 TT_NAME_MAC_LANGID_KASHMIRI
,
411 TT_NAME_MAC_LANGID_SINDHI
,
412 TT_NAME_MAC_LANGID_TIBETAN
,
413 TT_NAME_MAC_LANGID_NEPALI
,
414 TT_NAME_MAC_LANGID_SANSKRIT
,
415 TT_NAME_MAC_LANGID_MARATHI
,
416 TT_NAME_MAC_LANGID_BENGALI
,
417 TT_NAME_MAC_LANGID_ASSAMESE
,
418 TT_NAME_MAC_LANGID_GUJARATI
,
419 TT_NAME_MAC_LANGID_PUNJABI
,
420 TT_NAME_MAC_LANGID_ORIYA
,
421 TT_NAME_MAC_LANGID_MALAYALAM
,
422 TT_NAME_MAC_LANGID_KANNADA
,
423 TT_NAME_MAC_LANGID_TAMIL
,
424 TT_NAME_MAC_LANGID_TELUGU
,
425 TT_NAME_MAC_LANGID_SINHALESE
,
426 TT_NAME_MAC_LANGID_BURMESE
,
427 TT_NAME_MAC_LANGID_KHMER
,
428 TT_NAME_MAC_LANGID_LAO
,
429 TT_NAME_MAC_LANGID_VIETNAMESE
,
430 TT_NAME_MAC_LANGID_INDONESIAN
,
431 TT_NAME_MAC_LANGID_TAGALONG
,
432 TT_NAME_MAC_LANGID_MALAY_ROMAN
,
433 TT_NAME_MAC_LANGID_MALAY_ARABIC
,
434 TT_NAME_MAC_LANGID_AMHARIC
,
435 TT_NAME_MAC_LANGID_TIGRINYA
,
436 TT_NAME_MAC_LANGID_GALLA
,
437 TT_NAME_MAC_LANGID_SOMALI
,
438 TT_NAME_MAC_LANGID_SWAHILI
,
439 TT_NAME_MAC_LANGID_KINYARWANDA
,
440 TT_NAME_MAC_LANGID_RUNDI
,
441 TT_NAME_MAC_LANGID_NYANJA
,
442 TT_NAME_MAC_LANGID_MALAGASY
,
443 TT_NAME_MAC_LANGID_ESPERANTO
,
444 TT_NAME_MAC_LANGID_WELSH
,
445 TT_NAME_MAC_LANGID_BASQUE
,
446 TT_NAME_MAC_LANGID_CATALAN
,
447 TT_NAME_MAC_LANGID_LATIN
,
448 TT_NAME_MAC_LANGID_QUENCHUA
,
449 TT_NAME_MAC_LANGID_GUARANI
,
450 TT_NAME_MAC_LANGID_AYMARA
,
451 TT_NAME_MAC_LANGID_TATAR
,
452 TT_NAME_MAC_LANGID_UIGHUR
,
453 TT_NAME_MAC_LANGID_DZONGKHA
,
454 TT_NAME_MAC_LANGID_JAVANESE
,
455 TT_NAME_MAC_LANGID_SUNDANESE
,
456 TT_NAME_MAC_LANGID_GALICIAN
,
457 TT_NAME_MAC_LANGID_AFRIKAANS
,
458 TT_NAME_MAC_LANGID_BRETON
,
459 TT_NAME_MAC_LANGID_INUKTITUT
,
460 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC
,
461 TT_NAME_MAC_LANGID_MANX_GAELIC
,
462 TT_NAME_MAC_LANGID_IRISH_GAELIC
,
463 TT_NAME_MAC_LANGID_TONGAN
,
464 TT_NAME_MAC_LANGID_GREEK_POLYTONIC
,
465 TT_NAME_MAC_LANGID_GREENLANDIC
,
466 TT_NAME_MAC_LANGID_AZER_ROMAN
469 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
470 static const char name_mac_langid_to_locale
[][10] = {
591 enum OPENTYPE_STRING_ID
593 OPENTYPE_STRING_COPYRIGHT_NOTICE
= 0,
594 OPENTYPE_STRING_FAMILY_NAME
,
595 OPENTYPE_STRING_SUBFAMILY_NAME
,
596 OPENTYPE_STRING_UNIQUE_IDENTIFIER
,
597 OPENTYPE_STRING_FULL_FONTNAME
,
598 OPENTYPE_STRING_VERSION_STRING
,
599 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
600 OPENTYPE_STRING_TRADEMARK
,
601 OPENTYPE_STRING_MANUFACTURER
,
602 OPENTYPE_STRING_DESIGNER
,
603 OPENTYPE_STRING_DESCRIPTION
,
604 OPENTYPE_STRING_VENDOR_URL
,
605 OPENTYPE_STRING_DESIGNER_URL
,
606 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
607 OPENTYPE_STRING_LICENSE_INFO_URL
,
608 OPENTYPE_STRING_RESERVED_ID15
,
609 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
610 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
611 OPENTYPE_STRING_COMPATIBLE_FULLNAME
,
612 OPENTYPE_STRING_SAMPLE_TEXT
,
613 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
614 OPENTYPE_STRING_WWS_FAMILY_NAME
,
615 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
618 static const UINT16 dwriteid_to_opentypeid
[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME
+1] =
620 (UINT16
)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
621 OPENTYPE_STRING_COPYRIGHT_NOTICE
,
622 OPENTYPE_STRING_VERSION_STRING
,
623 OPENTYPE_STRING_TRADEMARK
,
624 OPENTYPE_STRING_MANUFACTURER
,
625 OPENTYPE_STRING_DESIGNER
,
626 OPENTYPE_STRING_DESIGNER_URL
,
627 OPENTYPE_STRING_DESCRIPTION
,
628 OPENTYPE_STRING_VENDOR_URL
,
629 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
630 OPENTYPE_STRING_LICENSE_INFO_URL
,
631 OPENTYPE_STRING_FAMILY_NAME
,
632 OPENTYPE_STRING_SUBFAMILY_NAME
,
633 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
634 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
635 OPENTYPE_STRING_SAMPLE_TEXT
,
636 OPENTYPE_STRING_FULL_FONTNAME
,
637 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
638 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
641 BOOL
is_face_type_supported(DWRITE_FONT_FACE_TYPE type
)
643 return (type
== DWRITE_FONT_FACE_TYPE_CFF
) ||
644 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE
) ||
645 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
) ||
646 (type
== DWRITE_FONT_FACE_TYPE_RAW_CFF
);
649 HRESULT
opentype_analyze_font(IDWriteFontFileStream
*stream
, UINT32
* font_count
, DWRITE_FONT_FILE_TYPE
*file_type
, DWRITE_FONT_FACE_TYPE
*face_type
, BOOL
*supported
)
651 /* TODO: Do font validation */
652 DWRITE_FONT_FACE_TYPE face
;
653 const void *font_data
;
658 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, &font_data
, 0, sizeof(TTC_Header_V1
), &context
);
663 *file_type
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
664 face
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
667 if (DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]) == MS_TTCF_TAG
)
669 const TTC_Header_V1
*header
= font_data
;
670 *font_count
= GET_BE_DWORD(header
->numFonts
);
671 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION
;
672 face
= DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
;
674 else if (GET_BE_DWORD(*(DWORD
*)font_data
) == 0x10000)
677 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE
;
678 face
= DWRITE_FONT_FACE_TYPE_TRUETYPE
;
680 else if (DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]) == MS_OTTO_TAG
)
682 *file_type
= DWRITE_FONT_FILE_TYPE_CFF
;
683 face
= DWRITE_FONT_FACE_TYPE_CFF
;
689 *supported
= is_face_type_supported(face
);
691 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
695 HRESULT
opentype_get_font_table(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE type
, UINT32 font_index
, UINT32 tag
,
696 const void **table_data
, void **table_context
, UINT32
*table_size
, BOOL
*found
)
699 TTC_SFNT_V1
*font_header
= NULL
;
701 TT_TableRecord
*table_record
= NULL
;
702 void *table_record_context
;
703 int table_count
, table_offset
= 0;
706 if (found
) *found
= FALSE
;
707 if (table_size
) *table_size
= 0;
709 if (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
) {
710 const TTC_Header_V1
*ttc_header
;
712 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&ttc_header
, 0, sizeof(*ttc_header
), &ttc_context
);
714 table_offset
= GET_BE_DWORD(ttc_header
->OffsetTable
[0]);
715 if (font_index
>= GET_BE_DWORD(ttc_header
->numFonts
))
718 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&font_header
, table_offset
, sizeof(*font_header
), &sfnt_context
);
719 IDWriteFontFileStream_ReleaseFileFragment(stream
, ttc_context
);
723 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&font_header
, 0, sizeof(*font_header
), &sfnt_context
);
728 table_count
= GET_BE_WORD(font_header
->numTables
);
729 table_offset
+= sizeof(*font_header
);
730 for (i
= 0; i
< table_count
; i
++)
732 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&table_record
, table_offset
, sizeof(*table_record
), &table_record_context
);
735 if (DWRITE_MAKE_OPENTYPE_TAG(table_record
->tag
[0], table_record
->tag
[1], table_record
->tag
[2], table_record
->tag
[3]) == tag
)
737 IDWriteFontFileStream_ReleaseFileFragment(stream
, table_record_context
);
738 table_offset
+= sizeof(*table_record
);
741 IDWriteFontFileStream_ReleaseFileFragment(stream
, sfnt_context
);
742 if (SUCCEEDED(hr
) && i
< table_count
)
744 int offset
= GET_BE_DWORD(table_record
->offset
);
745 int length
= GET_BE_DWORD(table_record
->length
);
746 IDWriteFontFileStream_ReleaseFileFragment(stream
, table_record_context
);
748 if (found
) *found
= TRUE
;
749 if (table_size
) *table_size
= length
;
750 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, table_data
, offset
, length
, table_context
);
760 static UINT32
opentype_cmap_get_unicode_ranges_count(const CMAP_Header
*CMAP_Table
)
765 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
); i
++) {
769 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
772 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
773 type
= GET_BE_WORD(*table
);
774 TRACE("table type %i\n", type
);
778 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
780 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
781 count
+= GET_BE_WORD(format
->segCountX2
)/2;
784 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
786 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
787 count
+= GET_BE_DWORD(format
->nGroups
);
791 FIXME("table type %i unhandled.\n", type
);
798 HRESULT
opentype_cmap_get_unicode_ranges(void *data
, UINT32 max_count
, DWRITE_UNICODE_RANGE
*ranges
, UINT32
*count
)
800 CMAP_Header
*CMAP_Table
= data
;
806 *count
= opentype_cmap_get_unicode_ranges_count(CMAP_Table
);
808 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
) && k
< max_count
; i
++)
814 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
817 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
818 type
= GET_BE_WORD(*table
);
819 TRACE("table type %i\n", type
);
823 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
825 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
826 UINT16 segment_count
= GET_BE_WORD(format
->segCountX2
)/2;
827 UINT16
*startCode
= (WORD
*)((BYTE
*)format
+ sizeof(CMAP_SegmentMapping_0
) + (sizeof(WORD
) * segment_count
));
829 for (j
= 0; j
< segment_count
&& GET_BE_WORD(format
->endCode
[j
]) < 0xffff && k
< max_count
; j
++, k
++) {
830 ranges
[k
].first
= GET_BE_WORD(startCode
[j
]);
831 ranges
[k
].last
= GET_BE_WORD(format
->endCode
[j
]);
835 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
837 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
838 for (j
= 0; j
< GET_BE_DWORD(format
->nGroups
) && k
< max_count
; j
++, k
++) {
839 ranges
[k
].first
= GET_BE_DWORD(format
->groups
[j
].startCharCode
);
840 ranges
[k
].last
= GET_BE_DWORD(format
->groups
[j
].endCharCode
);
845 FIXME("table type %i unhandled.\n", type
);
849 return *count
> max_count
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
852 void opentype_get_font_metrics(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE face_type
, UINT32 face_index
,
853 DWRITE_FONT_METRICS1
*metrics
, DWRITE_CARET_METRICS
*caret
)
855 void *os2_context
, *head_context
, *post_context
, *hhea_context
;
856 const TT_OS2_V2
*tt_os2
;
857 const TT_HEAD
*tt_head
;
858 const TT_POST
*tt_post
;
859 const TT_HHEA
*tt_hhea
;
861 memset(metrics
, 0, sizeof(*metrics
));
863 opentype_get_font_table(stream
, face_type
, face_index
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
864 opentype_get_font_table(stream
, face_type
, face_index
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
865 opentype_get_font_table(stream
, face_type
, face_index
, MS_POST_TAG
, (const void**)&tt_post
, &post_context
, NULL
, NULL
);
866 opentype_get_font_table(stream
, face_type
, face_index
, MS_HHEA_TAG
, (const void**)&tt_hhea
, &hhea_context
, NULL
, NULL
);
869 metrics
->designUnitsPerEm
= GET_BE_WORD(tt_head
->unitsPerEm
);
870 metrics
->glyphBoxLeft
= GET_BE_WORD(tt_head
->xMin
);
871 metrics
->glyphBoxTop
= GET_BE_WORD(tt_head
->yMax
);
872 metrics
->glyphBoxRight
= GET_BE_WORD(tt_head
->xMax
);
873 metrics
->glyphBoxBottom
= GET_BE_WORD(tt_head
->yMin
);
878 caret
->slopeRise
= GET_BE_WORD(tt_hhea
->caretSlopeRise
);
879 caret
->slopeRun
= GET_BE_WORD(tt_hhea
->caretSlopeRun
);
880 caret
->offset
= GET_BE_WORD(tt_hhea
->caretOffset
);
883 caret
->slopeRise
= 0;
890 USHORT version
= GET_BE_WORD(tt_os2
->version
);
892 metrics
->ascent
= GET_BE_WORD(tt_os2
->usWinAscent
);
893 metrics
->descent
= GET_BE_WORD(tt_os2
->usWinDescent
);
895 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
897 SHORT descender
= (SHORT
)GET_BE_WORD(tt_hhea
->descender
);
900 linegap
= GET_BE_WORD(tt_hhea
->ascender
) + abs(descender
) + GET_BE_WORD(tt_hhea
->linegap
) -
901 metrics
->ascent
- metrics
->descent
;
902 metrics
->lineGap
= linegap
> 0 ? linegap
: 0;
905 metrics
->strikethroughPosition
= GET_BE_WORD(tt_os2
->yStrikeoutPosition
);
906 metrics
->strikethroughThickness
= GET_BE_WORD(tt_os2
->yStrikeoutSize
);
907 metrics
->subscriptPositionX
= GET_BE_WORD(tt_os2
->ySubscriptXOffset
);
908 /* Y offset is stored as positive offset below baseline */
909 metrics
->subscriptPositionY
= -GET_BE_WORD(tt_os2
->ySubscriptYOffset
);
910 metrics
->subscriptSizeX
= GET_BE_WORD(tt_os2
->ySubscriptXSize
);
911 metrics
->subscriptSizeY
= GET_BE_WORD(tt_os2
->ySubscriptYSize
);
912 metrics
->superscriptPositionX
= GET_BE_WORD(tt_os2
->ySuperscriptXOffset
);
913 metrics
->superscriptPositionY
= GET_BE_WORD(tt_os2
->ySuperscriptYOffset
);
914 metrics
->superscriptSizeX
= GET_BE_WORD(tt_os2
->ySuperscriptXSize
);
915 metrics
->superscriptSizeY
= GET_BE_WORD(tt_os2
->ySuperscriptYSize
);
917 /* version 2 fields */
919 metrics
->capHeight
= GET_BE_WORD(tt_os2
->sCapHeight
);
920 metrics
->xHeight
= GET_BE_WORD(tt_os2
->sxHeight
);
923 /* version 4 fields */
925 if (GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_USE_TYPO_METRICS
) {
926 SHORT descent
= GET_BE_WORD(tt_os2
->sTypoDescender
);
927 metrics
->ascent
= GET_BE_WORD(tt_os2
->sTypoAscender
);
928 metrics
->descent
= descent
< 0 ? -descent
: 0;
929 metrics
->lineGap
= GET_BE_WORD(tt_os2
->sTypoLineGap
);
930 metrics
->hasTypographicMetrics
= TRUE
;
936 metrics
->underlinePosition
= GET_BE_WORD(tt_post
->underlinePosition
);
937 metrics
->underlineThickness
= GET_BE_WORD(tt_post
->underlineThickness
);
940 /* estimate missing metrics */
941 if (metrics
->xHeight
== 0)
942 metrics
->xHeight
= metrics
->designUnitsPerEm
/ 2;
943 if (metrics
->capHeight
== 0)
944 metrics
->capHeight
= metrics
->designUnitsPerEm
* 7 / 10;
947 IDWriteFontFileStream_ReleaseFileFragment(stream
, os2_context
);
949 IDWriteFontFileStream_ReleaseFileFragment(stream
, head_context
);
951 IDWriteFontFileStream_ReleaseFileFragment(stream
, post_context
);
953 IDWriteFontFileStream_ReleaseFileFragment(stream
, hhea_context
);
956 void opentype_get_font_properties(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE type
, UINT32 index
,
957 DWRITE_FONT_STRETCH
*stretch
, DWRITE_FONT_WEIGHT
*weight
, DWRITE_FONT_STYLE
*style
)
959 void *os2_context
, *head_context
;
960 const TT_OS2_V2
*tt_os2
;
961 const TT_HEAD
*tt_head
;
963 opentype_get_font_table(stream
, type
, index
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
964 opentype_get_font_table(stream
, type
, index
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
966 /* default stretch, weight and style to normal */
967 *stretch
= DWRITE_FONT_STRETCH_NORMAL
;
968 *weight
= DWRITE_FONT_WEIGHT_NORMAL
;
969 *style
= DWRITE_FONT_STYLE_NORMAL
;
971 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
973 if (GET_BE_WORD(tt_os2
->usWidthClass
) <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
974 *stretch
= GET_BE_WORD(tt_os2
->usWidthClass
);
976 *weight
= GET_BE_WORD(tt_os2
->usWeightClass
);
977 TRACE("stretch=%d, weight=%d\n", *stretch
, *weight
);
981 USHORT macStyle
= GET_BE_WORD(tt_head
->macStyle
);
982 if (macStyle
& 0x0002)
983 *style
= DWRITE_FONT_STYLE_ITALIC
;
987 IDWriteFontFileStream_ReleaseFileFragment(stream
, os2_context
);
989 IDWriteFontFileStream_ReleaseFileFragment(stream
, head_context
);
992 static UINT
get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform
, USHORT encoding
)
997 case OPENTYPE_PLATFORM_UNICODE
:
999 case OPENTYPE_PLATFORM_MAC
:
1002 case TT_NAME_MAC_ENCODING_ROMAN
:
1005 case TT_NAME_MAC_ENCODING_JAPANESE
:
1008 case TT_NAME_MAC_ENCODING_TRAD_CHINESE
:
1011 case TT_NAME_MAC_ENCODING_KOREAN
:
1014 case TT_NAME_MAC_ENCODING_ARABIC
:
1017 case TT_NAME_MAC_ENCODING_HEBREW
:
1020 case TT_NAME_MAC_ENCODING_GREEK
:
1023 case TT_NAME_MAC_ENCODING_RUSSIAN
:
1026 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE
:
1029 case TT_NAME_MAC_ENCODING_THAI
:
1033 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1037 case OPENTYPE_PLATFORM_WIN
:
1040 case TT_NAME_WINDOWS_ENCODING_SYMBOL
:
1041 case TT_NAME_WINDOWS_ENCODING_UCS2
:
1043 case TT_NAME_WINDOWS_ENCODING_SJIS
:
1046 case TT_NAME_WINDOWS_ENCODING_PRC
:
1049 case TT_NAME_WINDOWS_ENCODING_BIG5
:
1052 case TT_NAME_WINDOWS_ENCODING_WANSUNG
:
1055 case TT_NAME_WINDOWS_ENCODING_JOHAB
:
1059 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1064 FIXME("unknown platform %d\n", platform
);
1070 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform
, USHORT lang_id
, WCHAR
*locale
, USHORT locale_len
)
1072 static const WCHAR enusW
[] = {'e','n','-','U','S',0};
1075 case OPENTYPE_PLATFORM_MAC
:
1077 const char *locale_name
= NULL
;
1079 if (lang_id
> TT_NAME_MAC_LANGID_AZER_ROMAN
)
1080 ERR("invalid mac lang id %d\n", lang_id
);
1081 else if (!name_mac_langid_to_locale
[lang_id
][0])
1082 FIXME("failed to map mac lang id %d to locale name\n", lang_id
);
1084 locale_name
= name_mac_langid_to_locale
[lang_id
];
1087 MultiByteToWideChar(CP_ACP
, 0, name_mac_langid_to_locale
[lang_id
], -1, locale
, locale_len
);
1089 strcpyW(locale
, enusW
);
1092 case OPENTYPE_PLATFORM_WIN
:
1093 if (!LCIDToLocaleName(MAKELCID(lang_id
, SORT_DEFAULT
), locale
, locale_len
, 0)) {
1094 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id
, SORT_DEFAULT
));
1095 strcpyW(locale
, enusW
);
1099 FIXME("unknown platform %d\n", platform
);
1103 HRESULT
opentype_get_font_strings_from_id(const void *table_data
, DWRITE_INFORMATIONAL_STRING_ID id
, IDWriteLocalizedStrings
**strings
)
1105 const TT_NAME_V0
*header
;
1106 BYTE
*storage_area
= 0;
1116 hr
= create_localizedstrings(strings
);
1117 if (FAILED(hr
)) return hr
;
1119 header
= table_data
;
1121 switch (header
->format
) {
1125 FIXME("unsupported NAME format %d\n", header
->format
);
1128 storage_area
= (LPBYTE
)table_data
+ GET_BE_WORD(header
->stringOffset
);
1129 count
= GET_BE_WORD(header
->count
);
1131 name_id
= dwriteid_to_opentypeid
[id
];
1134 for (i
= 0; i
< count
; i
++) {
1135 const TT_NameRecord
*record
= &header
->nameRecord
[i
];
1136 USHORT lang_id
, length
, offset
, encoding
, platform
;
1138 if (GET_BE_WORD(record
->nameID
) != name_id
)
1143 /* Right now only accept unicode and windows encoded fonts */
1144 platform
= GET_BE_WORD(record
->platformID
);
1145 if (platform
!= OPENTYPE_PLATFORM_UNICODE
&&
1146 platform
!= OPENTYPE_PLATFORM_MAC
&&
1147 platform
!= OPENTYPE_PLATFORM_WIN
)
1149 FIXME("platform %i not supported\n", platform
);
1153 /* Skip such entries for now, as it's not clear which locale is implied when
1154 unicode platform is used. Also fonts tend to duplicate those strings as
1155 WIN platform entries. */
1156 if (platform
== OPENTYPE_PLATFORM_UNICODE
)
1159 lang_id
= GET_BE_WORD(record
->languageID
);
1160 length
= GET_BE_WORD(record
->length
);
1161 offset
= GET_BE_WORD(record
->offset
);
1162 encoding
= GET_BE_WORD(record
->encodingID
);
1164 if (lang_id
< 0x8000) {
1165 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
1169 codepage
= get_name_record_codepage(platform
, encoding
);
1170 get_name_record_locale(platform
, lang_id
, locale
, sizeof(locale
)/sizeof(WCHAR
));
1173 DWORD len
= MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, NULL
, 0);
1174 name_string
= heap_alloc(sizeof(WCHAR
) * (len
+1));
1175 MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, name_string
, len
);
1176 name_string
[len
] = 0;
1181 length
/= sizeof(WCHAR
);
1182 name_string
= heap_strdupnW((LPWSTR
)(storage_area
+ offset
), length
);
1183 for (i
= 0; i
< length
; i
++)
1184 name_string
[i
] = GET_BE_WORD(name_string
[i
]);
1187 TRACE("string %s for locale %s found\n", debugstr_w(name_string
), debugstr_w(locale
));
1188 add_localizedstring(*strings
, locale
, name_string
);
1189 heap_free(name_string
);
1192 FIXME("handle NAME format 1\n");
1198 IDWriteLocalizedStrings_Release(*strings
);
1205 static inline const OT_Script
*opentype_get_script(const OT_ScriptList
*scriptlist
, UINT32 scripttag
)
1209 for (j
= 0; j
< GET_BE_WORD(scriptlist
->ScriptCount
); j
++) {
1210 const char *tag
= scriptlist
->ScriptRecord
[j
].ScriptTag
;
1211 if (scripttag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1212 return (OT_Script
*)((BYTE
*)scriptlist
+ GET_BE_WORD(scriptlist
->ScriptRecord
[j
].Script
));
1218 static inline const OT_LangSys
*opentype_get_langsys(const OT_Script
*script
, UINT32 languagetag
)
1222 for (j
= 0; j
< GET_BE_WORD(script
->LangSysCount
); j
++) {
1223 const char *tag
= script
->LangSysRecord
[j
].LangSysTag
;
1224 if (languagetag
== DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]))
1225 return (OT_LangSys
*)((BYTE
*)script
+ GET_BE_WORD(script
->LangSysRecord
[j
].LangSys
));
1231 static void opentype_add_font_features(const GPOS_GSUB_Header
*header
, const OT_LangSys
*langsys
,
1232 UINT32 max_tagcount
, UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1234 const OT_FeatureList
*features
= (const OT_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1237 for (j
= 0; j
< GET_BE_WORD(langsys
->FeatureCount
); j
++) {
1238 const OT_FeatureRecord
*feature
= &features
->FeatureRecord
[langsys
->FeatureIndex
[j
]];
1239 const char *tag
= feature
->FeatureTag
;
1241 if (*count
< max_tagcount
)
1242 tags
[*count
] = DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]);
1248 HRESULT
opentype_get_typographic_features(IDWriteFontFace
*fontface
, UINT32 scripttag
, UINT32 languagetag
, UINT32 max_tagcount
,
1249 UINT32
*count
, DWRITE_FONT_FEATURE_TAG
*tags
)
1251 UINT32 tables
[2] = { MS_GSUB_TAG
, MS_GPOS_TAG
};
1256 for (i
= 0; i
< sizeof(tables
)/sizeof(tables
[0]); i
++) {
1257 const OT_ScriptList
*scriptlist
;
1258 const GPOS_GSUB_Header
*header
;
1259 const OT_Script
*script
;
1266 hr
= IDWriteFontFace_TryGetFontTable(fontface
, tables
[i
], &ptr
, &size
, &context
, &exists
);
1273 header
= (const GPOS_GSUB_Header
*)ptr
;
1274 scriptlist
= (const OT_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
1276 script
= opentype_get_script(scriptlist
, scripttag
);
1278 const OT_LangSys
*langsys
= opentype_get_langsys(script
, languagetag
);
1280 opentype_add_font_features(header
, langsys
, max_tagcount
, count
, tags
);
1283 IDWriteFontFace_ReleaseFontTable(fontface
, context
);
1286 return *count
> max_tagcount
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;