mshtml: Added nsIURI::GetPrePath implementation.
[wine.git] / dlls / dwrite / opentype.c
blob1f5e17815a30d9bdadea134a4ea633dd878846df
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 typedef struct {
189 WORD platformID;
190 WORD encodingID;
191 WORD languageID;
192 WORD nameID;
193 WORD length;
194 WORD offset;
195 } TT_NameRecord;
197 typedef struct {
198 WORD format;
199 WORD count;
200 WORD stringOffset;
201 TT_NameRecord nameRecord[1];
202 } TT_NAME_V0;
204 enum OPENTYPE_PLATFORM_ID
206 OPENTYPE_PLATFORM_UNICODE = 0,
207 OPENTYPE_PLATFORM_MAC,
208 OPENTYPE_PLATFORM_ISO,
209 OPENTYPE_PLATFORM_WIN,
210 OPENTYPE_PLATFORM_CUSTOM
213 enum TT_NAME_WINDOWS_ENCODING_ID
215 TT_NAME_WINDOWS_ENCODING_SYMBOL = 0,
216 TT_NAME_WINDOWS_ENCODING_UCS2,
217 TT_NAME_WINDOWS_ENCODING_SJIS,
218 TT_NAME_WINDOWS_ENCODING_PRC,
219 TT_NAME_WINDOWS_ENCODING_BIG5,
220 TT_NAME_WINDOWS_ENCODING_WANSUNG,
221 TT_NAME_WINDOWS_ENCODING_JOHAB,
222 TT_NAME_WINDOWS_ENCODING_RESERVED1,
223 TT_NAME_WINDOWS_ENCODING_RESERVED2,
224 TT_NAME_WINDOWS_ENCODING_RESERVED3,
225 TT_NAME_WINDOWS_ENCODING_UCS4
228 enum TT_NAME_MAC_ENCODING_ID
230 TT_NAME_MAC_ENCODING_ROMAN = 0,
231 TT_NAME_MAC_ENCODING_JAPANESE,
232 TT_NAME_MAC_ENCODING_TRAD_CHINESE,
233 TT_NAME_MAC_ENCODING_KOREAN,
234 TT_NAME_MAC_ENCODING_ARABIC,
235 TT_NAME_MAC_ENCODING_HEBREW,
236 TT_NAME_MAC_ENCODING_GREEK,
237 TT_NAME_MAC_ENCODING_RUSSIAN,
238 TT_NAME_MAC_ENCODING_RSYMBOL,
239 TT_NAME_MAC_ENCODING_DEVANAGARI,
240 TT_NAME_MAC_ENCODING_GURMUKHI,
241 TT_NAME_MAC_ENCODING_GUJARATI,
242 TT_NAME_MAC_ENCODING_ORIYA,
243 TT_NAME_MAC_ENCODING_BENGALI,
244 TT_NAME_MAC_ENCODING_TAMIL,
245 TT_NAME_MAC_ENCODING_TELUGU,
246 TT_NAME_MAC_ENCODING_KANNADA,
247 TT_NAME_MAC_ENCODING_MALAYALAM,
248 TT_NAME_MAC_ENCODING_SINHALESE,
249 TT_NAME_MAC_ENCODING_BURMESE,
250 TT_NAME_MAC_ENCODING_KHMER,
251 TT_NAME_MAC_ENCODING_THAI,
252 TT_NAME_MAC_ENCODING_LAOTIAN,
253 TT_NAME_MAC_ENCODING_GEORGIAN,
254 TT_NAME_MAC_ENCODING_ARMENIAN,
255 TT_NAME_MAC_ENCODING_SIMPL_CHINESE,
256 TT_NAME_MAC_ENCODING_TIBETAN,
257 TT_NAME_MAC_ENCODING_MONGOLIAN,
258 TT_NAME_MAC_ENCODING_GEEZ,
259 TT_NAME_MAC_ENCODING_SLAVIC,
260 TT_NAME_MAC_ENCODING_VIETNAMESE,
261 TT_NAME_MAC_ENCODING_SINDHI,
262 TT_NAME_MAC_ENCODING_UNINTERPRETED
265 enum TT_NAME_MAC_LANGUAGE_ID
267 TT_NAME_MAC_LANGID_ENGLISH = 0,
268 TT_NAME_MAC_LANGID_FRENCH,
269 TT_NAME_MAC_LANGID_GERMAN,
270 TT_NAME_MAC_LANGID_ITALIAN,
271 TT_NAME_MAC_LANGID_DUTCH,
272 TT_NAME_MAC_LANGID_SWEDISH,
273 TT_NAME_MAC_LANGID_SPANISH,
274 TT_NAME_MAC_LANGID_DANISH,
275 TT_NAME_MAC_LANGID_PORTUGUESE,
276 TT_NAME_MAC_LANGID_NORWEGIAN,
277 TT_NAME_MAC_LANGID_HEBREW,
278 TT_NAME_MAC_LANGID_JAPANESE,
279 TT_NAME_MAC_LANGID_ARABIC,
280 TT_NAME_MAC_LANGID_FINNISH,
281 TT_NAME_MAC_LANGID_GREEK,
282 TT_NAME_MAC_LANGID_ICELANDIC,
283 TT_NAME_MAC_LANGID_MALTESE,
284 TT_NAME_MAC_LANGID_TURKISH,
285 TT_NAME_MAC_LANGID_CROATIAN,
286 TT_NAME_MAC_LANGID_TRAD_CHINESE,
287 TT_NAME_MAC_LANGID_URDU,
288 TT_NAME_MAC_LANGID_HINDI,
289 TT_NAME_MAC_LANGID_THAI,
290 TT_NAME_MAC_LANGID_KOREAN,
291 TT_NAME_MAC_LANGID_LITHUANIAN,
292 TT_NAME_MAC_LANGID_POLISH,
293 TT_NAME_MAC_LANGID_HUNGARIAN,
294 TT_NAME_MAC_LANGID_ESTONIAN,
295 TT_NAME_MAC_LANGID_LATVIAN,
296 TT_NAME_MAC_LANGID_SAMI,
297 TT_NAME_MAC_LANGID_FAROESE,
298 TT_NAME_MAC_LANGID_FARSI,
299 TT_NAME_MAC_LANGID_RUSSIAN,
300 TT_NAME_MAC_LANGID_SIMPL_CHINESE,
301 TT_NAME_MAC_LANGID_FLEMISH,
302 TT_NAME_MAC_LANGID_GAELIC,
303 TT_NAME_MAC_LANGID_ALBANIAN,
304 TT_NAME_MAC_LANGID_ROMANIAN,
305 TT_NAME_MAC_LANGID_CZECH,
306 TT_NAME_MAC_LANGID_SLOVAK,
307 TT_NAME_MAC_LANGID_SLOVENIAN,
308 TT_NAME_MAC_LANGID_YIDDISH,
309 TT_NAME_MAC_LANGID_SERBIAN,
310 TT_NAME_MAC_LANGID_MACEDONIAN,
311 TT_NAME_MAC_LANGID_BULGARIAN,
312 TT_NAME_MAC_LANGID_UKRAINIAN,
313 TT_NAME_MAC_LANGID_BYELORUSSIAN,
314 TT_NAME_MAC_LANGID_UZBEK,
315 TT_NAME_MAC_LANGID_KAZAKH,
316 TT_NAME_MAC_LANGID_AZERB_CYR,
317 TT_NAME_MAC_LANGID_AZERB_ARABIC,
318 TT_NAME_MAC_LANGID_ARMENIAN,
319 TT_NAME_MAC_LANGID_GEORGIAN,
320 TT_NAME_MAC_LANGID_MOLDAVIAN,
321 TT_NAME_MAC_LANGID_KIRGHIZ,
322 TT_NAME_MAC_LANGID_TAJIKI,
323 TT_NAME_MAC_LANGID_TURKMEN,
324 TT_NAME_MAC_LANGID_MONGOLIAN,
325 TT_NAME_MAC_LANGID_MONGOLIAN_CYR,
326 TT_NAME_MAC_LANGID_PASHTO,
327 TT_NAME_MAC_LANGID_KURDISH,
328 TT_NAME_MAC_LANGID_KASHMIRI,
329 TT_NAME_MAC_LANGID_SINDHI,
330 TT_NAME_MAC_LANGID_TIBETAN,
331 TT_NAME_MAC_LANGID_NEPALI,
332 TT_NAME_MAC_LANGID_SANSKRIT,
333 TT_NAME_MAC_LANGID_MARATHI,
334 TT_NAME_MAC_LANGID_BENGALI,
335 TT_NAME_MAC_LANGID_ASSAMESE,
336 TT_NAME_MAC_LANGID_GUJARATI,
337 TT_NAME_MAC_LANGID_PUNJABI,
338 TT_NAME_MAC_LANGID_ORIYA,
339 TT_NAME_MAC_LANGID_MALAYALAM,
340 TT_NAME_MAC_LANGID_KANNADA,
341 TT_NAME_MAC_LANGID_TAMIL,
342 TT_NAME_MAC_LANGID_TELUGU,
343 TT_NAME_MAC_LANGID_SINHALESE,
344 TT_NAME_MAC_LANGID_BURMESE,
345 TT_NAME_MAC_LANGID_KHMER,
346 TT_NAME_MAC_LANGID_LAO,
347 TT_NAME_MAC_LANGID_VIETNAMESE,
348 TT_NAME_MAC_LANGID_INDONESIAN,
349 TT_NAME_MAC_LANGID_TAGALONG,
350 TT_NAME_MAC_LANGID_MALAY_ROMAN,
351 TT_NAME_MAC_LANGID_MALAY_ARABIC,
352 TT_NAME_MAC_LANGID_AMHARIC,
353 TT_NAME_MAC_LANGID_TIGRINYA,
354 TT_NAME_MAC_LANGID_GALLA,
355 TT_NAME_MAC_LANGID_SOMALI,
356 TT_NAME_MAC_LANGID_SWAHILI,
357 TT_NAME_MAC_LANGID_KINYARWANDA,
358 TT_NAME_MAC_LANGID_RUNDI,
359 TT_NAME_MAC_LANGID_NYANJA,
360 TT_NAME_MAC_LANGID_MALAGASY,
361 TT_NAME_MAC_LANGID_ESPERANTO,
362 TT_NAME_MAC_LANGID_WELSH,
363 TT_NAME_MAC_LANGID_BASQUE,
364 TT_NAME_MAC_LANGID_CATALAN,
365 TT_NAME_MAC_LANGID_LATIN,
366 TT_NAME_MAC_LANGID_QUENCHUA,
367 TT_NAME_MAC_LANGID_GUARANI,
368 TT_NAME_MAC_LANGID_AYMARA,
369 TT_NAME_MAC_LANGID_TATAR,
370 TT_NAME_MAC_LANGID_UIGHUR,
371 TT_NAME_MAC_LANGID_DZONGKHA,
372 TT_NAME_MAC_LANGID_JAVANESE,
373 TT_NAME_MAC_LANGID_SUNDANESE,
374 TT_NAME_MAC_LANGID_GALICIAN,
375 TT_NAME_MAC_LANGID_AFRIKAANS,
376 TT_NAME_MAC_LANGID_BRETON,
377 TT_NAME_MAC_LANGID_INUKTITUT,
378 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC,
379 TT_NAME_MAC_LANGID_MANX_GAELIC,
380 TT_NAME_MAC_LANGID_IRISH_GAELIC,
381 TT_NAME_MAC_LANGID_TONGAN,
382 TT_NAME_MAC_LANGID_GREEK_POLYTONIC,
383 TT_NAME_MAC_LANGID_GREENLANDIC,
384 TT_NAME_MAC_LANGID_AZER_ROMAN
387 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
388 static const char name_mac_langid_to_locale[][10] = {
389 "en-US",
390 "fr-FR",
391 "de-DE",
392 "it-IT",
393 "nl-NL",
394 "sv-SE",
395 "es-ES",
396 "da-DA",
397 "pt-PT",
398 "no-NO",
399 "he-IL",
400 "ja-JP",
401 "ar-AR",
402 "fi-FI",
403 "el-GR",
404 "is-IS",
405 "mt-MT",
406 "tr-TR",
407 "hr-HR",
408 "zh-HK",
409 "ur-PK",
410 "hi-IN",
411 "th-TH",
412 "ko-KR",
413 "lt-LT",
414 "pl-PL",
415 "hu-HU",
416 "et-EE",
417 "lv-LV",
418 "se-NO",
419 "fo-FO",
420 "fa-IR",
421 "ru-RU",
422 "zh-CN",
423 "nl-BE",
424 "gd-GB",
425 "sq-AL",
426 "ro-RO",
427 "cs-CZ",
428 "sk-SK",
429 "sl-SI",
431 "sr-Latn",
432 "mk-MK",
433 "bg-BG",
434 "uk-UA",
435 "be-BY",
436 "uz-Latn",
437 "kk-KZ",
438 "az-Cyrl-AZ",
439 "az-AZ",
440 "hy-AM",
441 "ka-GE",
444 "tg-TJ",
445 "tk-TM",
446 "mn-Mong",
447 "mn-MN",
448 "ps-AF",
449 "ku-Arab",
451 "sd-Arab",
452 "bo-CN",
453 "ne-NP",
454 "sa-IN",
455 "mr-IN",
456 "bn-IN",
457 "as-IN",
458 "gu-IN",
459 "pa-Arab",
460 "or-IN",
461 "ml-IN",
462 "kn-IN",
463 "ta-LK",
464 "te-IN",
465 "si-LK",
467 "km-KH",
468 "lo-LA",
469 "vi-VN",
470 "id-ID",
472 "ms-MY",
473 "ms-Arab",
474 "am-ET",
475 "ti-ET",
478 "sw-KE",
479 "rw-RW",
484 "cy-GB",
485 "eu-ES",
486 "ca-ES",
491 "tt-RU",
492 "ug-CN",
496 "gl-ES",
497 "af-ZA",
498 "br-FR",
499 "iu-Latn-CA",
500 "gd-GB",
502 "ga-IE",
505 "kl-GL",
506 "az-Latn"
509 enum OPENTYPE_STRING_ID
511 OPENTYPE_STRING_COPYRIGHT_NOTICE = 0,
512 OPENTYPE_STRING_FAMILY_NAME,
513 OPENTYPE_STRING_SUBFAMILY_NAME,
514 OPENTYPE_STRING_UNIQUE_IDENTIFIER,
515 OPENTYPE_STRING_FULL_FONTNAME,
516 OPENTYPE_STRING_VERSION_STRING,
517 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
518 OPENTYPE_STRING_TRADEMARK,
519 OPENTYPE_STRING_MANUFACTURER,
520 OPENTYPE_STRING_DESIGNER,
521 OPENTYPE_STRING_DESCRIPTION,
522 OPENTYPE_STRING_VENDOR_URL,
523 OPENTYPE_STRING_DESIGNER_URL,
524 OPENTYPE_STRING_LICENSE_DESCRIPTION,
525 OPENTYPE_STRING_LICENSE_INFO_URL,
526 OPENTYPE_STRING_RESERVED_ID15,
527 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
528 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
529 OPENTYPE_STRING_COMPATIBLE_FULLNAME,
530 OPENTYPE_STRING_SAMPLE_TEXT,
531 OPENTYPE_STRING_POSTSCRIPT_CID_NAME,
532 OPENTYPE_STRING_WWS_FAMILY_NAME,
533 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
536 static const UINT16 dwriteid_to_opentypeid[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1] =
538 (UINT16)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
539 OPENTYPE_STRING_COPYRIGHT_NOTICE,
540 OPENTYPE_STRING_VERSION_STRING,
541 OPENTYPE_STRING_TRADEMARK,
542 OPENTYPE_STRING_MANUFACTURER,
543 OPENTYPE_STRING_DESIGNER,
544 OPENTYPE_STRING_DESIGNER_URL,
545 OPENTYPE_STRING_DESCRIPTION,
546 OPENTYPE_STRING_VENDOR_URL,
547 OPENTYPE_STRING_LICENSE_DESCRIPTION,
548 OPENTYPE_STRING_LICENSE_INFO_URL,
549 OPENTYPE_STRING_FAMILY_NAME,
550 OPENTYPE_STRING_SUBFAMILY_NAME,
551 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
552 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
553 OPENTYPE_STRING_SAMPLE_TEXT,
554 OPENTYPE_STRING_FULL_FONTNAME,
555 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
556 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
559 HRESULT opentype_analyze_font(IDWriteFontFileStream *stream, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported)
561 /* TODO: Do font validation */
562 const void *font_data;
563 const char* tag;
564 void *context;
565 HRESULT hr;
567 hr = IDWriteFontFileStream_ReadFileFragment(stream, &font_data, 0, sizeof(TTC_Header_V1), &context);
568 if (FAILED(hr))
569 return hr;
571 tag = font_data;
572 *supported = FALSE;
573 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
574 if (face_type)
575 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
576 *font_count = 0;
578 if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_TTCF_TAG)
580 const TTC_Header_V1 *header = font_data;
581 *font_count = GET_BE_DWORD(header->numFonts);
582 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION;
583 if (face_type)
584 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION;
585 *supported = TRUE;
587 else if (GET_BE_DWORD(*(DWORD*)font_data) == 0x10000)
589 *font_count = 1;
590 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
591 if (face_type)
592 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
593 *supported = TRUE;
595 else if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_OTTO_TAG)
597 *file_type = DWRITE_FONT_FILE_TYPE_CFF;
600 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
601 return S_OK;
604 HRESULT opentype_get_font_table(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE type, UINT32 font_index, UINT32 tag,
605 const void **table_data, void **table_context, UINT32 *table_size, BOOL *found)
607 HRESULT hr;
608 TTC_SFNT_V1 *font_header = NULL;
609 void *sfnt_context;
610 TT_TableRecord *table_record = NULL;
611 void *table_record_context;
612 int table_count, table_offset = 0;
613 int i;
615 if (found) *found = FALSE;
616 if (table_size) *table_size = 0;
618 if (type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) {
619 const TTC_Header_V1 *ttc_header;
620 void * ttc_context;
621 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context);
622 if (SUCCEEDED(hr)) {
623 table_offset = GET_BE_DWORD(ttc_header->OffsetTable[0]);
624 if (font_index >= GET_BE_DWORD(ttc_header->numFonts))
625 hr = E_INVALIDARG;
626 else
627 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context);
628 IDWriteFontFileStream_ReleaseFileFragment(stream, ttc_context);
631 else
632 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context);
634 if (FAILED(hr))
635 return hr;
637 table_count = GET_BE_WORD(font_header->numTables);
638 table_offset += sizeof(*font_header);
639 for (i = 0; i < table_count; i++)
641 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&table_record, table_offset, sizeof(*table_record), &table_record_context);
642 if (FAILED(hr))
643 break;
644 if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag)
645 break;
646 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
647 table_offset += sizeof(*table_record);
650 IDWriteFontFileStream_ReleaseFileFragment(stream, sfnt_context);
651 if (SUCCEEDED(hr) && i < table_count)
653 int offset = GET_BE_DWORD(table_record->offset);
654 int length = GET_BE_DWORD(table_record->length);
655 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
657 if (found) *found = TRUE;
658 if (table_size) *table_size = length;
659 hr = IDWriteFontFileStream_ReadFileFragment(stream, table_data, offset, length, table_context);
662 return hr;
665 /**********
666 * CMAP
667 **********/
669 static int compare_group(const void *a, const void* b)
671 const DWORD *chr = a;
672 const CMAP_SegmentedCoverage_group *group = b;
674 if (*chr < GET_BE_DWORD(group->startCharCode))
675 return -1;
676 if (*chr > GET_BE_DWORD(group->endCharCode))
677 return 1;
678 return 0;
681 static void CMAP4_GetGlyphIndex(CMAP_SegmentMapping_0* format, UINT32 utf32c, UINT16 *pgi)
683 WORD *startCode;
684 SHORT *idDelta;
685 WORD *idRangeOffset;
686 int segment;
688 int segment_count = GET_BE_WORD(format->segCountX2)/2;
689 /* This is correct because of the padding before startCode */
690 startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
691 idDelta = (SHORT*)(((BYTE*)startCode) + (sizeof(WORD) * segment_count));
692 idRangeOffset = (WORD*)(((BYTE*)idDelta) + (sizeof(WORD) * segment_count));
694 segment = 0;
695 while(GET_BE_WORD(format->endCode[segment]) < 0xffff)
697 if (utf32c <= GET_BE_WORD(format->endCode[segment]))
698 break;
699 segment++;
701 if (segment >= segment_count)
702 return;
703 TRACE("Segment %i of %i\n",segment, segment_count);
704 if (GET_BE_WORD(startCode[segment]) > utf32c)
705 return;
706 TRACE("In range %i -> %i\n", GET_BE_WORD(startCode[segment]), GET_BE_WORD(format->endCode[segment]));
707 if (GET_BE_WORD(idRangeOffset[segment]) == 0)
709 *pgi = (SHORT)(GET_BE_WORD(idDelta[segment])) + utf32c;
711 else
713 WORD ro = GET_BE_WORD(idRangeOffset[segment])/2;
714 WORD co = (utf32c - GET_BE_WORD(startCode[segment]));
715 WORD *index = (WORD*)((BYTE*)&idRangeOffset[segment] + (ro + co));
716 *pgi = GET_BE_WORD(*index);
720 static void CMAP12_GetGlyphIndex(CMAP_SegmentedCoverage* format, UINT32 utf32c, UINT16 *pgi)
722 CMAP_SegmentedCoverage_group *group;
724 group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
725 sizeof(CMAP_SegmentedCoverage_group), compare_group);
727 if (group)
729 DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
730 *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
734 void opentype_cmap_get_glyphindex(void *data, UINT32 utf32c, UINT16 *pgi)
736 CMAP_Header *CMAP_Table = data;
737 int i;
739 *pgi = 0;
741 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
743 WORD type;
744 WORD *table;
746 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
747 continue;
749 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
750 type = GET_BE_WORD(*table);
751 TRACE("table type %i\n", type);
753 switch (type)
755 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
756 CMAP4_GetGlyphIndex((CMAP_SegmentMapping_0*) table, utf32c, pgi);
757 break;
758 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
759 CMAP12_GetGlyphIndex((CMAP_SegmentedCoverage*) table, utf32c, pgi);
760 break;
761 default:
762 TRACE("table type %i unhandled.\n", type);
765 if (*pgi) return;
769 static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table)
771 UINT32 count = 0;
772 int i;
774 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) {
775 WORD type;
776 WORD *table;
778 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
779 continue;
781 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
782 type = GET_BE_WORD(*table);
783 TRACE("table type %i\n", type);
785 switch (type)
787 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
789 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
790 count += GET_BE_WORD(format->segCountX2)/2;
791 break;
793 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
795 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
796 count += GET_BE_DWORD(format->nGroups);
797 break;
799 default:
800 FIXME("table type %i unhandled.\n", type);
804 return count;
807 HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
809 CMAP_Header *CMAP_Table = data;
810 int i, k = 0;
812 if (!CMAP_Table)
813 return E_FAIL;
815 *count = opentype_cmap_get_unicode_ranges_count(CMAP_Table);
817 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables) && k < max_count; i++)
819 WORD type;
820 WORD *table;
821 int j;
823 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
824 continue;
826 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
827 type = GET_BE_WORD(*table);
828 TRACE("table type %i\n", type);
830 switch (type)
832 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
834 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
835 UINT16 segment_count = GET_BE_WORD(format->segCountX2)/2;
836 UINT16 *startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
838 for (j = 0; j < segment_count && GET_BE_WORD(format->endCode[j]) < 0xffff && k < max_count; j++, k++) {
839 ranges[k].first = GET_BE_WORD(startCode[j]);
840 ranges[k].last = GET_BE_WORD(format->endCode[j]);
842 break;
844 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
846 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
847 for (j = 0; j < GET_BE_DWORD(format->nGroups) && k < max_count; j++, k++) {
848 ranges[k].first = GET_BE_DWORD(format->groups[j].startCharCode);
849 ranges[k].last = GET_BE_DWORD(format->groups[j].endCharCode);
851 break;
853 default:
854 FIXME("table type %i unhandled.\n", type);
858 return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK;
861 void opentype_get_font_metrics(const void *os2, const void *head, const void *post, DWRITE_FONT_METRICS1 *metrics)
863 TT_OS2_V2 *tt_os2 = (TT_OS2_V2*)os2;
864 TT_HEAD *tt_head = (TT_HEAD*)head;
865 TT_POST *tt_post = (TT_POST*)post;
867 memset(metrics, 0, sizeof(*metrics));
869 if (tt_os2) {
870 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
871 metrics->descent = GET_BE_WORD(tt_os2->sTypoDescender);
872 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
873 metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight);
874 metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight);
875 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
876 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
877 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
878 /* Y offset is stored as positive offset below baseline */
879 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
880 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
881 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
882 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
883 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
884 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
885 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
888 if (tt_head) {
889 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
890 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
891 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
892 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
893 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
896 if (tt_post) {
897 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
898 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
902 void opentype_get_font_properties(const void *os2, const void *head, DWRITE_FONT_STRETCH *stretch, DWRITE_FONT_WEIGHT *weight, DWRITE_FONT_STYLE *style)
904 TT_OS2_V2 *tt_os2 = (TT_OS2_V2*)os2;
905 TT_HEAD *tt_head = (TT_HEAD*)head;
907 /* default stretch, weight and style to normal */
908 *stretch = DWRITE_FONT_STRETCH_NORMAL;
909 *weight = DWRITE_FONT_WEIGHT_NORMAL;
910 *style = DWRITE_FONT_STYLE_NORMAL;
912 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
913 if (tt_os2) {
914 if (GET_BE_WORD(tt_os2->usWidthClass) <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
915 *stretch = GET_BE_WORD(tt_os2->usWidthClass);
917 *weight = GET_BE_WORD(tt_os2->usWeightClass);
918 TRACE("stretch=%d, weight=%d\n", *stretch, *weight);
921 if (tt_head) {
922 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
923 if (macStyle & 0x0002)
924 *style = DWRITE_FONT_STYLE_ITALIC;
928 static UINT get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform, USHORT encoding)
930 UINT codepage = 0;
932 switch (platform) {
933 case OPENTYPE_PLATFORM_UNICODE:
934 break;
935 case OPENTYPE_PLATFORM_MAC:
936 switch (encoding)
938 case TT_NAME_MAC_ENCODING_ROMAN:
939 codepage = 10000;
940 break;
941 case TT_NAME_MAC_ENCODING_JAPANESE:
942 codepage = 10001;
943 break;
944 case TT_NAME_MAC_ENCODING_TRAD_CHINESE:
945 codepage = 10002;
946 break;
947 case TT_NAME_MAC_ENCODING_KOREAN:
948 codepage = 10003;
949 break;
950 case TT_NAME_MAC_ENCODING_ARABIC:
951 codepage = 10004;
952 break;
953 case TT_NAME_MAC_ENCODING_HEBREW:
954 codepage = 10005;
955 break;
956 case TT_NAME_MAC_ENCODING_GREEK:
957 codepage = 10006;
958 break;
959 case TT_NAME_MAC_ENCODING_RUSSIAN:
960 codepage = 10007;
961 break;
962 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE:
963 codepage = 10008;
964 break;
965 case TT_NAME_MAC_ENCODING_THAI:
966 codepage = 10021;
967 break;
968 default:
969 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
970 break;
972 break;
973 case OPENTYPE_PLATFORM_WIN:
974 switch (encoding)
976 case TT_NAME_WINDOWS_ENCODING_SYMBOL:
977 case TT_NAME_WINDOWS_ENCODING_UCS2:
978 break;
979 case TT_NAME_WINDOWS_ENCODING_SJIS:
980 codepage = 932;
981 break;
982 case TT_NAME_WINDOWS_ENCODING_PRC:
983 codepage = 936;
984 break;
985 case TT_NAME_WINDOWS_ENCODING_BIG5:
986 codepage = 950;
987 break;
988 case TT_NAME_WINDOWS_ENCODING_WANSUNG:
989 codepage = 20949;
990 break;
991 case TT_NAME_WINDOWS_ENCODING_JOHAB:
992 codepage = 1361;
993 break;
994 default:
995 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
996 break;
998 break;
999 default:
1000 FIXME("unknown platform %d\n", platform);
1003 return codepage;
1006 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform, USHORT lang_id, WCHAR *locale, USHORT locale_len)
1008 static const WCHAR enusW[] = {'e','n','-','U','S',0};
1010 switch (platform) {
1011 case OPENTYPE_PLATFORM_MAC:
1013 const char *locale_name = NULL;
1015 if (lang_id > TT_NAME_MAC_LANGID_AZER_ROMAN)
1016 ERR("invalid mac lang id %d\n", lang_id);
1017 else if (!name_mac_langid_to_locale[lang_id][0])
1018 FIXME("failed to map mac lang id %d to locale name\n", lang_id);
1019 else
1020 locale_name = name_mac_langid_to_locale[lang_id];
1022 if (locale_name)
1023 MultiByteToWideChar(CP_ACP, 0, name_mac_langid_to_locale[lang_id], -1, locale, locale_len);
1024 else
1025 strcpyW(locale, enusW);
1026 break;
1028 case OPENTYPE_PLATFORM_WIN:
1029 if (!LCIDToLocaleName(MAKELCID(lang_id, SORT_DEFAULT), locale, locale_len, 0)) {
1030 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id, SORT_DEFAULT));
1031 strcpyW(locale, enusW);
1033 break;
1034 default:
1035 FIXME("unknown platform %d\n", platform);
1039 HRESULT opentype_get_font_strings_from_id(const void *table_data, DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings)
1041 const TT_NAME_V0 *header;
1042 BYTE *storage_area = 0;
1043 USHORT count = 0;
1044 UINT16 name_id;
1045 BOOL exists;
1046 HRESULT hr;
1047 int i;
1049 if (!table_data)
1050 return E_FAIL;
1052 hr = create_localizedstrings(strings);
1053 if (FAILED(hr)) return hr;
1055 header = table_data;
1056 storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset);
1057 count = GET_BE_WORD(header->count);
1059 name_id = dwriteid_to_opentypeid[id];
1061 exists = FALSE;
1062 for (i = 0; i < count; i++) {
1063 const TT_NameRecord *record = &header->nameRecord[i];
1064 USHORT lang_id, length, offset, encoding, platform;
1066 if (GET_BE_WORD(record->nameID) != name_id)
1067 continue;
1069 exists = TRUE;
1071 /* Right now only accept unicode and windows encoded fonts */
1072 platform = GET_BE_WORD(record->platformID);
1073 if (platform != OPENTYPE_PLATFORM_UNICODE &&
1074 platform != OPENTYPE_PLATFORM_MAC &&
1075 platform != OPENTYPE_PLATFORM_WIN)
1077 FIXME("platform %i not supported\n", platform);
1078 continue;
1081 lang_id = GET_BE_WORD(record->languageID);
1082 length = GET_BE_WORD(record->length);
1083 offset = GET_BE_WORD(record->offset);
1084 encoding = GET_BE_WORD(record->encodingID);
1086 if (lang_id < 0x8000) {
1087 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
1088 WCHAR *name_string;
1089 UINT codepage;
1091 codepage = get_name_record_codepage(platform, encoding);
1092 get_name_record_locale(platform, lang_id, locale, sizeof(locale)/sizeof(WCHAR));
1094 if (codepage) {
1095 DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0);
1096 name_string = heap_alloc(sizeof(WCHAR) * (len+1));
1097 MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len);
1098 name_string[len] = 0;
1100 else {
1101 int i;
1103 length /= sizeof(WCHAR);
1104 name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length);
1105 for (i = 0; i < length; i++)
1106 name_string[i] = GET_BE_WORD(name_string[i]);
1109 TRACE("string %s for locale %s found\n", debugstr_w(name_string), debugstr_w(locale));
1110 add_localizedstring(*strings, locale, name_string);
1111 heap_free(name_string);
1113 else {
1114 FIXME("handle NAME format 1");
1115 continue;
1119 if (!exists) {
1120 IDWriteLocalizedStrings_Release(*strings);
1121 *strings = NULL;
1124 return hr;