dwrite: Respect typographic metrics when font instructs us to.
[wine.git] / dlls / dwrite / opentype.c
blob28923c5dce0672124937081121271ce214555ffb
1 /*
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
21 #define COBJMACROS
23 #include "dwrite_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
27 #define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f')
28 #define MS_OTTO_TAG DWRITE_MAKE_OPENTYPE_TAG('O','T','T','O')
30 #ifdef WORDS_BIGENDIAN
31 #define GET_BE_WORD(x) (x)
32 #define GET_BE_DWORD(x) (x)
33 #else
34 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
35 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)))
36 #endif
38 typedef struct {
39 CHAR TTCTag[4];
40 DWORD Version;
41 DWORD numFonts;
42 DWORD OffsetTable[1];
43 } TTC_Header_V1;
45 typedef struct {
46 DWORD version;
47 WORD numTables;
48 WORD searchRange;
49 WORD entrySelector;
50 WORD rangeShift;
51 } TTC_SFNT_V1;
53 typedef struct {
54 CHAR tag[4];
55 DWORD checkSum;
56 DWORD offset;
57 DWORD length;
58 } TT_TableRecord;
60 typedef struct {
61 WORD platformID;
62 WORD encodingID;
63 DWORD offset;
64 } CMAP_EncodingRecord;
66 typedef struct {
67 WORD version;
68 WORD numTables;
69 CMAP_EncodingRecord tables[1];
70 } CMAP_Header;
72 typedef struct {
73 DWORD startCharCode;
74 DWORD endCharCode;
75 DWORD startGlyphID;
76 } CMAP_SegmentedCoverage_group;
78 typedef struct {
79 WORD format;
80 WORD reserved;
81 DWORD length;
82 DWORD language;
83 DWORD nGroups;
84 CMAP_SegmentedCoverage_group groups[1];
85 } CMAP_SegmentedCoverage;
87 typedef struct {
88 WORD format;
89 WORD length;
90 WORD language;
91 WORD segCountX2;
92 WORD searchRange;
93 WORD entrySelector;
94 WORD rangeShift;
95 WORD endCode[1];
96 } CMAP_SegmentMapping_0;
98 enum OPENTYPE_CMAP_TABLE_FORMAT
100 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING = 4,
101 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE = 12
104 /* PANOSE is 10 bytes in size, need to pack the structure properly */
105 #include "pshpack2.h"
106 typedef struct
108 ULONG version;
109 ULONG revision;
110 ULONG checksumadj;
111 ULONG magic;
112 USHORT flags;
113 USHORT unitsPerEm;
114 ULONGLONG created;
115 ULONGLONG modified;
116 SHORT xMin;
117 SHORT yMin;
118 SHORT xMax;
119 SHORT yMax;
120 USHORT macStyle;
121 USHORT lowestRecPPEM;
122 SHORT direction_hint;
123 SHORT index_format;
124 SHORT glyphdata_format;
125 } TT_HEAD;
127 typedef struct
129 ULONG Version;
130 ULONG italicAngle;
131 SHORT underlinePosition;
132 SHORT underlineThickness;
133 ULONG fixed_pitch;
134 ULONG minmemType42;
135 ULONG maxmemType42;
136 ULONG minmemType1;
137 ULONG maxmemType1;
138 } TT_POST;
140 typedef struct
142 USHORT version;
143 SHORT xAvgCharWidth;
144 USHORT usWeightClass;
145 USHORT usWidthClass;
146 SHORT fsType;
147 SHORT ySubscriptXSize;
148 SHORT ySubscriptYSize;
149 SHORT ySubscriptXOffset;
150 SHORT ySubscriptYOffset;
151 SHORT ySuperscriptXSize;
152 SHORT ySuperscriptYSize;
153 SHORT ySuperscriptXOffset;
154 SHORT ySuperscriptYOffset;
155 SHORT yStrikeoutSize;
156 SHORT yStrikeoutPosition;
157 SHORT sFamilyClass;
158 PANOSE panose;
159 ULONG ulUnicodeRange1;
160 ULONG ulUnicodeRange2;
161 ULONG ulUnicodeRange3;
162 ULONG ulUnicodeRange4;
163 CHAR achVendID[4];
164 USHORT fsSelection;
165 USHORT usFirstCharIndex;
166 USHORT usLastCharIndex;
167 /* According to the Apple spec, original version didn't have the below fields,
168 * version numbers were taken from the OpenType spec.
170 /* version 0 (TrueType 1.5) */
171 USHORT sTypoAscender;
172 USHORT sTypoDescender;
173 USHORT sTypoLineGap;
174 USHORT usWinAscent;
175 USHORT usWinDescent;
176 /* version 1 (TrueType 1.66) */
177 ULONG ulCodePageRange1;
178 ULONG ulCodePageRange2;
179 /* version 2 (OpenType 1.2) */
180 SHORT sxHeight;
181 SHORT sCapHeight;
182 USHORT usDefaultChar;
183 USHORT usBreakChar;
184 USHORT usMaxContext;
185 } TT_OS2_V2;
186 #include "poppack.h"
188 enum OS2_FSSELECTION {
189 OS2_FSSELECTION_ITALIC = 1 << 0,
190 OS2_FSSELECTION_UNDERSCORE = 1 << 1,
191 OS2_FSSELECTION_NEGATIVE = 1 << 2,
192 OS2_FSSELECTION_OUTLINED = 1 << 3,
193 OS2_FSSELECTION_STRIKEOUT = 1 << 4,
194 OS2_FSSELECTION_BOLD = 1 << 5,
195 OS2_FSSELECTION_REGULAR = 1 << 6,
196 OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7,
197 OS2_FSSELECTION_WWS = 1 << 8,
198 OS2_FSSELECTION_OBLIQUE = 1 << 9
201 typedef struct {
202 WORD platformID;
203 WORD encodingID;
204 WORD languageID;
205 WORD nameID;
206 WORD length;
207 WORD offset;
208 } TT_NameRecord;
210 typedef struct {
211 WORD format;
212 WORD count;
213 WORD stringOffset;
214 TT_NameRecord nameRecord[1];
215 } TT_NAME_V0;
217 enum OPENTYPE_PLATFORM_ID
219 OPENTYPE_PLATFORM_UNICODE = 0,
220 OPENTYPE_PLATFORM_MAC,
221 OPENTYPE_PLATFORM_ISO,
222 OPENTYPE_PLATFORM_WIN,
223 OPENTYPE_PLATFORM_CUSTOM
226 enum TT_NAME_WINDOWS_ENCODING_ID
228 TT_NAME_WINDOWS_ENCODING_SYMBOL = 0,
229 TT_NAME_WINDOWS_ENCODING_UCS2,
230 TT_NAME_WINDOWS_ENCODING_SJIS,
231 TT_NAME_WINDOWS_ENCODING_PRC,
232 TT_NAME_WINDOWS_ENCODING_BIG5,
233 TT_NAME_WINDOWS_ENCODING_WANSUNG,
234 TT_NAME_WINDOWS_ENCODING_JOHAB,
235 TT_NAME_WINDOWS_ENCODING_RESERVED1,
236 TT_NAME_WINDOWS_ENCODING_RESERVED2,
237 TT_NAME_WINDOWS_ENCODING_RESERVED3,
238 TT_NAME_WINDOWS_ENCODING_UCS4
241 enum TT_NAME_MAC_ENCODING_ID
243 TT_NAME_MAC_ENCODING_ROMAN = 0,
244 TT_NAME_MAC_ENCODING_JAPANESE,
245 TT_NAME_MAC_ENCODING_TRAD_CHINESE,
246 TT_NAME_MAC_ENCODING_KOREAN,
247 TT_NAME_MAC_ENCODING_ARABIC,
248 TT_NAME_MAC_ENCODING_HEBREW,
249 TT_NAME_MAC_ENCODING_GREEK,
250 TT_NAME_MAC_ENCODING_RUSSIAN,
251 TT_NAME_MAC_ENCODING_RSYMBOL,
252 TT_NAME_MAC_ENCODING_DEVANAGARI,
253 TT_NAME_MAC_ENCODING_GURMUKHI,
254 TT_NAME_MAC_ENCODING_GUJARATI,
255 TT_NAME_MAC_ENCODING_ORIYA,
256 TT_NAME_MAC_ENCODING_BENGALI,
257 TT_NAME_MAC_ENCODING_TAMIL,
258 TT_NAME_MAC_ENCODING_TELUGU,
259 TT_NAME_MAC_ENCODING_KANNADA,
260 TT_NAME_MAC_ENCODING_MALAYALAM,
261 TT_NAME_MAC_ENCODING_SINHALESE,
262 TT_NAME_MAC_ENCODING_BURMESE,
263 TT_NAME_MAC_ENCODING_KHMER,
264 TT_NAME_MAC_ENCODING_THAI,
265 TT_NAME_MAC_ENCODING_LAOTIAN,
266 TT_NAME_MAC_ENCODING_GEORGIAN,
267 TT_NAME_MAC_ENCODING_ARMENIAN,
268 TT_NAME_MAC_ENCODING_SIMPL_CHINESE,
269 TT_NAME_MAC_ENCODING_TIBETAN,
270 TT_NAME_MAC_ENCODING_MONGOLIAN,
271 TT_NAME_MAC_ENCODING_GEEZ,
272 TT_NAME_MAC_ENCODING_SLAVIC,
273 TT_NAME_MAC_ENCODING_VIETNAMESE,
274 TT_NAME_MAC_ENCODING_SINDHI,
275 TT_NAME_MAC_ENCODING_UNINTERPRETED
278 enum TT_NAME_MAC_LANGUAGE_ID
280 TT_NAME_MAC_LANGID_ENGLISH = 0,
281 TT_NAME_MAC_LANGID_FRENCH,
282 TT_NAME_MAC_LANGID_GERMAN,
283 TT_NAME_MAC_LANGID_ITALIAN,
284 TT_NAME_MAC_LANGID_DUTCH,
285 TT_NAME_MAC_LANGID_SWEDISH,
286 TT_NAME_MAC_LANGID_SPANISH,
287 TT_NAME_MAC_LANGID_DANISH,
288 TT_NAME_MAC_LANGID_PORTUGUESE,
289 TT_NAME_MAC_LANGID_NORWEGIAN,
290 TT_NAME_MAC_LANGID_HEBREW,
291 TT_NAME_MAC_LANGID_JAPANESE,
292 TT_NAME_MAC_LANGID_ARABIC,
293 TT_NAME_MAC_LANGID_FINNISH,
294 TT_NAME_MAC_LANGID_GREEK,
295 TT_NAME_MAC_LANGID_ICELANDIC,
296 TT_NAME_MAC_LANGID_MALTESE,
297 TT_NAME_MAC_LANGID_TURKISH,
298 TT_NAME_MAC_LANGID_CROATIAN,
299 TT_NAME_MAC_LANGID_TRAD_CHINESE,
300 TT_NAME_MAC_LANGID_URDU,
301 TT_NAME_MAC_LANGID_HINDI,
302 TT_NAME_MAC_LANGID_THAI,
303 TT_NAME_MAC_LANGID_KOREAN,
304 TT_NAME_MAC_LANGID_LITHUANIAN,
305 TT_NAME_MAC_LANGID_POLISH,
306 TT_NAME_MAC_LANGID_HUNGARIAN,
307 TT_NAME_MAC_LANGID_ESTONIAN,
308 TT_NAME_MAC_LANGID_LATVIAN,
309 TT_NAME_MAC_LANGID_SAMI,
310 TT_NAME_MAC_LANGID_FAROESE,
311 TT_NAME_MAC_LANGID_FARSI,
312 TT_NAME_MAC_LANGID_RUSSIAN,
313 TT_NAME_MAC_LANGID_SIMPL_CHINESE,
314 TT_NAME_MAC_LANGID_FLEMISH,
315 TT_NAME_MAC_LANGID_GAELIC,
316 TT_NAME_MAC_LANGID_ALBANIAN,
317 TT_NAME_MAC_LANGID_ROMANIAN,
318 TT_NAME_MAC_LANGID_CZECH,
319 TT_NAME_MAC_LANGID_SLOVAK,
320 TT_NAME_MAC_LANGID_SLOVENIAN,
321 TT_NAME_MAC_LANGID_YIDDISH,
322 TT_NAME_MAC_LANGID_SERBIAN,
323 TT_NAME_MAC_LANGID_MACEDONIAN,
324 TT_NAME_MAC_LANGID_BULGARIAN,
325 TT_NAME_MAC_LANGID_UKRAINIAN,
326 TT_NAME_MAC_LANGID_BYELORUSSIAN,
327 TT_NAME_MAC_LANGID_UZBEK,
328 TT_NAME_MAC_LANGID_KAZAKH,
329 TT_NAME_MAC_LANGID_AZERB_CYR,
330 TT_NAME_MAC_LANGID_AZERB_ARABIC,
331 TT_NAME_MAC_LANGID_ARMENIAN,
332 TT_NAME_MAC_LANGID_GEORGIAN,
333 TT_NAME_MAC_LANGID_MOLDAVIAN,
334 TT_NAME_MAC_LANGID_KIRGHIZ,
335 TT_NAME_MAC_LANGID_TAJIKI,
336 TT_NAME_MAC_LANGID_TURKMEN,
337 TT_NAME_MAC_LANGID_MONGOLIAN,
338 TT_NAME_MAC_LANGID_MONGOLIAN_CYR,
339 TT_NAME_MAC_LANGID_PASHTO,
340 TT_NAME_MAC_LANGID_KURDISH,
341 TT_NAME_MAC_LANGID_KASHMIRI,
342 TT_NAME_MAC_LANGID_SINDHI,
343 TT_NAME_MAC_LANGID_TIBETAN,
344 TT_NAME_MAC_LANGID_NEPALI,
345 TT_NAME_MAC_LANGID_SANSKRIT,
346 TT_NAME_MAC_LANGID_MARATHI,
347 TT_NAME_MAC_LANGID_BENGALI,
348 TT_NAME_MAC_LANGID_ASSAMESE,
349 TT_NAME_MAC_LANGID_GUJARATI,
350 TT_NAME_MAC_LANGID_PUNJABI,
351 TT_NAME_MAC_LANGID_ORIYA,
352 TT_NAME_MAC_LANGID_MALAYALAM,
353 TT_NAME_MAC_LANGID_KANNADA,
354 TT_NAME_MAC_LANGID_TAMIL,
355 TT_NAME_MAC_LANGID_TELUGU,
356 TT_NAME_MAC_LANGID_SINHALESE,
357 TT_NAME_MAC_LANGID_BURMESE,
358 TT_NAME_MAC_LANGID_KHMER,
359 TT_NAME_MAC_LANGID_LAO,
360 TT_NAME_MAC_LANGID_VIETNAMESE,
361 TT_NAME_MAC_LANGID_INDONESIAN,
362 TT_NAME_MAC_LANGID_TAGALONG,
363 TT_NAME_MAC_LANGID_MALAY_ROMAN,
364 TT_NAME_MAC_LANGID_MALAY_ARABIC,
365 TT_NAME_MAC_LANGID_AMHARIC,
366 TT_NAME_MAC_LANGID_TIGRINYA,
367 TT_NAME_MAC_LANGID_GALLA,
368 TT_NAME_MAC_LANGID_SOMALI,
369 TT_NAME_MAC_LANGID_SWAHILI,
370 TT_NAME_MAC_LANGID_KINYARWANDA,
371 TT_NAME_MAC_LANGID_RUNDI,
372 TT_NAME_MAC_LANGID_NYANJA,
373 TT_NAME_MAC_LANGID_MALAGASY,
374 TT_NAME_MAC_LANGID_ESPERANTO,
375 TT_NAME_MAC_LANGID_WELSH,
376 TT_NAME_MAC_LANGID_BASQUE,
377 TT_NAME_MAC_LANGID_CATALAN,
378 TT_NAME_MAC_LANGID_LATIN,
379 TT_NAME_MAC_LANGID_QUENCHUA,
380 TT_NAME_MAC_LANGID_GUARANI,
381 TT_NAME_MAC_LANGID_AYMARA,
382 TT_NAME_MAC_LANGID_TATAR,
383 TT_NAME_MAC_LANGID_UIGHUR,
384 TT_NAME_MAC_LANGID_DZONGKHA,
385 TT_NAME_MAC_LANGID_JAVANESE,
386 TT_NAME_MAC_LANGID_SUNDANESE,
387 TT_NAME_MAC_LANGID_GALICIAN,
388 TT_NAME_MAC_LANGID_AFRIKAANS,
389 TT_NAME_MAC_LANGID_BRETON,
390 TT_NAME_MAC_LANGID_INUKTITUT,
391 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC,
392 TT_NAME_MAC_LANGID_MANX_GAELIC,
393 TT_NAME_MAC_LANGID_IRISH_GAELIC,
394 TT_NAME_MAC_LANGID_TONGAN,
395 TT_NAME_MAC_LANGID_GREEK_POLYTONIC,
396 TT_NAME_MAC_LANGID_GREENLANDIC,
397 TT_NAME_MAC_LANGID_AZER_ROMAN
400 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
401 static const char name_mac_langid_to_locale[][10] = {
402 "en-US",
403 "fr-FR",
404 "de-DE",
405 "it-IT",
406 "nl-NL",
407 "sv-SE",
408 "es-ES",
409 "da-DA",
410 "pt-PT",
411 "no-NO",
412 "he-IL",
413 "ja-JP",
414 "ar-AR",
415 "fi-FI",
416 "el-GR",
417 "is-IS",
418 "mt-MT",
419 "tr-TR",
420 "hr-HR",
421 "zh-HK",
422 "ur-PK",
423 "hi-IN",
424 "th-TH",
425 "ko-KR",
426 "lt-LT",
427 "pl-PL",
428 "hu-HU",
429 "et-EE",
430 "lv-LV",
431 "se-NO",
432 "fo-FO",
433 "fa-IR",
434 "ru-RU",
435 "zh-CN",
436 "nl-BE",
437 "gd-GB",
438 "sq-AL",
439 "ro-RO",
440 "cs-CZ",
441 "sk-SK",
442 "sl-SI",
444 "sr-Latn",
445 "mk-MK",
446 "bg-BG",
447 "uk-UA",
448 "be-BY",
449 "uz-Latn",
450 "kk-KZ",
451 "az-Cyrl-AZ",
452 "az-AZ",
453 "hy-AM",
454 "ka-GE",
457 "tg-TJ",
458 "tk-TM",
459 "mn-Mong",
460 "mn-MN",
461 "ps-AF",
462 "ku-Arab",
464 "sd-Arab",
465 "bo-CN",
466 "ne-NP",
467 "sa-IN",
468 "mr-IN",
469 "bn-IN",
470 "as-IN",
471 "gu-IN",
472 "pa-Arab",
473 "or-IN",
474 "ml-IN",
475 "kn-IN",
476 "ta-LK",
477 "te-IN",
478 "si-LK",
480 "km-KH",
481 "lo-LA",
482 "vi-VN",
483 "id-ID",
485 "ms-MY",
486 "ms-Arab",
487 "am-ET",
488 "ti-ET",
491 "sw-KE",
492 "rw-RW",
497 "cy-GB",
498 "eu-ES",
499 "ca-ES",
504 "tt-RU",
505 "ug-CN",
509 "gl-ES",
510 "af-ZA",
511 "br-FR",
512 "iu-Latn-CA",
513 "gd-GB",
515 "ga-IE",
518 "kl-GL",
519 "az-Latn"
522 enum OPENTYPE_STRING_ID
524 OPENTYPE_STRING_COPYRIGHT_NOTICE = 0,
525 OPENTYPE_STRING_FAMILY_NAME,
526 OPENTYPE_STRING_SUBFAMILY_NAME,
527 OPENTYPE_STRING_UNIQUE_IDENTIFIER,
528 OPENTYPE_STRING_FULL_FONTNAME,
529 OPENTYPE_STRING_VERSION_STRING,
530 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
531 OPENTYPE_STRING_TRADEMARK,
532 OPENTYPE_STRING_MANUFACTURER,
533 OPENTYPE_STRING_DESIGNER,
534 OPENTYPE_STRING_DESCRIPTION,
535 OPENTYPE_STRING_VENDOR_URL,
536 OPENTYPE_STRING_DESIGNER_URL,
537 OPENTYPE_STRING_LICENSE_DESCRIPTION,
538 OPENTYPE_STRING_LICENSE_INFO_URL,
539 OPENTYPE_STRING_RESERVED_ID15,
540 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
541 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
542 OPENTYPE_STRING_COMPATIBLE_FULLNAME,
543 OPENTYPE_STRING_SAMPLE_TEXT,
544 OPENTYPE_STRING_POSTSCRIPT_CID_NAME,
545 OPENTYPE_STRING_WWS_FAMILY_NAME,
546 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
549 static const UINT16 dwriteid_to_opentypeid[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1] =
551 (UINT16)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
552 OPENTYPE_STRING_COPYRIGHT_NOTICE,
553 OPENTYPE_STRING_VERSION_STRING,
554 OPENTYPE_STRING_TRADEMARK,
555 OPENTYPE_STRING_MANUFACTURER,
556 OPENTYPE_STRING_DESIGNER,
557 OPENTYPE_STRING_DESIGNER_URL,
558 OPENTYPE_STRING_DESCRIPTION,
559 OPENTYPE_STRING_VENDOR_URL,
560 OPENTYPE_STRING_LICENSE_DESCRIPTION,
561 OPENTYPE_STRING_LICENSE_INFO_URL,
562 OPENTYPE_STRING_FAMILY_NAME,
563 OPENTYPE_STRING_SUBFAMILY_NAME,
564 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
565 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
566 OPENTYPE_STRING_SAMPLE_TEXT,
567 OPENTYPE_STRING_FULL_FONTNAME,
568 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
569 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
572 HRESULT opentype_analyze_font(IDWriteFontFileStream *stream, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported)
574 /* TODO: Do font validation */
575 const void *font_data;
576 const char* tag;
577 void *context;
578 HRESULT hr;
580 hr = IDWriteFontFileStream_ReadFileFragment(stream, &font_data, 0, sizeof(TTC_Header_V1), &context);
581 if (FAILED(hr))
582 return hr;
584 tag = font_data;
585 *supported = FALSE;
586 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
587 if (face_type)
588 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
589 *font_count = 0;
591 if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_TTCF_TAG)
593 const TTC_Header_V1 *header = font_data;
594 *font_count = GET_BE_DWORD(header->numFonts);
595 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION;
596 if (face_type)
597 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION;
598 *supported = TRUE;
600 else if (GET_BE_DWORD(*(DWORD*)font_data) == 0x10000)
602 *font_count = 1;
603 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
604 if (face_type)
605 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
606 *supported = TRUE;
608 else if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_OTTO_TAG)
610 *file_type = DWRITE_FONT_FILE_TYPE_CFF;
613 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
614 return S_OK;
617 HRESULT opentype_get_font_table(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE type, UINT32 font_index, UINT32 tag,
618 const void **table_data, void **table_context, UINT32 *table_size, BOOL *found)
620 HRESULT hr;
621 TTC_SFNT_V1 *font_header = NULL;
622 void *sfnt_context;
623 TT_TableRecord *table_record = NULL;
624 void *table_record_context;
625 int table_count, table_offset = 0;
626 int i;
628 if (found) *found = FALSE;
629 if (table_size) *table_size = 0;
631 if (type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) {
632 const TTC_Header_V1 *ttc_header;
633 void * ttc_context;
634 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context);
635 if (SUCCEEDED(hr)) {
636 table_offset = GET_BE_DWORD(ttc_header->OffsetTable[0]);
637 if (font_index >= GET_BE_DWORD(ttc_header->numFonts))
638 hr = E_INVALIDARG;
639 else
640 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context);
641 IDWriteFontFileStream_ReleaseFileFragment(stream, ttc_context);
644 else
645 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context);
647 if (FAILED(hr))
648 return hr;
650 table_count = GET_BE_WORD(font_header->numTables);
651 table_offset += sizeof(*font_header);
652 for (i = 0; i < table_count; i++)
654 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&table_record, table_offset, sizeof(*table_record), &table_record_context);
655 if (FAILED(hr))
656 break;
657 if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag)
658 break;
659 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
660 table_offset += sizeof(*table_record);
663 IDWriteFontFileStream_ReleaseFileFragment(stream, sfnt_context);
664 if (SUCCEEDED(hr) && i < table_count)
666 int offset = GET_BE_DWORD(table_record->offset);
667 int length = GET_BE_DWORD(table_record->length);
668 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
670 if (found) *found = TRUE;
671 if (table_size) *table_size = length;
672 hr = IDWriteFontFileStream_ReadFileFragment(stream, table_data, offset, length, table_context);
675 return hr;
678 /**********
679 * CMAP
680 **********/
682 static int compare_group(const void *a, const void* b)
684 const DWORD *chr = a;
685 const CMAP_SegmentedCoverage_group *group = b;
687 if (*chr < GET_BE_DWORD(group->startCharCode))
688 return -1;
689 if (*chr > GET_BE_DWORD(group->endCharCode))
690 return 1;
691 return 0;
694 static void CMAP4_GetGlyphIndex(CMAP_SegmentMapping_0* format, UINT32 utf32c, UINT16 *pgi)
696 WORD *startCode;
697 SHORT *idDelta;
698 WORD *idRangeOffset;
699 int segment;
701 int segment_count = GET_BE_WORD(format->segCountX2)/2;
702 /* This is correct because of the padding before startCode */
703 startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
704 idDelta = (SHORT*)(((BYTE*)startCode) + (sizeof(WORD) * segment_count));
705 idRangeOffset = (WORD*)(((BYTE*)idDelta) + (sizeof(WORD) * segment_count));
707 segment = 0;
708 while(GET_BE_WORD(format->endCode[segment]) < 0xffff)
710 if (utf32c <= GET_BE_WORD(format->endCode[segment]))
711 break;
712 segment++;
714 if (segment >= segment_count)
715 return;
716 TRACE("Segment %i of %i\n",segment, segment_count);
717 if (GET_BE_WORD(startCode[segment]) > utf32c)
718 return;
719 TRACE("In range %i -> %i\n", GET_BE_WORD(startCode[segment]), GET_BE_WORD(format->endCode[segment]));
720 if (GET_BE_WORD(idRangeOffset[segment]) == 0)
722 *pgi = (SHORT)(GET_BE_WORD(idDelta[segment])) + utf32c;
724 else
726 WORD ro = GET_BE_WORD(idRangeOffset[segment])/2;
727 WORD co = (utf32c - GET_BE_WORD(startCode[segment]));
728 WORD *index = (WORD*)((BYTE*)&idRangeOffset[segment] + (ro + co));
729 *pgi = GET_BE_WORD(*index);
733 static void CMAP12_GetGlyphIndex(CMAP_SegmentedCoverage* format, UINT32 utf32c, UINT16 *pgi)
735 CMAP_SegmentedCoverage_group *group;
737 group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
738 sizeof(CMAP_SegmentedCoverage_group), compare_group);
740 if (group)
742 DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
743 *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
747 void opentype_cmap_get_glyphindex(void *data, UINT32 utf32c, UINT16 *pgi)
749 CMAP_Header *CMAP_Table = data;
750 int i;
752 *pgi = 0;
754 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
756 WORD type;
757 WORD *table;
759 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
760 continue;
762 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
763 type = GET_BE_WORD(*table);
764 TRACE("table type %i\n", type);
766 switch (type)
768 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
769 CMAP4_GetGlyphIndex((CMAP_SegmentMapping_0*) table, utf32c, pgi);
770 break;
771 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
772 CMAP12_GetGlyphIndex((CMAP_SegmentedCoverage*) table, utf32c, pgi);
773 break;
774 default:
775 TRACE("table type %i unhandled.\n", type);
778 if (*pgi) return;
782 static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table)
784 UINT32 count = 0;
785 int i;
787 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) {
788 WORD type;
789 WORD *table;
791 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
792 continue;
794 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
795 type = GET_BE_WORD(*table);
796 TRACE("table type %i\n", type);
798 switch (type)
800 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
802 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
803 count += GET_BE_WORD(format->segCountX2)/2;
804 break;
806 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
808 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
809 count += GET_BE_DWORD(format->nGroups);
810 break;
812 default:
813 FIXME("table type %i unhandled.\n", type);
817 return count;
820 HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
822 CMAP_Header *CMAP_Table = data;
823 int i, k = 0;
825 if (!CMAP_Table)
826 return E_FAIL;
828 *count = opentype_cmap_get_unicode_ranges_count(CMAP_Table);
830 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables) && k < max_count; i++)
832 WORD type;
833 WORD *table;
834 int j;
836 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
837 continue;
839 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
840 type = GET_BE_WORD(*table);
841 TRACE("table type %i\n", type);
843 switch (type)
845 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
847 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
848 UINT16 segment_count = GET_BE_WORD(format->segCountX2)/2;
849 UINT16 *startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
851 for (j = 0; j < segment_count && GET_BE_WORD(format->endCode[j]) < 0xffff && k < max_count; j++, k++) {
852 ranges[k].first = GET_BE_WORD(startCode[j]);
853 ranges[k].last = GET_BE_WORD(format->endCode[j]);
855 break;
857 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
859 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
860 for (j = 0; j < GET_BE_DWORD(format->nGroups) && k < max_count; j++, k++) {
861 ranges[k].first = GET_BE_DWORD(format->groups[j].startCharCode);
862 ranges[k].last = GET_BE_DWORD(format->groups[j].endCharCode);
864 break;
866 default:
867 FIXME("table type %i unhandled.\n", type);
871 return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK;
874 void opentype_get_font_metrics(const void *os2, const void *head, const void *post, DWRITE_FONT_METRICS1 *metrics)
876 TT_OS2_V2 *tt_os2 = (TT_OS2_V2*)os2;
877 TT_HEAD *tt_head = (TT_HEAD*)head;
878 TT_POST *tt_post = (TT_POST*)post;
880 memset(metrics, 0, sizeof(*metrics));
882 if (tt_head) {
883 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
884 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
885 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
886 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
887 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
890 if (tt_os2) {
891 USHORT version = GET_BE_WORD(tt_os2->version);
893 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
894 metrics->descent = GET_BE_WORD(tt_os2->usWinDescent);
895 /* FIXME: sTypoLineGap should only be used when USE_TYPO_METRICS is set,
896 if not set this value is probably derived from other metrics */
897 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
898 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
899 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
900 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
901 /* Y offset is stored as positive offset below baseline */
902 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
903 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
904 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
905 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
906 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
907 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
908 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
910 /* version 2 fields */
911 if (version >= 2) {
912 metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight);
913 metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight);
916 /* version 4 fields */
917 if (version >= 4) {
918 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
919 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
920 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
921 metrics->descent = descent < 0 ? -descent : 0;
922 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
923 metrics->hasTypographicMetrics = TRUE;
928 if (tt_post) {
929 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
930 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
933 /* estimate missing metrics */
934 if (metrics->xHeight == 0)
935 metrics->xHeight = metrics->designUnitsPerEm / 2;
936 if (metrics->capHeight == 0)
937 metrics->capHeight = metrics->designUnitsPerEm * 7 / 10;
940 void opentype_get_font_properties(const void *os2, const void *head, DWRITE_FONT_STRETCH *stretch, DWRITE_FONT_WEIGHT *weight, DWRITE_FONT_STYLE *style)
942 TT_OS2_V2 *tt_os2 = (TT_OS2_V2*)os2;
943 TT_HEAD *tt_head = (TT_HEAD*)head;
945 /* default stretch, weight and style to normal */
946 *stretch = DWRITE_FONT_STRETCH_NORMAL;
947 *weight = DWRITE_FONT_WEIGHT_NORMAL;
948 *style = DWRITE_FONT_STYLE_NORMAL;
950 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
951 if (tt_os2) {
952 if (GET_BE_WORD(tt_os2->usWidthClass) <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
953 *stretch = GET_BE_WORD(tt_os2->usWidthClass);
955 *weight = GET_BE_WORD(tt_os2->usWeightClass);
956 TRACE("stretch=%d, weight=%d\n", *stretch, *weight);
959 if (tt_head) {
960 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
961 if (macStyle & 0x0002)
962 *style = DWRITE_FONT_STYLE_ITALIC;
966 static UINT get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform, USHORT encoding)
968 UINT codepage = 0;
970 switch (platform) {
971 case OPENTYPE_PLATFORM_UNICODE:
972 break;
973 case OPENTYPE_PLATFORM_MAC:
974 switch (encoding)
976 case TT_NAME_MAC_ENCODING_ROMAN:
977 codepage = 10000;
978 break;
979 case TT_NAME_MAC_ENCODING_JAPANESE:
980 codepage = 10001;
981 break;
982 case TT_NAME_MAC_ENCODING_TRAD_CHINESE:
983 codepage = 10002;
984 break;
985 case TT_NAME_MAC_ENCODING_KOREAN:
986 codepage = 10003;
987 break;
988 case TT_NAME_MAC_ENCODING_ARABIC:
989 codepage = 10004;
990 break;
991 case TT_NAME_MAC_ENCODING_HEBREW:
992 codepage = 10005;
993 break;
994 case TT_NAME_MAC_ENCODING_GREEK:
995 codepage = 10006;
996 break;
997 case TT_NAME_MAC_ENCODING_RUSSIAN:
998 codepage = 10007;
999 break;
1000 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE:
1001 codepage = 10008;
1002 break;
1003 case TT_NAME_MAC_ENCODING_THAI:
1004 codepage = 10021;
1005 break;
1006 default:
1007 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1008 break;
1010 break;
1011 case OPENTYPE_PLATFORM_WIN:
1012 switch (encoding)
1014 case TT_NAME_WINDOWS_ENCODING_SYMBOL:
1015 case TT_NAME_WINDOWS_ENCODING_UCS2:
1016 break;
1017 case TT_NAME_WINDOWS_ENCODING_SJIS:
1018 codepage = 932;
1019 break;
1020 case TT_NAME_WINDOWS_ENCODING_PRC:
1021 codepage = 936;
1022 break;
1023 case TT_NAME_WINDOWS_ENCODING_BIG5:
1024 codepage = 950;
1025 break;
1026 case TT_NAME_WINDOWS_ENCODING_WANSUNG:
1027 codepage = 20949;
1028 break;
1029 case TT_NAME_WINDOWS_ENCODING_JOHAB:
1030 codepage = 1361;
1031 break;
1032 default:
1033 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1034 break;
1036 break;
1037 default:
1038 FIXME("unknown platform %d\n", platform);
1041 return codepage;
1044 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform, USHORT lang_id, WCHAR *locale, USHORT locale_len)
1046 static const WCHAR enusW[] = {'e','n','-','U','S',0};
1048 switch (platform) {
1049 case OPENTYPE_PLATFORM_MAC:
1051 const char *locale_name = NULL;
1053 if (lang_id > TT_NAME_MAC_LANGID_AZER_ROMAN)
1054 ERR("invalid mac lang id %d\n", lang_id);
1055 else if (!name_mac_langid_to_locale[lang_id][0])
1056 FIXME("failed to map mac lang id %d to locale name\n", lang_id);
1057 else
1058 locale_name = name_mac_langid_to_locale[lang_id];
1060 if (locale_name)
1061 MultiByteToWideChar(CP_ACP, 0, name_mac_langid_to_locale[lang_id], -1, locale, locale_len);
1062 else
1063 strcpyW(locale, enusW);
1064 break;
1066 case OPENTYPE_PLATFORM_WIN:
1067 if (!LCIDToLocaleName(MAKELCID(lang_id, SORT_DEFAULT), locale, locale_len, 0)) {
1068 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id, SORT_DEFAULT));
1069 strcpyW(locale, enusW);
1071 break;
1072 default:
1073 FIXME("unknown platform %d\n", platform);
1077 HRESULT opentype_get_font_strings_from_id(const void *table_data, DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings)
1079 const TT_NAME_V0 *header;
1080 BYTE *storage_area = 0;
1081 USHORT count = 0;
1082 UINT16 name_id;
1083 BOOL exists;
1084 HRESULT hr;
1085 int i;
1087 if (!table_data)
1088 return E_FAIL;
1090 hr = create_localizedstrings(strings);
1091 if (FAILED(hr)) return hr;
1093 header = table_data;
1094 storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset);
1095 count = GET_BE_WORD(header->count);
1097 name_id = dwriteid_to_opentypeid[id];
1099 exists = FALSE;
1100 for (i = 0; i < count; i++) {
1101 const TT_NameRecord *record = &header->nameRecord[i];
1102 USHORT lang_id, length, offset, encoding, platform;
1104 if (GET_BE_WORD(record->nameID) != name_id)
1105 continue;
1107 exists = TRUE;
1109 /* Right now only accept unicode and windows encoded fonts */
1110 platform = GET_BE_WORD(record->platformID);
1111 if (platform != OPENTYPE_PLATFORM_UNICODE &&
1112 platform != OPENTYPE_PLATFORM_MAC &&
1113 platform != OPENTYPE_PLATFORM_WIN)
1115 FIXME("platform %i not supported\n", platform);
1116 continue;
1119 lang_id = GET_BE_WORD(record->languageID);
1120 length = GET_BE_WORD(record->length);
1121 offset = GET_BE_WORD(record->offset);
1122 encoding = GET_BE_WORD(record->encodingID);
1124 if (lang_id < 0x8000) {
1125 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
1126 WCHAR *name_string;
1127 UINT codepage;
1129 codepage = get_name_record_codepage(platform, encoding);
1130 get_name_record_locale(platform, lang_id, locale, sizeof(locale)/sizeof(WCHAR));
1132 if (codepage) {
1133 DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0);
1134 name_string = heap_alloc(sizeof(WCHAR) * (len+1));
1135 MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len);
1136 name_string[len] = 0;
1138 else {
1139 int i;
1141 length /= sizeof(WCHAR);
1142 name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length);
1143 for (i = 0; i < length; i++)
1144 name_string[i] = GET_BE_WORD(name_string[i]);
1147 TRACE("string %s for locale %s found\n", debugstr_w(name_string), debugstr_w(locale));
1148 add_localizedstring(*strings, locale, name_string);
1149 heap_free(name_string);
1151 else {
1152 FIXME("handle NAME format 1");
1153 continue;
1157 if (!exists) {
1158 IDWriteLocalizedStrings_Release(*strings);
1159 *strings = NULL;
1162 return hr;