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')
34 #ifdef WORDS_BIGENDIAN
35 #define GET_BE_WORD(x) (x)
36 #define GET_BE_DWORD(x) (x)
38 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
39 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)))
68 } CMAP_EncodingRecord
;
73 CMAP_EncodingRecord tables
[1];
80 } CMAP_SegmentedCoverage_group
;
88 CMAP_SegmentedCoverage_group groups
[1];
89 } CMAP_SegmentedCoverage
;
100 } CMAP_SegmentMapping_0
;
102 enum OPENTYPE_CMAP_TABLE_FORMAT
104 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
= 4,
105 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
= 12
108 /* PANOSE is 10 bytes in size, need to pack the structure properly */
109 #include "pshpack2.h"
125 USHORT lowestRecPPEM
;
126 SHORT direction_hint
;
128 SHORT glyphdata_format
;
135 SHORT underlinePosition
;
136 SHORT underlineThickness
;
148 USHORT usWeightClass
;
151 SHORT ySubscriptXSize
;
152 SHORT ySubscriptYSize
;
153 SHORT ySubscriptXOffset
;
154 SHORT ySubscriptYOffset
;
155 SHORT ySuperscriptXSize
;
156 SHORT ySuperscriptYSize
;
157 SHORT ySuperscriptXOffset
;
158 SHORT ySuperscriptYOffset
;
159 SHORT yStrikeoutSize
;
160 SHORT yStrikeoutPosition
;
163 ULONG ulUnicodeRange1
;
164 ULONG ulUnicodeRange2
;
165 ULONG ulUnicodeRange3
;
166 ULONG ulUnicodeRange4
;
169 USHORT usFirstCharIndex
;
170 USHORT usLastCharIndex
;
171 /* According to the Apple spec, original version didn't have the below fields,
172 * version numbers were taken from the OpenType spec.
174 /* version 0 (TrueType 1.5) */
175 USHORT sTypoAscender
;
176 USHORT sTypoDescender
;
180 /* version 1 (TrueType 1.66) */
181 ULONG ulCodePageRange1
;
182 ULONG ulCodePageRange2
;
183 /* version 2 (OpenType 1.2) */
186 USHORT usDefaultChar
;
196 USHORT advanceWidthMax
;
197 SHORT minLeftSideBearing
;
198 SHORT minRightSideBearing
;
200 SHORT caretSlopeRise
;
204 SHORT metricDataFormat
;
205 USHORT numberOfHMetrics
;
210 enum OS2_FSSELECTION
{
211 OS2_FSSELECTION_ITALIC
= 1 << 0,
212 OS2_FSSELECTION_UNDERSCORE
= 1 << 1,
213 OS2_FSSELECTION_NEGATIVE
= 1 << 2,
214 OS2_FSSELECTION_OUTLINED
= 1 << 3,
215 OS2_FSSELECTION_STRIKEOUT
= 1 << 4,
216 OS2_FSSELECTION_BOLD
= 1 << 5,
217 OS2_FSSELECTION_REGULAR
= 1 << 6,
218 OS2_FSSELECTION_USE_TYPO_METRICS
= 1 << 7,
219 OS2_FSSELECTION_WWS
= 1 << 8,
220 OS2_FSSELECTION_OBLIQUE
= 1 << 9
236 TT_NameRecord nameRecord
[1];
239 enum OPENTYPE_PLATFORM_ID
241 OPENTYPE_PLATFORM_UNICODE
= 0,
242 OPENTYPE_PLATFORM_MAC
,
243 OPENTYPE_PLATFORM_ISO
,
244 OPENTYPE_PLATFORM_WIN
,
245 OPENTYPE_PLATFORM_CUSTOM
248 enum TT_NAME_WINDOWS_ENCODING_ID
250 TT_NAME_WINDOWS_ENCODING_SYMBOL
= 0,
251 TT_NAME_WINDOWS_ENCODING_UCS2
,
252 TT_NAME_WINDOWS_ENCODING_SJIS
,
253 TT_NAME_WINDOWS_ENCODING_PRC
,
254 TT_NAME_WINDOWS_ENCODING_BIG5
,
255 TT_NAME_WINDOWS_ENCODING_WANSUNG
,
256 TT_NAME_WINDOWS_ENCODING_JOHAB
,
257 TT_NAME_WINDOWS_ENCODING_RESERVED1
,
258 TT_NAME_WINDOWS_ENCODING_RESERVED2
,
259 TT_NAME_WINDOWS_ENCODING_RESERVED3
,
260 TT_NAME_WINDOWS_ENCODING_UCS4
263 enum TT_NAME_MAC_ENCODING_ID
265 TT_NAME_MAC_ENCODING_ROMAN
= 0,
266 TT_NAME_MAC_ENCODING_JAPANESE
,
267 TT_NAME_MAC_ENCODING_TRAD_CHINESE
,
268 TT_NAME_MAC_ENCODING_KOREAN
,
269 TT_NAME_MAC_ENCODING_ARABIC
,
270 TT_NAME_MAC_ENCODING_HEBREW
,
271 TT_NAME_MAC_ENCODING_GREEK
,
272 TT_NAME_MAC_ENCODING_RUSSIAN
,
273 TT_NAME_MAC_ENCODING_RSYMBOL
,
274 TT_NAME_MAC_ENCODING_DEVANAGARI
,
275 TT_NAME_MAC_ENCODING_GURMUKHI
,
276 TT_NAME_MAC_ENCODING_GUJARATI
,
277 TT_NAME_MAC_ENCODING_ORIYA
,
278 TT_NAME_MAC_ENCODING_BENGALI
,
279 TT_NAME_MAC_ENCODING_TAMIL
,
280 TT_NAME_MAC_ENCODING_TELUGU
,
281 TT_NAME_MAC_ENCODING_KANNADA
,
282 TT_NAME_MAC_ENCODING_MALAYALAM
,
283 TT_NAME_MAC_ENCODING_SINHALESE
,
284 TT_NAME_MAC_ENCODING_BURMESE
,
285 TT_NAME_MAC_ENCODING_KHMER
,
286 TT_NAME_MAC_ENCODING_THAI
,
287 TT_NAME_MAC_ENCODING_LAOTIAN
,
288 TT_NAME_MAC_ENCODING_GEORGIAN
,
289 TT_NAME_MAC_ENCODING_ARMENIAN
,
290 TT_NAME_MAC_ENCODING_SIMPL_CHINESE
,
291 TT_NAME_MAC_ENCODING_TIBETAN
,
292 TT_NAME_MAC_ENCODING_MONGOLIAN
,
293 TT_NAME_MAC_ENCODING_GEEZ
,
294 TT_NAME_MAC_ENCODING_SLAVIC
,
295 TT_NAME_MAC_ENCODING_VIETNAMESE
,
296 TT_NAME_MAC_ENCODING_SINDHI
,
297 TT_NAME_MAC_ENCODING_UNINTERPRETED
300 enum TT_NAME_MAC_LANGUAGE_ID
302 TT_NAME_MAC_LANGID_ENGLISH
= 0,
303 TT_NAME_MAC_LANGID_FRENCH
,
304 TT_NAME_MAC_LANGID_GERMAN
,
305 TT_NAME_MAC_LANGID_ITALIAN
,
306 TT_NAME_MAC_LANGID_DUTCH
,
307 TT_NAME_MAC_LANGID_SWEDISH
,
308 TT_NAME_MAC_LANGID_SPANISH
,
309 TT_NAME_MAC_LANGID_DANISH
,
310 TT_NAME_MAC_LANGID_PORTUGUESE
,
311 TT_NAME_MAC_LANGID_NORWEGIAN
,
312 TT_NAME_MAC_LANGID_HEBREW
,
313 TT_NAME_MAC_LANGID_JAPANESE
,
314 TT_NAME_MAC_LANGID_ARABIC
,
315 TT_NAME_MAC_LANGID_FINNISH
,
316 TT_NAME_MAC_LANGID_GREEK
,
317 TT_NAME_MAC_LANGID_ICELANDIC
,
318 TT_NAME_MAC_LANGID_MALTESE
,
319 TT_NAME_MAC_LANGID_TURKISH
,
320 TT_NAME_MAC_LANGID_CROATIAN
,
321 TT_NAME_MAC_LANGID_TRAD_CHINESE
,
322 TT_NAME_MAC_LANGID_URDU
,
323 TT_NAME_MAC_LANGID_HINDI
,
324 TT_NAME_MAC_LANGID_THAI
,
325 TT_NAME_MAC_LANGID_KOREAN
,
326 TT_NAME_MAC_LANGID_LITHUANIAN
,
327 TT_NAME_MAC_LANGID_POLISH
,
328 TT_NAME_MAC_LANGID_HUNGARIAN
,
329 TT_NAME_MAC_LANGID_ESTONIAN
,
330 TT_NAME_MAC_LANGID_LATVIAN
,
331 TT_NAME_MAC_LANGID_SAMI
,
332 TT_NAME_MAC_LANGID_FAROESE
,
333 TT_NAME_MAC_LANGID_FARSI
,
334 TT_NAME_MAC_LANGID_RUSSIAN
,
335 TT_NAME_MAC_LANGID_SIMPL_CHINESE
,
336 TT_NAME_MAC_LANGID_FLEMISH
,
337 TT_NAME_MAC_LANGID_GAELIC
,
338 TT_NAME_MAC_LANGID_ALBANIAN
,
339 TT_NAME_MAC_LANGID_ROMANIAN
,
340 TT_NAME_MAC_LANGID_CZECH
,
341 TT_NAME_MAC_LANGID_SLOVAK
,
342 TT_NAME_MAC_LANGID_SLOVENIAN
,
343 TT_NAME_MAC_LANGID_YIDDISH
,
344 TT_NAME_MAC_LANGID_SERBIAN
,
345 TT_NAME_MAC_LANGID_MACEDONIAN
,
346 TT_NAME_MAC_LANGID_BULGARIAN
,
347 TT_NAME_MAC_LANGID_UKRAINIAN
,
348 TT_NAME_MAC_LANGID_BYELORUSSIAN
,
349 TT_NAME_MAC_LANGID_UZBEK
,
350 TT_NAME_MAC_LANGID_KAZAKH
,
351 TT_NAME_MAC_LANGID_AZERB_CYR
,
352 TT_NAME_MAC_LANGID_AZERB_ARABIC
,
353 TT_NAME_MAC_LANGID_ARMENIAN
,
354 TT_NAME_MAC_LANGID_GEORGIAN
,
355 TT_NAME_MAC_LANGID_MOLDAVIAN
,
356 TT_NAME_MAC_LANGID_KIRGHIZ
,
357 TT_NAME_MAC_LANGID_TAJIKI
,
358 TT_NAME_MAC_LANGID_TURKMEN
,
359 TT_NAME_MAC_LANGID_MONGOLIAN
,
360 TT_NAME_MAC_LANGID_MONGOLIAN_CYR
,
361 TT_NAME_MAC_LANGID_PASHTO
,
362 TT_NAME_MAC_LANGID_KURDISH
,
363 TT_NAME_MAC_LANGID_KASHMIRI
,
364 TT_NAME_MAC_LANGID_SINDHI
,
365 TT_NAME_MAC_LANGID_TIBETAN
,
366 TT_NAME_MAC_LANGID_NEPALI
,
367 TT_NAME_MAC_LANGID_SANSKRIT
,
368 TT_NAME_MAC_LANGID_MARATHI
,
369 TT_NAME_MAC_LANGID_BENGALI
,
370 TT_NAME_MAC_LANGID_ASSAMESE
,
371 TT_NAME_MAC_LANGID_GUJARATI
,
372 TT_NAME_MAC_LANGID_PUNJABI
,
373 TT_NAME_MAC_LANGID_ORIYA
,
374 TT_NAME_MAC_LANGID_MALAYALAM
,
375 TT_NAME_MAC_LANGID_KANNADA
,
376 TT_NAME_MAC_LANGID_TAMIL
,
377 TT_NAME_MAC_LANGID_TELUGU
,
378 TT_NAME_MAC_LANGID_SINHALESE
,
379 TT_NAME_MAC_LANGID_BURMESE
,
380 TT_NAME_MAC_LANGID_KHMER
,
381 TT_NAME_MAC_LANGID_LAO
,
382 TT_NAME_MAC_LANGID_VIETNAMESE
,
383 TT_NAME_MAC_LANGID_INDONESIAN
,
384 TT_NAME_MAC_LANGID_TAGALONG
,
385 TT_NAME_MAC_LANGID_MALAY_ROMAN
,
386 TT_NAME_MAC_LANGID_MALAY_ARABIC
,
387 TT_NAME_MAC_LANGID_AMHARIC
,
388 TT_NAME_MAC_LANGID_TIGRINYA
,
389 TT_NAME_MAC_LANGID_GALLA
,
390 TT_NAME_MAC_LANGID_SOMALI
,
391 TT_NAME_MAC_LANGID_SWAHILI
,
392 TT_NAME_MAC_LANGID_KINYARWANDA
,
393 TT_NAME_MAC_LANGID_RUNDI
,
394 TT_NAME_MAC_LANGID_NYANJA
,
395 TT_NAME_MAC_LANGID_MALAGASY
,
396 TT_NAME_MAC_LANGID_ESPERANTO
,
397 TT_NAME_MAC_LANGID_WELSH
,
398 TT_NAME_MAC_LANGID_BASQUE
,
399 TT_NAME_MAC_LANGID_CATALAN
,
400 TT_NAME_MAC_LANGID_LATIN
,
401 TT_NAME_MAC_LANGID_QUENCHUA
,
402 TT_NAME_MAC_LANGID_GUARANI
,
403 TT_NAME_MAC_LANGID_AYMARA
,
404 TT_NAME_MAC_LANGID_TATAR
,
405 TT_NAME_MAC_LANGID_UIGHUR
,
406 TT_NAME_MAC_LANGID_DZONGKHA
,
407 TT_NAME_MAC_LANGID_JAVANESE
,
408 TT_NAME_MAC_LANGID_SUNDANESE
,
409 TT_NAME_MAC_LANGID_GALICIAN
,
410 TT_NAME_MAC_LANGID_AFRIKAANS
,
411 TT_NAME_MAC_LANGID_BRETON
,
412 TT_NAME_MAC_LANGID_INUKTITUT
,
413 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC
,
414 TT_NAME_MAC_LANGID_MANX_GAELIC
,
415 TT_NAME_MAC_LANGID_IRISH_GAELIC
,
416 TT_NAME_MAC_LANGID_TONGAN
,
417 TT_NAME_MAC_LANGID_GREEK_POLYTONIC
,
418 TT_NAME_MAC_LANGID_GREENLANDIC
,
419 TT_NAME_MAC_LANGID_AZER_ROMAN
422 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
423 static const char name_mac_langid_to_locale
[][10] = {
544 enum OPENTYPE_STRING_ID
546 OPENTYPE_STRING_COPYRIGHT_NOTICE
= 0,
547 OPENTYPE_STRING_FAMILY_NAME
,
548 OPENTYPE_STRING_SUBFAMILY_NAME
,
549 OPENTYPE_STRING_UNIQUE_IDENTIFIER
,
550 OPENTYPE_STRING_FULL_FONTNAME
,
551 OPENTYPE_STRING_VERSION_STRING
,
552 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
553 OPENTYPE_STRING_TRADEMARK
,
554 OPENTYPE_STRING_MANUFACTURER
,
555 OPENTYPE_STRING_DESIGNER
,
556 OPENTYPE_STRING_DESCRIPTION
,
557 OPENTYPE_STRING_VENDOR_URL
,
558 OPENTYPE_STRING_DESIGNER_URL
,
559 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
560 OPENTYPE_STRING_LICENSE_INFO_URL
,
561 OPENTYPE_STRING_RESERVED_ID15
,
562 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
563 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
564 OPENTYPE_STRING_COMPATIBLE_FULLNAME
,
565 OPENTYPE_STRING_SAMPLE_TEXT
,
566 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
,
567 OPENTYPE_STRING_WWS_FAMILY_NAME
,
568 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
571 static const UINT16 dwriteid_to_opentypeid
[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME
+1] =
573 (UINT16
)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
574 OPENTYPE_STRING_COPYRIGHT_NOTICE
,
575 OPENTYPE_STRING_VERSION_STRING
,
576 OPENTYPE_STRING_TRADEMARK
,
577 OPENTYPE_STRING_MANUFACTURER
,
578 OPENTYPE_STRING_DESIGNER
,
579 OPENTYPE_STRING_DESIGNER_URL
,
580 OPENTYPE_STRING_DESCRIPTION
,
581 OPENTYPE_STRING_VENDOR_URL
,
582 OPENTYPE_STRING_LICENSE_DESCRIPTION
,
583 OPENTYPE_STRING_LICENSE_INFO_URL
,
584 OPENTYPE_STRING_FAMILY_NAME
,
585 OPENTYPE_STRING_SUBFAMILY_NAME
,
586 OPENTYPE_STRING_PREFERRED_FAMILY_NAME
,
587 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME
,
588 OPENTYPE_STRING_SAMPLE_TEXT
,
589 OPENTYPE_STRING_FULL_FONTNAME
,
590 OPENTYPE_STRING_POSTSCRIPT_FONTNAME
,
591 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
594 BOOL
is_face_type_supported(DWRITE_FONT_FACE_TYPE type
)
596 return (type
== DWRITE_FONT_FACE_TYPE_CFF
) ||
597 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE
) ||
598 (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
) ||
599 (type
== DWRITE_FONT_FACE_TYPE_RAW_CFF
);
602 HRESULT
opentype_analyze_font(IDWriteFontFileStream
*stream
, UINT32
* font_count
, DWRITE_FONT_FILE_TYPE
*file_type
, DWRITE_FONT_FACE_TYPE
*face_type
, BOOL
*supported
)
604 /* TODO: Do font validation */
605 DWRITE_FONT_FACE_TYPE face
;
606 const void *font_data
;
611 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, &font_data
, 0, sizeof(TTC_Header_V1
), &context
);
616 *file_type
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
617 face
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
620 if (DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]) == MS_TTCF_TAG
)
622 const TTC_Header_V1
*header
= font_data
;
623 *font_count
= GET_BE_DWORD(header
->numFonts
);
624 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION
;
625 face
= DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
;
627 else if (GET_BE_DWORD(*(DWORD
*)font_data
) == 0x10000)
630 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE
;
631 face
= DWRITE_FONT_FACE_TYPE_TRUETYPE
;
633 else if (DWRITE_MAKE_OPENTYPE_TAG(tag
[0], tag
[1], tag
[2], tag
[3]) == MS_OTTO_TAG
)
635 *file_type
= DWRITE_FONT_FILE_TYPE_CFF
;
636 face
= DWRITE_FONT_FACE_TYPE_CFF
;
642 *supported
= is_face_type_supported(face
);
644 IDWriteFontFileStream_ReleaseFileFragment(stream
, context
);
648 HRESULT
opentype_get_font_table(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE type
, UINT32 font_index
, UINT32 tag
,
649 const void **table_data
, void **table_context
, UINT32
*table_size
, BOOL
*found
)
652 TTC_SFNT_V1
*font_header
= NULL
;
654 TT_TableRecord
*table_record
= NULL
;
655 void *table_record_context
;
656 int table_count
, table_offset
= 0;
659 if (found
) *found
= FALSE
;
660 if (table_size
) *table_size
= 0;
662 if (type
== DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
) {
663 const TTC_Header_V1
*ttc_header
;
665 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&ttc_header
, 0, sizeof(*ttc_header
), &ttc_context
);
667 table_offset
= GET_BE_DWORD(ttc_header
->OffsetTable
[0]);
668 if (font_index
>= GET_BE_DWORD(ttc_header
->numFonts
))
671 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&font_header
, table_offset
, sizeof(*font_header
), &sfnt_context
);
672 IDWriteFontFileStream_ReleaseFileFragment(stream
, ttc_context
);
676 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&font_header
, 0, sizeof(*font_header
), &sfnt_context
);
681 table_count
= GET_BE_WORD(font_header
->numTables
);
682 table_offset
+= sizeof(*font_header
);
683 for (i
= 0; i
< table_count
; i
++)
685 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&table_record
, table_offset
, sizeof(*table_record
), &table_record_context
);
688 if (DWRITE_MAKE_OPENTYPE_TAG(table_record
->tag
[0], table_record
->tag
[1], table_record
->tag
[2], table_record
->tag
[3]) == tag
)
690 IDWriteFontFileStream_ReleaseFileFragment(stream
, table_record_context
);
691 table_offset
+= sizeof(*table_record
);
694 IDWriteFontFileStream_ReleaseFileFragment(stream
, sfnt_context
);
695 if (SUCCEEDED(hr
) && i
< table_count
)
697 int offset
= GET_BE_DWORD(table_record
->offset
);
698 int length
= GET_BE_DWORD(table_record
->length
);
699 IDWriteFontFileStream_ReleaseFileFragment(stream
, table_record_context
);
701 if (found
) *found
= TRUE
;
702 if (table_size
) *table_size
= length
;
703 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, table_data
, offset
, length
, table_context
);
713 static int compare_group(const void *a
, const void* b
)
715 const DWORD
*chr
= a
;
716 const CMAP_SegmentedCoverage_group
*group
= b
;
718 if (*chr
< GET_BE_DWORD(group
->startCharCode
))
720 if (*chr
> GET_BE_DWORD(group
->endCharCode
))
725 static void CMAP4_GetGlyphIndex(CMAP_SegmentMapping_0
* format
, UINT32 utf32c
, UINT16
*pgi
)
732 int segment_count
= GET_BE_WORD(format
->segCountX2
)/2;
733 /* This is correct because of the padding before startCode */
734 startCode
= (WORD
*)((BYTE
*)format
+ sizeof(CMAP_SegmentMapping_0
) + (sizeof(WORD
) * segment_count
));
735 idDelta
= (SHORT
*)(((BYTE
*)startCode
) + (sizeof(WORD
) * segment_count
));
736 idRangeOffset
= (WORD
*)(((BYTE
*)idDelta
) + (sizeof(WORD
) * segment_count
));
739 while(GET_BE_WORD(format
->endCode
[segment
]) < 0xffff)
741 if (utf32c
<= GET_BE_WORD(format
->endCode
[segment
]))
745 if (segment
>= segment_count
)
747 TRACE("Segment %i of %i\n",segment
, segment_count
);
748 if (GET_BE_WORD(startCode
[segment
]) > utf32c
)
750 TRACE("In range %i -> %i\n", GET_BE_WORD(startCode
[segment
]), GET_BE_WORD(format
->endCode
[segment
]));
751 if (GET_BE_WORD(idRangeOffset
[segment
]) == 0)
753 *pgi
= (SHORT
)(GET_BE_WORD(idDelta
[segment
])) + utf32c
;
757 WORD ro
= GET_BE_WORD(idRangeOffset
[segment
])/2;
758 WORD co
= (utf32c
- GET_BE_WORD(startCode
[segment
]));
759 WORD
*index
= (WORD
*)((BYTE
*)&idRangeOffset
[segment
] + (ro
+ co
));
760 *pgi
= GET_BE_WORD(*index
);
764 static void CMAP12_GetGlyphIndex(CMAP_SegmentedCoverage
* format
, UINT32 utf32c
, UINT16
*pgi
)
766 CMAP_SegmentedCoverage_group
*group
;
768 group
= bsearch(&utf32c
, format
->groups
, GET_BE_DWORD(format
->nGroups
),
769 sizeof(CMAP_SegmentedCoverage_group
), compare_group
);
773 DWORD offset
= utf32c
- GET_BE_DWORD(group
->startCharCode
);
774 *pgi
= GET_BE_DWORD(group
->startGlyphID
) + offset
;
778 void opentype_cmap_get_glyphindex(void *data
, UINT32 utf32c
, UINT16
*pgi
)
780 CMAP_Header
*CMAP_Table
= data
;
785 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
); i
++)
790 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
793 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
794 type
= GET_BE_WORD(*table
);
795 TRACE("table type %i\n", type
);
799 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
800 CMAP4_GetGlyphIndex((CMAP_SegmentMapping_0
*) table
, utf32c
, pgi
);
802 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
803 CMAP12_GetGlyphIndex((CMAP_SegmentedCoverage
*) table
, utf32c
, pgi
);
806 TRACE("table type %i unhandled.\n", type
);
813 static UINT32
opentype_cmap_get_unicode_ranges_count(const CMAP_Header
*CMAP_Table
)
818 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
); i
++) {
822 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
825 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
826 type
= GET_BE_WORD(*table
);
827 TRACE("table type %i\n", type
);
831 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
833 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
834 count
+= GET_BE_WORD(format
->segCountX2
)/2;
837 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
839 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
840 count
+= GET_BE_DWORD(format
->nGroups
);
844 FIXME("table type %i unhandled.\n", type
);
851 HRESULT
opentype_cmap_get_unicode_ranges(void *data
, UINT32 max_count
, DWRITE_UNICODE_RANGE
*ranges
, UINT32
*count
)
853 CMAP_Header
*CMAP_Table
= data
;
859 *count
= opentype_cmap_get_unicode_ranges_count(CMAP_Table
);
861 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
) && k
< max_count
; i
++)
867 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
870 table
= (WORD
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
871 type
= GET_BE_WORD(*table
);
872 TRACE("table type %i\n", type
);
876 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING
:
878 CMAP_SegmentMapping_0
*format
= (CMAP_SegmentMapping_0
*)table
;
879 UINT16 segment_count
= GET_BE_WORD(format
->segCountX2
)/2;
880 UINT16
*startCode
= (WORD
*)((BYTE
*)format
+ sizeof(CMAP_SegmentMapping_0
) + (sizeof(WORD
) * segment_count
));
882 for (j
= 0; j
< segment_count
&& GET_BE_WORD(format
->endCode
[j
]) < 0xffff && k
< max_count
; j
++, k
++) {
883 ranges
[k
].first
= GET_BE_WORD(startCode
[j
]);
884 ranges
[k
].last
= GET_BE_WORD(format
->endCode
[j
]);
888 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE
:
890 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)table
;
891 for (j
= 0; j
< GET_BE_DWORD(format
->nGroups
) && k
< max_count
; j
++, k
++) {
892 ranges
[k
].first
= GET_BE_DWORD(format
->groups
[j
].startCharCode
);
893 ranges
[k
].last
= GET_BE_DWORD(format
->groups
[j
].endCharCode
);
898 FIXME("table type %i unhandled.\n", type
);
902 return *count
> max_count
? E_NOT_SUFFICIENT_BUFFER
: S_OK
;
905 void opentype_get_font_metrics(IDWriteFontFileStream
*stream
, DWRITE_FONT_FACE_TYPE face_type
, UINT32 face_index
,
906 DWRITE_FONT_METRICS1
*metrics
)
908 void *os2_context
, *head_context
, *post_context
, *hhea_context
;
909 const TT_OS2_V2
*tt_os2
;
910 const TT_HEAD
*tt_head
;
911 const TT_POST
*tt_post
;
912 const TT_HHEA
*tt_hhea
;
914 memset(metrics
, 0, sizeof(*metrics
));
916 opentype_get_font_table(stream
, face_type
, face_index
, MS_OS2_TAG
, (const void**)&tt_os2
, &os2_context
, NULL
, NULL
);
917 opentype_get_font_table(stream
, face_type
, face_index
, MS_HEAD_TAG
, (const void**)&tt_head
, &head_context
, NULL
, NULL
);
918 opentype_get_font_table(stream
, face_type
, face_index
, MS_POST_TAG
, (const void**)&tt_post
, &post_context
, NULL
, NULL
);
919 opentype_get_font_table(stream
, face_type
, face_index
, MS_HHEA_TAG
, (const void**)&tt_hhea
, &hhea_context
, NULL
, NULL
);
922 metrics
->designUnitsPerEm
= GET_BE_WORD(tt_head
->unitsPerEm
);
923 metrics
->glyphBoxLeft
= GET_BE_WORD(tt_head
->xMin
);
924 metrics
->glyphBoxTop
= GET_BE_WORD(tt_head
->yMax
);
925 metrics
->glyphBoxRight
= GET_BE_WORD(tt_head
->xMax
);
926 metrics
->glyphBoxBottom
= GET_BE_WORD(tt_head
->yMin
);
930 USHORT version
= GET_BE_WORD(tt_os2
->version
);
932 metrics
->ascent
= GET_BE_WORD(tt_os2
->usWinAscent
);
933 metrics
->descent
= GET_BE_WORD(tt_os2
->usWinDescent
);
935 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
937 SHORT descender
= (SHORT
)GET_BE_WORD(tt_hhea
->descender
);
940 linegap
= GET_BE_WORD(tt_hhea
->ascender
) + abs(descender
) + GET_BE_WORD(tt_hhea
->linegap
) -
941 metrics
->ascent
- metrics
->descent
;
942 metrics
->lineGap
= linegap
> 0 ? linegap
: 0;
945 metrics
->strikethroughPosition
= GET_BE_WORD(tt_os2
->yStrikeoutPosition
);
946 metrics
->strikethroughThickness
= GET_BE_WORD(tt_os2
->yStrikeoutSize
);
947 metrics
->subscriptPositionX
= GET_BE_WORD(tt_os2
->ySubscriptXOffset
);
948 /* Y offset is stored as positive offset below baseline */
949 metrics
->subscriptPositionY
= -GET_BE_WORD(tt_os2
->ySubscriptYOffset
);
950 metrics
->subscriptSizeX
= GET_BE_WORD(tt_os2
->ySubscriptXSize
);
951 metrics
->subscriptSizeY
= GET_BE_WORD(tt_os2
->ySubscriptYSize
);
952 metrics
->superscriptPositionX
= GET_BE_WORD(tt_os2
->ySuperscriptXOffset
);
953 metrics
->superscriptPositionY
= GET_BE_WORD(tt_os2
->ySuperscriptYOffset
);
954 metrics
->superscriptSizeX
= GET_BE_WORD(tt_os2
->ySuperscriptXSize
);
955 metrics
->superscriptSizeY
= GET_BE_WORD(tt_os2
->ySuperscriptYSize
);
957 /* version 2 fields */
959 metrics
->capHeight
= GET_BE_WORD(tt_os2
->sCapHeight
);
960 metrics
->xHeight
= GET_BE_WORD(tt_os2
->sxHeight
);
963 /* version 4 fields */
965 if (GET_BE_WORD(tt_os2
->fsSelection
) & OS2_FSSELECTION_USE_TYPO_METRICS
) {
966 SHORT descent
= GET_BE_WORD(tt_os2
->sTypoDescender
);
967 metrics
->ascent
= GET_BE_WORD(tt_os2
->sTypoAscender
);
968 metrics
->descent
= descent
< 0 ? -descent
: 0;
969 metrics
->lineGap
= GET_BE_WORD(tt_os2
->sTypoLineGap
);
970 metrics
->hasTypographicMetrics
= TRUE
;
976 metrics
->underlinePosition
= GET_BE_WORD(tt_post
->underlinePosition
);
977 metrics
->underlineThickness
= GET_BE_WORD(tt_post
->underlineThickness
);
980 /* estimate missing metrics */
981 if (metrics
->xHeight
== 0)
982 metrics
->xHeight
= metrics
->designUnitsPerEm
/ 2;
983 if (metrics
->capHeight
== 0)
984 metrics
->capHeight
= metrics
->designUnitsPerEm
* 7 / 10;
987 IDWriteFontFileStream_ReleaseFileFragment(stream
, os2_context
);
989 IDWriteFontFileStream_ReleaseFileFragment(stream
, head_context
);
991 IDWriteFontFileStream_ReleaseFileFragment(stream
, post_context
);
993 IDWriteFontFileStream_ReleaseFileFragment(stream
, hhea_context
);
996 void opentype_get_font_properties(const void *os2
, const void *head
, DWRITE_FONT_STRETCH
*stretch
, DWRITE_FONT_WEIGHT
*weight
, DWRITE_FONT_STYLE
*style
)
998 TT_OS2_V2
*tt_os2
= (TT_OS2_V2
*)os2
;
999 TT_HEAD
*tt_head
= (TT_HEAD
*)head
;
1001 /* default stretch, weight and style to normal */
1002 *stretch
= DWRITE_FONT_STRETCH_NORMAL
;
1003 *weight
= DWRITE_FONT_WEIGHT_NORMAL
;
1004 *style
= DWRITE_FONT_STYLE_NORMAL
;
1006 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1008 if (GET_BE_WORD(tt_os2
->usWidthClass
) <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
1009 *stretch
= GET_BE_WORD(tt_os2
->usWidthClass
);
1011 *weight
= GET_BE_WORD(tt_os2
->usWeightClass
);
1012 TRACE("stretch=%d, weight=%d\n", *stretch
, *weight
);
1016 USHORT macStyle
= GET_BE_WORD(tt_head
->macStyle
);
1017 if (macStyle
& 0x0002)
1018 *style
= DWRITE_FONT_STYLE_ITALIC
;
1022 static UINT
get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform
, USHORT encoding
)
1027 case OPENTYPE_PLATFORM_UNICODE
:
1029 case OPENTYPE_PLATFORM_MAC
:
1032 case TT_NAME_MAC_ENCODING_ROMAN
:
1035 case TT_NAME_MAC_ENCODING_JAPANESE
:
1038 case TT_NAME_MAC_ENCODING_TRAD_CHINESE
:
1041 case TT_NAME_MAC_ENCODING_KOREAN
:
1044 case TT_NAME_MAC_ENCODING_ARABIC
:
1047 case TT_NAME_MAC_ENCODING_HEBREW
:
1050 case TT_NAME_MAC_ENCODING_GREEK
:
1053 case TT_NAME_MAC_ENCODING_RUSSIAN
:
1056 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE
:
1059 case TT_NAME_MAC_ENCODING_THAI
:
1063 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1067 case OPENTYPE_PLATFORM_WIN
:
1070 case TT_NAME_WINDOWS_ENCODING_SYMBOL
:
1071 case TT_NAME_WINDOWS_ENCODING_UCS2
:
1073 case TT_NAME_WINDOWS_ENCODING_SJIS
:
1076 case TT_NAME_WINDOWS_ENCODING_PRC
:
1079 case TT_NAME_WINDOWS_ENCODING_BIG5
:
1082 case TT_NAME_WINDOWS_ENCODING_WANSUNG
:
1085 case TT_NAME_WINDOWS_ENCODING_JOHAB
:
1089 FIXME("encoding %u not handled, platform %d.\n", encoding
, platform
);
1094 FIXME("unknown platform %d\n", platform
);
1100 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform
, USHORT lang_id
, WCHAR
*locale
, USHORT locale_len
)
1102 static const WCHAR enusW
[] = {'e','n','-','U','S',0};
1105 case OPENTYPE_PLATFORM_MAC
:
1107 const char *locale_name
= NULL
;
1109 if (lang_id
> TT_NAME_MAC_LANGID_AZER_ROMAN
)
1110 ERR("invalid mac lang id %d\n", lang_id
);
1111 else if (!name_mac_langid_to_locale
[lang_id
][0])
1112 FIXME("failed to map mac lang id %d to locale name\n", lang_id
);
1114 locale_name
= name_mac_langid_to_locale
[lang_id
];
1117 MultiByteToWideChar(CP_ACP
, 0, name_mac_langid_to_locale
[lang_id
], -1, locale
, locale_len
);
1119 strcpyW(locale
, enusW
);
1122 case OPENTYPE_PLATFORM_WIN
:
1123 if (!LCIDToLocaleName(MAKELCID(lang_id
, SORT_DEFAULT
), locale
, locale_len
, 0)) {
1124 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id
, SORT_DEFAULT
));
1125 strcpyW(locale
, enusW
);
1129 FIXME("unknown platform %d\n", platform
);
1133 HRESULT
opentype_get_font_strings_from_id(const void *table_data
, DWRITE_INFORMATIONAL_STRING_ID id
, IDWriteLocalizedStrings
**strings
)
1135 const TT_NAME_V0
*header
;
1136 BYTE
*storage_area
= 0;
1146 hr
= create_localizedstrings(strings
);
1147 if (FAILED(hr
)) return hr
;
1149 header
= table_data
;
1150 storage_area
= (LPBYTE
)table_data
+ GET_BE_WORD(header
->stringOffset
);
1151 count
= GET_BE_WORD(header
->count
);
1153 name_id
= dwriteid_to_opentypeid
[id
];
1156 for (i
= 0; i
< count
; i
++) {
1157 const TT_NameRecord
*record
= &header
->nameRecord
[i
];
1158 USHORT lang_id
, length
, offset
, encoding
, platform
;
1160 if (GET_BE_WORD(record
->nameID
) != name_id
)
1165 /* Right now only accept unicode and windows encoded fonts */
1166 platform
= GET_BE_WORD(record
->platformID
);
1167 if (platform
!= OPENTYPE_PLATFORM_UNICODE
&&
1168 platform
!= OPENTYPE_PLATFORM_MAC
&&
1169 platform
!= OPENTYPE_PLATFORM_WIN
)
1171 FIXME("platform %i not supported\n", platform
);
1175 lang_id
= GET_BE_WORD(record
->languageID
);
1176 length
= GET_BE_WORD(record
->length
);
1177 offset
= GET_BE_WORD(record
->offset
);
1178 encoding
= GET_BE_WORD(record
->encodingID
);
1180 if (lang_id
< 0x8000) {
1181 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
1185 codepage
= get_name_record_codepage(platform
, encoding
);
1186 get_name_record_locale(platform
, lang_id
, locale
, sizeof(locale
)/sizeof(WCHAR
));
1189 DWORD len
= MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, NULL
, 0);
1190 name_string
= heap_alloc(sizeof(WCHAR
) * (len
+1));
1191 MultiByteToWideChar(codepage
, 0, (LPSTR
)(storage_area
+ offset
), length
, name_string
, len
);
1192 name_string
[len
] = 0;
1197 length
/= sizeof(WCHAR
);
1198 name_string
= heap_strdupnW((LPWSTR
)(storage_area
+ offset
), length
);
1199 for (i
= 0; i
< length
; i
++)
1200 name_string
[i
] = GET_BE_WORD(name_string
[i
]);
1203 TRACE("string %s for locale %s found\n", debugstr_w(name_string
), debugstr_w(locale
));
1204 add_localizedstring(*strings
, locale
, name_string
);
1205 heap_free(name_string
);
1208 FIXME("handle NAME format 1\n");
1214 IDWriteLocalizedStrings_Release(*strings
);