msvcirt: Add implementation of streambuf::sputbackc.
[wine.git] / dlls / dwrite / opentype.c
blobcbc509077873b6e39e339850256378fe20096793
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_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)
39 #else
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)))
42 #endif
44 typedef struct {
45 CHAR TTCTag[4];
46 DWORD Version;
47 DWORD numFonts;
48 DWORD OffsetTable[1];
49 } TTC_Header_V1;
51 typedef struct {
52 DWORD version;
53 WORD numTables;
54 WORD searchRange;
55 WORD entrySelector;
56 WORD rangeShift;
57 } TTC_SFNT_V1;
59 typedef struct {
60 CHAR tag[4];
61 DWORD checkSum;
62 DWORD offset;
63 DWORD length;
64 } TT_TableRecord;
66 typedef struct {
67 WORD platformID;
68 WORD encodingID;
69 DWORD offset;
70 } CMAP_EncodingRecord;
72 typedef struct {
73 WORD version;
74 WORD numTables;
75 CMAP_EncodingRecord tables[1];
76 } CMAP_Header;
78 typedef struct {
79 DWORD startCharCode;
80 DWORD endCharCode;
81 DWORD startGlyphID;
82 } CMAP_SegmentedCoverage_group;
84 typedef struct {
85 WORD format;
86 WORD reserved;
87 DWORD length;
88 DWORD language;
89 DWORD nGroups;
90 CMAP_SegmentedCoverage_group groups[1];
91 } CMAP_SegmentedCoverage;
93 typedef struct {
94 WORD format;
95 WORD length;
96 WORD language;
97 WORD segCountX2;
98 WORD searchRange;
99 WORD entrySelector;
100 WORD rangeShift;
101 WORD endCode[1];
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"
112 typedef struct
114 ULONG version;
115 ULONG revision;
116 ULONG checksumadj;
117 ULONG magic;
118 USHORT flags;
119 USHORT unitsPerEm;
120 ULONGLONG created;
121 ULONGLONG modified;
122 SHORT xMin;
123 SHORT yMin;
124 SHORT xMax;
125 SHORT yMax;
126 USHORT macStyle;
127 USHORT lowestRecPPEM;
128 SHORT direction_hint;
129 SHORT index_format;
130 SHORT glyphdata_format;
131 } TT_HEAD;
133 typedef struct
135 ULONG Version;
136 ULONG italicAngle;
137 SHORT underlinePosition;
138 SHORT underlineThickness;
139 ULONG fixed_pitch;
140 ULONG minmemType42;
141 ULONG maxmemType42;
142 ULONG minmemType1;
143 ULONG maxmemType1;
144 } TT_POST;
146 typedef struct
148 USHORT version;
149 SHORT xAvgCharWidth;
150 USHORT usWeightClass;
151 USHORT usWidthClass;
152 SHORT fsType;
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;
163 SHORT sFamilyClass;
164 PANOSE panose;
165 ULONG ulUnicodeRange1;
166 ULONG ulUnicodeRange2;
167 ULONG ulUnicodeRange3;
168 ULONG ulUnicodeRange4;
169 CHAR achVendID[4];
170 USHORT fsSelection;
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;
179 USHORT sTypoLineGap;
180 USHORT usWinAscent;
181 USHORT usWinDescent;
182 /* version 1 (TrueType 1.66) */
183 ULONG ulCodePageRange1;
184 ULONG ulCodePageRange2;
185 /* version 2 (OpenType 1.2) */
186 SHORT sxHeight;
187 SHORT sCapHeight;
188 USHORT usDefaultChar;
189 USHORT usBreakChar;
190 USHORT usMaxContext;
191 } TT_OS2_V2;
193 typedef struct {
194 ULONG version;
195 SHORT ascender;
196 SHORT descender;
197 SHORT linegap;
198 USHORT advanceWidthMax;
199 SHORT minLeftSideBearing;
200 SHORT minRightSideBearing;
201 SHORT xMaxExtent;
202 SHORT caretSlopeRise;
203 SHORT caretSlopeRun;
204 SHORT caretOffset;
205 SHORT reserved[4];
206 SHORT metricDataFormat;
207 USHORT numberOfHMetrics;
208 } TT_HHEA;
210 #include "poppack.h"
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
225 typedef struct {
226 WORD platformID;
227 WORD encodingID;
228 WORD languageID;
229 WORD nameID;
230 WORD length;
231 WORD offset;
232 } TT_NameRecord;
234 typedef struct {
235 WORD format;
236 WORD count;
237 WORD stringOffset;
238 TT_NameRecord nameRecord[1];
239 } TT_NAME_V0;
241 typedef struct {
242 CHAR FeatureTag[4];
243 WORD Feature;
244 } OT_FeatureRecord;
246 typedef struct {
247 WORD FeatureCount;
248 OT_FeatureRecord FeatureRecord[1];
249 } OT_FeatureList;
251 typedef struct {
252 WORD LookupOrder; /* Reserved */
253 WORD ReqFeatureIndex;
254 WORD FeatureCount;
255 WORD FeatureIndex[1];
256 } OT_LangSys;
258 typedef struct {
259 CHAR LangSysTag[4];
260 WORD LangSys;
261 } OT_LangSysRecord;
263 typedef struct {
264 WORD DefaultLangSys;
265 WORD LangSysCount;
266 OT_LangSysRecord LangSysRecord[1];
267 } OT_Script;
269 typedef struct {
270 CHAR ScriptTag[4];
271 WORD Script;
272 } OT_ScriptRecord;
274 typedef struct {
275 WORD ScriptCount;
276 OT_ScriptRecord ScriptRecord[1];
277 } OT_ScriptList;
279 typedef struct {
280 DWORD version;
281 WORD ScriptList;
282 WORD FeatureList;
283 WORD LookupList;
284 } GPOS_GSUB_Header;
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] = {
471 "en-US",
472 "fr-FR",
473 "de-DE",
474 "it-IT",
475 "nl-NL",
476 "sv-SE",
477 "es-ES",
478 "da-DA",
479 "pt-PT",
480 "no-NO",
481 "he-IL",
482 "ja-JP",
483 "ar-AR",
484 "fi-FI",
485 "el-GR",
486 "is-IS",
487 "mt-MT",
488 "tr-TR",
489 "hr-HR",
490 "zh-HK",
491 "ur-PK",
492 "hi-IN",
493 "th-TH",
494 "ko-KR",
495 "lt-LT",
496 "pl-PL",
497 "hu-HU",
498 "et-EE",
499 "lv-LV",
500 "se-NO",
501 "fo-FO",
502 "fa-IR",
503 "ru-RU",
504 "zh-CN",
505 "nl-BE",
506 "gd-GB",
507 "sq-AL",
508 "ro-RO",
509 "cs-CZ",
510 "sk-SK",
511 "sl-SI",
513 "sr-Latn",
514 "mk-MK",
515 "bg-BG",
516 "uk-UA",
517 "be-BY",
518 "uz-Latn",
519 "kk-KZ",
520 "az-Cyrl-AZ",
521 "az-AZ",
522 "hy-AM",
523 "ka-GE",
526 "tg-TJ",
527 "tk-TM",
528 "mn-Mong",
529 "mn-MN",
530 "ps-AF",
531 "ku-Arab",
533 "sd-Arab",
534 "bo-CN",
535 "ne-NP",
536 "sa-IN",
537 "mr-IN",
538 "bn-IN",
539 "as-IN",
540 "gu-IN",
541 "pa-Arab",
542 "or-IN",
543 "ml-IN",
544 "kn-IN",
545 "ta-LK",
546 "te-IN",
547 "si-LK",
549 "km-KH",
550 "lo-LA",
551 "vi-VN",
552 "id-ID",
554 "ms-MY",
555 "ms-Arab",
556 "am-ET",
557 "ti-ET",
560 "sw-KE",
561 "rw-RW",
566 "cy-GB",
567 "eu-ES",
568 "ca-ES",
573 "tt-RU",
574 "ug-CN",
578 "gl-ES",
579 "af-ZA",
580 "br-FR",
581 "iu-Latn-CA",
582 "gd-GB",
584 "ga-IE",
587 "kl-GL",
588 "az-Latn"
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;
654 const char* tag;
655 void *context;
656 HRESULT hr;
658 hr = IDWriteFontFileStream_ReadFileFragment(stream, &font_data, 0, sizeof(TTC_Header_V1), &context);
659 if (FAILED(hr))
660 return hr;
662 tag = font_data;
663 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
664 face = DWRITE_FONT_FACE_TYPE_UNKNOWN;
665 *font_count = 0;
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)
676 *font_count = 1;
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;
686 if (face_type)
687 *face_type = face;
689 *supported = is_face_type_supported(face);
691 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
692 return S_OK;
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)
698 HRESULT hr;
699 TTC_SFNT_V1 *font_header = NULL;
700 void *sfnt_context;
701 TT_TableRecord *table_record = NULL;
702 void *table_record_context;
703 int table_count, table_offset = 0;
704 int i;
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;
711 void * ttc_context;
712 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context);
713 if (SUCCEEDED(hr)) {
714 table_offset = GET_BE_DWORD(ttc_header->OffsetTable[0]);
715 if (font_index >= GET_BE_DWORD(ttc_header->numFonts))
716 hr = E_INVALIDARG;
717 else
718 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context);
719 IDWriteFontFileStream_ReleaseFileFragment(stream, ttc_context);
722 else
723 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context);
725 if (FAILED(hr))
726 return hr;
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);
733 if (FAILED(hr))
734 break;
735 if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag)
736 break;
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);
753 return hr;
756 /**********
757 * CMAP
758 **********/
760 static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table)
762 UINT32 count = 0;
763 int i;
765 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) {
766 WORD type;
767 WORD *table;
769 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
770 continue;
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);
776 switch (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;
782 break;
784 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
786 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
787 count += GET_BE_DWORD(format->nGroups);
788 break;
790 default:
791 FIXME("table type %i unhandled.\n", type);
795 return count;
798 HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
800 CMAP_Header *CMAP_Table = data;
801 int i, k = 0;
803 if (!CMAP_Table)
804 return E_FAIL;
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++)
810 WORD type;
811 WORD *table;
812 int j;
814 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
815 continue;
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);
821 switch (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]);
833 break;
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);
842 break;
844 default:
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);
868 if (tt_head) {
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);
876 if (caret) {
877 if (tt_hhea) {
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);
882 else {
883 caret->slopeRise = 0;
884 caret->slopeRun = 0;
885 caret->offset = 0;
889 if (tt_os2) {
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 */
896 if (tt_hhea) {
897 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
898 INT32 linegap;
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 */
918 if (version >= 2) {
919 metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight);
920 metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight);
923 /* version 4 fields */
924 if (version >= 4) {
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;
935 if (tt_post) {
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;
946 if (tt_os2)
947 IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context);
948 if (tt_head)
949 IDWriteFontFileStream_ReleaseFileFragment(stream, head_context);
950 if (tt_post)
951 IDWriteFontFileStream_ReleaseFileFragment(stream, post_context);
952 if (tt_hhea)
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 */
972 if (tt_os2) {
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);
980 if (tt_head) {
981 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
982 if (macStyle & 0x0002)
983 *style = DWRITE_FONT_STYLE_ITALIC;
986 if (tt_os2)
987 IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context);
988 if (tt_head)
989 IDWriteFontFileStream_ReleaseFileFragment(stream, head_context);
992 static UINT get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform, USHORT encoding)
994 UINT codepage = 0;
996 switch (platform) {
997 case OPENTYPE_PLATFORM_UNICODE:
998 break;
999 case OPENTYPE_PLATFORM_MAC:
1000 switch (encoding)
1002 case TT_NAME_MAC_ENCODING_ROMAN:
1003 codepage = 10000;
1004 break;
1005 case TT_NAME_MAC_ENCODING_JAPANESE:
1006 codepage = 10001;
1007 break;
1008 case TT_NAME_MAC_ENCODING_TRAD_CHINESE:
1009 codepage = 10002;
1010 break;
1011 case TT_NAME_MAC_ENCODING_KOREAN:
1012 codepage = 10003;
1013 break;
1014 case TT_NAME_MAC_ENCODING_ARABIC:
1015 codepage = 10004;
1016 break;
1017 case TT_NAME_MAC_ENCODING_HEBREW:
1018 codepage = 10005;
1019 break;
1020 case TT_NAME_MAC_ENCODING_GREEK:
1021 codepage = 10006;
1022 break;
1023 case TT_NAME_MAC_ENCODING_RUSSIAN:
1024 codepage = 10007;
1025 break;
1026 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE:
1027 codepage = 10008;
1028 break;
1029 case TT_NAME_MAC_ENCODING_THAI:
1030 codepage = 10021;
1031 break;
1032 default:
1033 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1034 break;
1036 break;
1037 case OPENTYPE_PLATFORM_WIN:
1038 switch (encoding)
1040 case TT_NAME_WINDOWS_ENCODING_SYMBOL:
1041 case TT_NAME_WINDOWS_ENCODING_UCS2:
1042 break;
1043 case TT_NAME_WINDOWS_ENCODING_SJIS:
1044 codepage = 932;
1045 break;
1046 case TT_NAME_WINDOWS_ENCODING_PRC:
1047 codepage = 936;
1048 break;
1049 case TT_NAME_WINDOWS_ENCODING_BIG5:
1050 codepage = 950;
1051 break;
1052 case TT_NAME_WINDOWS_ENCODING_WANSUNG:
1053 codepage = 20949;
1054 break;
1055 case TT_NAME_WINDOWS_ENCODING_JOHAB:
1056 codepage = 1361;
1057 break;
1058 default:
1059 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1060 break;
1062 break;
1063 default:
1064 FIXME("unknown platform %d\n", platform);
1067 return codepage;
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};
1074 switch (platform) {
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);
1083 else
1084 locale_name = name_mac_langid_to_locale[lang_id];
1086 if (locale_name)
1087 MultiByteToWideChar(CP_ACP, 0, name_mac_langid_to_locale[lang_id], -1, locale, locale_len);
1088 else
1089 strcpyW(locale, enusW);
1090 break;
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);
1097 break;
1098 default:
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;
1107 USHORT count = 0;
1108 UINT16 name_id;
1109 BOOL exists;
1110 HRESULT hr;
1111 int i;
1113 if (!table_data)
1114 return E_FAIL;
1116 hr = create_localizedstrings(strings);
1117 if (FAILED(hr)) return hr;
1119 header = table_data;
1121 switch (header->format) {
1122 case 0:
1123 break;
1124 default:
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];
1133 exists = FALSE;
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)
1139 continue;
1141 exists = TRUE;
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);
1150 continue;
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)
1157 continue;
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];
1166 WCHAR *name_string;
1167 UINT codepage;
1169 codepage = get_name_record_codepage(platform, encoding);
1170 get_name_record_locale(platform, lang_id, locale, sizeof(locale)/sizeof(WCHAR));
1172 if (codepage) {
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;
1178 else {
1179 int i;
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);
1191 else {
1192 FIXME("handle NAME format 1\n");
1193 continue;
1197 if (!exists) {
1198 IDWriteLocalizedStrings_Release(*strings);
1199 *strings = NULL;
1202 return hr;
1205 static inline const OT_Script *opentype_get_script(const OT_ScriptList *scriptlist, UINT32 scripttag)
1207 UINT16 j;
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));
1215 return NULL;
1218 static inline const OT_LangSys *opentype_get_langsys(const OT_Script *script, UINT32 languagetag)
1220 UINT16 j;
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));
1228 return NULL;
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));
1235 UINT16 j;
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]);
1244 (*count)++;
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 };
1252 HRESULT hr;
1253 UINT8 i;
1255 *count = 0;
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;
1260 const void *ptr;
1261 void *context;
1262 UINT32 size;
1263 BOOL exists;
1265 exists = FALSE;
1266 hr = IDWriteFontFace_TryGetFontTable(fontface, tables[i], &ptr, &size, &context, &exists);
1267 if (FAILED(hr))
1268 return hr;
1270 if (!exists)
1271 continue;
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);
1277 if (script) {
1278 const OT_LangSys *langsys = opentype_get_langsys(script, languagetag);
1279 if (langsys)
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;