d3d8/tests: Introduce a helper function to test for WARP.
[wine.git] / dlls / dwrite / opentype.c
blob82e0a9c05d25fa4b010bd6714dac061d85399cf1
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"
24 #include "winternl.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
28 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
29 #define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
30 #define MS_OTTO_TAG DWRITE_MAKE_OPENTYPE_TAG('O','T','T','O')
31 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
32 #define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
33 #define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f')
34 #define MS_GPOS_TAG DWRITE_MAKE_OPENTYPE_TAG('G','P','O','S')
35 #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B')
36 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
38 #ifdef WORDS_BIGENDIAN
39 #define GET_BE_WORD(x) (x)
40 #define GET_BE_DWORD(x) (x)
41 #else
42 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
43 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
44 #endif
46 typedef struct {
47 CHAR TTCTag[4];
48 DWORD Version;
49 DWORD numFonts;
50 DWORD OffsetTable[1];
51 } TTC_Header_V1;
53 typedef struct {
54 DWORD version;
55 WORD numTables;
56 WORD searchRange;
57 WORD entrySelector;
58 WORD rangeShift;
59 } TTC_SFNT_V1;
61 typedef struct {
62 CHAR tag[4];
63 DWORD checkSum;
64 DWORD offset;
65 DWORD length;
66 } TT_TableRecord;
68 typedef struct {
69 WORD platformID;
70 WORD encodingID;
71 DWORD offset;
72 } CMAP_EncodingRecord;
74 typedef struct {
75 WORD version;
76 WORD numTables;
77 CMAP_EncodingRecord tables[1];
78 } CMAP_Header;
80 typedef struct {
81 DWORD startCharCode;
82 DWORD endCharCode;
83 DWORD startGlyphID;
84 } CMAP_SegmentedCoverage_group;
86 typedef struct {
87 WORD format;
88 WORD reserved;
89 DWORD length;
90 DWORD language;
91 DWORD nGroups;
92 CMAP_SegmentedCoverage_group groups[1];
93 } CMAP_SegmentedCoverage;
95 typedef struct {
96 WORD format;
97 WORD length;
98 WORD language;
99 WORD segCountX2;
100 WORD searchRange;
101 WORD entrySelector;
102 WORD rangeShift;
103 WORD endCode[1];
104 } CMAP_SegmentMapping_0;
106 enum OPENTYPE_CMAP_TABLE_FORMAT
108 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING = 4,
109 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE = 12
112 /* PANOSE is 10 bytes in size, need to pack the structure properly */
113 #include "pshpack2.h"
114 typedef struct
116 ULONG version;
117 ULONG revision;
118 ULONG checksumadj;
119 ULONG magic;
120 USHORT flags;
121 USHORT unitsPerEm;
122 ULONGLONG created;
123 ULONGLONG modified;
124 SHORT xMin;
125 SHORT yMin;
126 SHORT xMax;
127 SHORT yMax;
128 USHORT macStyle;
129 USHORT lowestRecPPEM;
130 SHORT direction_hint;
131 SHORT index_format;
132 SHORT glyphdata_format;
133 } TT_HEAD;
135 enum TT_HEAD_MACSTYLE
137 TT_HEAD_MACSTYLE_BOLD = 1 << 0,
138 TT_HEAD_MACSTYLE_ITALIC = 1 << 1,
139 TT_HEAD_MACSTYLE_UNDERLINE = 1 << 2,
140 TT_HEAD_MACSTYLE_OUTLINE = 1 << 3,
141 TT_HEAD_MACSTYLE_SHADOW = 1 << 4,
142 TT_HEAD_MACSTYLE_CONDENSED = 1 << 5,
143 TT_HEAD_MACSTYLE_EXTENDED = 1 << 6,
146 typedef struct
148 ULONG Version;
149 ULONG italicAngle;
150 SHORT underlinePosition;
151 SHORT underlineThickness;
152 ULONG fixed_pitch;
153 ULONG minmemType42;
154 ULONG maxmemType42;
155 ULONG minmemType1;
156 ULONG maxmemType1;
157 } TT_POST;
159 typedef struct
161 USHORT version;
162 SHORT xAvgCharWidth;
163 USHORT usWeightClass;
164 USHORT usWidthClass;
165 SHORT fsType;
166 SHORT ySubscriptXSize;
167 SHORT ySubscriptYSize;
168 SHORT ySubscriptXOffset;
169 SHORT ySubscriptYOffset;
170 SHORT ySuperscriptXSize;
171 SHORT ySuperscriptYSize;
172 SHORT ySuperscriptXOffset;
173 SHORT ySuperscriptYOffset;
174 SHORT yStrikeoutSize;
175 SHORT yStrikeoutPosition;
176 SHORT sFamilyClass;
177 PANOSE panose;
178 ULONG ulUnicodeRange1;
179 ULONG ulUnicodeRange2;
180 ULONG ulUnicodeRange3;
181 ULONG ulUnicodeRange4;
182 CHAR achVendID[4];
183 USHORT fsSelection;
184 USHORT usFirstCharIndex;
185 USHORT usLastCharIndex;
186 /* According to the Apple spec, original version didn't have the below fields,
187 * version numbers were taken from the OpenType spec.
189 /* version 0 (TrueType 1.5) */
190 USHORT sTypoAscender;
191 USHORT sTypoDescender;
192 USHORT sTypoLineGap;
193 USHORT usWinAscent;
194 USHORT usWinDescent;
195 /* version 1 (TrueType 1.66) */
196 ULONG ulCodePageRange1;
197 ULONG ulCodePageRange2;
198 /* version 2 (OpenType 1.2) */
199 SHORT sxHeight;
200 SHORT sCapHeight;
201 USHORT usDefaultChar;
202 USHORT usBreakChar;
203 USHORT usMaxContext;
204 } TT_OS2_V2;
206 typedef struct {
207 ULONG version;
208 SHORT ascender;
209 SHORT descender;
210 SHORT linegap;
211 USHORT advanceWidthMax;
212 SHORT minLeftSideBearing;
213 SHORT minRightSideBearing;
214 SHORT xMaxExtent;
215 SHORT caretSlopeRise;
216 SHORT caretSlopeRun;
217 SHORT caretOffset;
218 SHORT reserved[4];
219 SHORT metricDataFormat;
220 USHORT numberOfHMetrics;
221 } TT_HHEA;
223 #include "poppack.h"
225 enum OS2_FSSELECTION {
226 OS2_FSSELECTION_ITALIC = 1 << 0,
227 OS2_FSSELECTION_UNDERSCORE = 1 << 1,
228 OS2_FSSELECTION_NEGATIVE = 1 << 2,
229 OS2_FSSELECTION_OUTLINED = 1 << 3,
230 OS2_FSSELECTION_STRIKEOUT = 1 << 4,
231 OS2_FSSELECTION_BOLD = 1 << 5,
232 OS2_FSSELECTION_REGULAR = 1 << 6,
233 OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7,
234 OS2_FSSELECTION_WWS = 1 << 8,
235 OS2_FSSELECTION_OBLIQUE = 1 << 9
238 typedef struct {
239 WORD platformID;
240 WORD encodingID;
241 WORD languageID;
242 WORD nameID;
243 WORD length;
244 WORD offset;
245 } TT_NameRecord;
247 typedef struct {
248 WORD format;
249 WORD count;
250 WORD stringOffset;
251 TT_NameRecord nameRecord[1];
252 } TT_NAME_V0;
254 struct VDMX_Header
256 WORD version;
257 WORD numRecs;
258 WORD numRatios;
261 struct VDMX_Ratio
263 BYTE bCharSet;
264 BYTE xRatio;
265 BYTE yStartRatio;
266 BYTE yEndRatio;
269 struct VDMX_group
271 WORD recs;
272 BYTE startsz;
273 BYTE endsz;
276 struct VDMX_vTable
278 WORD yPelHeight;
279 SHORT yMax;
280 SHORT yMin;
283 typedef struct {
284 CHAR FeatureTag[4];
285 WORD Feature;
286 } OT_FeatureRecord;
288 typedef struct {
289 WORD FeatureCount;
290 OT_FeatureRecord FeatureRecord[1];
291 } OT_FeatureList;
293 typedef struct {
294 WORD LookupOrder; /* Reserved */
295 WORD ReqFeatureIndex;
296 WORD FeatureCount;
297 WORD FeatureIndex[1];
298 } OT_LangSys;
300 typedef struct {
301 CHAR LangSysTag[4];
302 WORD LangSys;
303 } OT_LangSysRecord;
305 typedef struct {
306 WORD DefaultLangSys;
307 WORD LangSysCount;
308 OT_LangSysRecord LangSysRecord[1];
309 } OT_Script;
311 typedef struct {
312 CHAR ScriptTag[4];
313 WORD Script;
314 } OT_ScriptRecord;
316 typedef struct {
317 WORD ScriptCount;
318 OT_ScriptRecord ScriptRecord[1];
319 } OT_ScriptList;
321 typedef struct {
322 DWORD version;
323 WORD ScriptList;
324 WORD FeatureList;
325 WORD LookupList;
326 } GPOS_GSUB_Header;
328 enum OPENTYPE_PLATFORM_ID
330 OPENTYPE_PLATFORM_UNICODE = 0,
331 OPENTYPE_PLATFORM_MAC,
332 OPENTYPE_PLATFORM_ISO,
333 OPENTYPE_PLATFORM_WIN,
334 OPENTYPE_PLATFORM_CUSTOM
337 enum TT_NAME_WINDOWS_ENCODING_ID
339 TT_NAME_WINDOWS_ENCODING_SYMBOL = 0,
340 TT_NAME_WINDOWS_ENCODING_UCS2,
341 TT_NAME_WINDOWS_ENCODING_SJIS,
342 TT_NAME_WINDOWS_ENCODING_PRC,
343 TT_NAME_WINDOWS_ENCODING_BIG5,
344 TT_NAME_WINDOWS_ENCODING_WANSUNG,
345 TT_NAME_WINDOWS_ENCODING_JOHAB,
346 TT_NAME_WINDOWS_ENCODING_RESERVED1,
347 TT_NAME_WINDOWS_ENCODING_RESERVED2,
348 TT_NAME_WINDOWS_ENCODING_RESERVED3,
349 TT_NAME_WINDOWS_ENCODING_UCS4
352 enum TT_NAME_MAC_ENCODING_ID
354 TT_NAME_MAC_ENCODING_ROMAN = 0,
355 TT_NAME_MAC_ENCODING_JAPANESE,
356 TT_NAME_MAC_ENCODING_TRAD_CHINESE,
357 TT_NAME_MAC_ENCODING_KOREAN,
358 TT_NAME_MAC_ENCODING_ARABIC,
359 TT_NAME_MAC_ENCODING_HEBREW,
360 TT_NAME_MAC_ENCODING_GREEK,
361 TT_NAME_MAC_ENCODING_RUSSIAN,
362 TT_NAME_MAC_ENCODING_RSYMBOL,
363 TT_NAME_MAC_ENCODING_DEVANAGARI,
364 TT_NAME_MAC_ENCODING_GURMUKHI,
365 TT_NAME_MAC_ENCODING_GUJARATI,
366 TT_NAME_MAC_ENCODING_ORIYA,
367 TT_NAME_MAC_ENCODING_BENGALI,
368 TT_NAME_MAC_ENCODING_TAMIL,
369 TT_NAME_MAC_ENCODING_TELUGU,
370 TT_NAME_MAC_ENCODING_KANNADA,
371 TT_NAME_MAC_ENCODING_MALAYALAM,
372 TT_NAME_MAC_ENCODING_SINHALESE,
373 TT_NAME_MAC_ENCODING_BURMESE,
374 TT_NAME_MAC_ENCODING_KHMER,
375 TT_NAME_MAC_ENCODING_THAI,
376 TT_NAME_MAC_ENCODING_LAOTIAN,
377 TT_NAME_MAC_ENCODING_GEORGIAN,
378 TT_NAME_MAC_ENCODING_ARMENIAN,
379 TT_NAME_MAC_ENCODING_SIMPL_CHINESE,
380 TT_NAME_MAC_ENCODING_TIBETAN,
381 TT_NAME_MAC_ENCODING_MONGOLIAN,
382 TT_NAME_MAC_ENCODING_GEEZ,
383 TT_NAME_MAC_ENCODING_SLAVIC,
384 TT_NAME_MAC_ENCODING_VIETNAMESE,
385 TT_NAME_MAC_ENCODING_SINDHI,
386 TT_NAME_MAC_ENCODING_UNINTERPRETED
389 enum TT_NAME_MAC_LANGUAGE_ID
391 TT_NAME_MAC_LANGID_ENGLISH = 0,
392 TT_NAME_MAC_LANGID_FRENCH,
393 TT_NAME_MAC_LANGID_GERMAN,
394 TT_NAME_MAC_LANGID_ITALIAN,
395 TT_NAME_MAC_LANGID_DUTCH,
396 TT_NAME_MAC_LANGID_SWEDISH,
397 TT_NAME_MAC_LANGID_SPANISH,
398 TT_NAME_MAC_LANGID_DANISH,
399 TT_NAME_MAC_LANGID_PORTUGUESE,
400 TT_NAME_MAC_LANGID_NORWEGIAN,
401 TT_NAME_MAC_LANGID_HEBREW,
402 TT_NAME_MAC_LANGID_JAPANESE,
403 TT_NAME_MAC_LANGID_ARABIC,
404 TT_NAME_MAC_LANGID_FINNISH,
405 TT_NAME_MAC_LANGID_GREEK,
406 TT_NAME_MAC_LANGID_ICELANDIC,
407 TT_NAME_MAC_LANGID_MALTESE,
408 TT_NAME_MAC_LANGID_TURKISH,
409 TT_NAME_MAC_LANGID_CROATIAN,
410 TT_NAME_MAC_LANGID_TRAD_CHINESE,
411 TT_NAME_MAC_LANGID_URDU,
412 TT_NAME_MAC_LANGID_HINDI,
413 TT_NAME_MAC_LANGID_THAI,
414 TT_NAME_MAC_LANGID_KOREAN,
415 TT_NAME_MAC_LANGID_LITHUANIAN,
416 TT_NAME_MAC_LANGID_POLISH,
417 TT_NAME_MAC_LANGID_HUNGARIAN,
418 TT_NAME_MAC_LANGID_ESTONIAN,
419 TT_NAME_MAC_LANGID_LATVIAN,
420 TT_NAME_MAC_LANGID_SAMI,
421 TT_NAME_MAC_LANGID_FAROESE,
422 TT_NAME_MAC_LANGID_FARSI,
423 TT_NAME_MAC_LANGID_RUSSIAN,
424 TT_NAME_MAC_LANGID_SIMPL_CHINESE,
425 TT_NAME_MAC_LANGID_FLEMISH,
426 TT_NAME_MAC_LANGID_GAELIC,
427 TT_NAME_MAC_LANGID_ALBANIAN,
428 TT_NAME_MAC_LANGID_ROMANIAN,
429 TT_NAME_MAC_LANGID_CZECH,
430 TT_NAME_MAC_LANGID_SLOVAK,
431 TT_NAME_MAC_LANGID_SLOVENIAN,
432 TT_NAME_MAC_LANGID_YIDDISH,
433 TT_NAME_MAC_LANGID_SERBIAN,
434 TT_NAME_MAC_LANGID_MACEDONIAN,
435 TT_NAME_MAC_LANGID_BULGARIAN,
436 TT_NAME_MAC_LANGID_UKRAINIAN,
437 TT_NAME_MAC_LANGID_BYELORUSSIAN,
438 TT_NAME_MAC_LANGID_UZBEK,
439 TT_NAME_MAC_LANGID_KAZAKH,
440 TT_NAME_MAC_LANGID_AZERB_CYR,
441 TT_NAME_MAC_LANGID_AZERB_ARABIC,
442 TT_NAME_MAC_LANGID_ARMENIAN,
443 TT_NAME_MAC_LANGID_GEORGIAN,
444 TT_NAME_MAC_LANGID_MOLDAVIAN,
445 TT_NAME_MAC_LANGID_KIRGHIZ,
446 TT_NAME_MAC_LANGID_TAJIKI,
447 TT_NAME_MAC_LANGID_TURKMEN,
448 TT_NAME_MAC_LANGID_MONGOLIAN,
449 TT_NAME_MAC_LANGID_MONGOLIAN_CYR,
450 TT_NAME_MAC_LANGID_PASHTO,
451 TT_NAME_MAC_LANGID_KURDISH,
452 TT_NAME_MAC_LANGID_KASHMIRI,
453 TT_NAME_MAC_LANGID_SINDHI,
454 TT_NAME_MAC_LANGID_TIBETAN,
455 TT_NAME_MAC_LANGID_NEPALI,
456 TT_NAME_MAC_LANGID_SANSKRIT,
457 TT_NAME_MAC_LANGID_MARATHI,
458 TT_NAME_MAC_LANGID_BENGALI,
459 TT_NAME_MAC_LANGID_ASSAMESE,
460 TT_NAME_MAC_LANGID_GUJARATI,
461 TT_NAME_MAC_LANGID_PUNJABI,
462 TT_NAME_MAC_LANGID_ORIYA,
463 TT_NAME_MAC_LANGID_MALAYALAM,
464 TT_NAME_MAC_LANGID_KANNADA,
465 TT_NAME_MAC_LANGID_TAMIL,
466 TT_NAME_MAC_LANGID_TELUGU,
467 TT_NAME_MAC_LANGID_SINHALESE,
468 TT_NAME_MAC_LANGID_BURMESE,
469 TT_NAME_MAC_LANGID_KHMER,
470 TT_NAME_MAC_LANGID_LAO,
471 TT_NAME_MAC_LANGID_VIETNAMESE,
472 TT_NAME_MAC_LANGID_INDONESIAN,
473 TT_NAME_MAC_LANGID_TAGALONG,
474 TT_NAME_MAC_LANGID_MALAY_ROMAN,
475 TT_NAME_MAC_LANGID_MALAY_ARABIC,
476 TT_NAME_MAC_LANGID_AMHARIC,
477 TT_NAME_MAC_LANGID_TIGRINYA,
478 TT_NAME_MAC_LANGID_GALLA,
479 TT_NAME_MAC_LANGID_SOMALI,
480 TT_NAME_MAC_LANGID_SWAHILI,
481 TT_NAME_MAC_LANGID_KINYARWANDA,
482 TT_NAME_MAC_LANGID_RUNDI,
483 TT_NAME_MAC_LANGID_NYANJA,
484 TT_NAME_MAC_LANGID_MALAGASY,
485 TT_NAME_MAC_LANGID_ESPERANTO,
486 TT_NAME_MAC_LANGID_WELSH,
487 TT_NAME_MAC_LANGID_BASQUE,
488 TT_NAME_MAC_LANGID_CATALAN,
489 TT_NAME_MAC_LANGID_LATIN,
490 TT_NAME_MAC_LANGID_QUENCHUA,
491 TT_NAME_MAC_LANGID_GUARANI,
492 TT_NAME_MAC_LANGID_AYMARA,
493 TT_NAME_MAC_LANGID_TATAR,
494 TT_NAME_MAC_LANGID_UIGHUR,
495 TT_NAME_MAC_LANGID_DZONGKHA,
496 TT_NAME_MAC_LANGID_JAVANESE,
497 TT_NAME_MAC_LANGID_SUNDANESE,
498 TT_NAME_MAC_LANGID_GALICIAN,
499 TT_NAME_MAC_LANGID_AFRIKAANS,
500 TT_NAME_MAC_LANGID_BRETON,
501 TT_NAME_MAC_LANGID_INUKTITUT,
502 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC,
503 TT_NAME_MAC_LANGID_MANX_GAELIC,
504 TT_NAME_MAC_LANGID_IRISH_GAELIC,
505 TT_NAME_MAC_LANGID_TONGAN,
506 TT_NAME_MAC_LANGID_GREEK_POLYTONIC,
507 TT_NAME_MAC_LANGID_GREENLANDIC,
508 TT_NAME_MAC_LANGID_AZER_ROMAN
511 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
512 static const char name_mac_langid_to_locale[][10] = {
513 "en-US",
514 "fr-FR",
515 "de-DE",
516 "it-IT",
517 "nl-NL",
518 "sv-SE",
519 "es-ES",
520 "da-DA",
521 "pt-PT",
522 "no-NO",
523 "he-IL",
524 "ja-JP",
525 "ar-AR",
526 "fi-FI",
527 "el-GR",
528 "is-IS",
529 "mt-MT",
530 "tr-TR",
531 "hr-HR",
532 "zh-HK",
533 "ur-PK",
534 "hi-IN",
535 "th-TH",
536 "ko-KR",
537 "lt-LT",
538 "pl-PL",
539 "hu-HU",
540 "et-EE",
541 "lv-LV",
542 "se-NO",
543 "fo-FO",
544 "fa-IR",
545 "ru-RU",
546 "zh-CN",
547 "nl-BE",
548 "gd-GB",
549 "sq-AL",
550 "ro-RO",
551 "cs-CZ",
552 "sk-SK",
553 "sl-SI",
555 "sr-Latn",
556 "mk-MK",
557 "bg-BG",
558 "uk-UA",
559 "be-BY",
560 "uz-Latn",
561 "kk-KZ",
562 "az-Cyrl-AZ",
563 "az-AZ",
564 "hy-AM",
565 "ka-GE",
568 "tg-TJ",
569 "tk-TM",
570 "mn-Mong",
571 "mn-MN",
572 "ps-AF",
573 "ku-Arab",
575 "sd-Arab",
576 "bo-CN",
577 "ne-NP",
578 "sa-IN",
579 "mr-IN",
580 "bn-IN",
581 "as-IN",
582 "gu-IN",
583 "pa-Arab",
584 "or-IN",
585 "ml-IN",
586 "kn-IN",
587 "ta-LK",
588 "te-IN",
589 "si-LK",
591 "km-KH",
592 "lo-LA",
593 "vi-VN",
594 "id-ID",
596 "ms-MY",
597 "ms-Arab",
598 "am-ET",
599 "ti-ET",
602 "sw-KE",
603 "rw-RW",
608 "cy-GB",
609 "eu-ES",
610 "ca-ES",
615 "tt-RU",
616 "ug-CN",
620 "gl-ES",
621 "af-ZA",
622 "br-FR",
623 "iu-Latn-CA",
624 "gd-GB",
626 "ga-IE",
629 "kl-GL",
630 "az-Latn"
633 enum OPENTYPE_STRING_ID
635 OPENTYPE_STRING_COPYRIGHT_NOTICE = 0,
636 OPENTYPE_STRING_FAMILY_NAME,
637 OPENTYPE_STRING_SUBFAMILY_NAME,
638 OPENTYPE_STRING_UNIQUE_IDENTIFIER,
639 OPENTYPE_STRING_FULL_FONTNAME,
640 OPENTYPE_STRING_VERSION_STRING,
641 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
642 OPENTYPE_STRING_TRADEMARK,
643 OPENTYPE_STRING_MANUFACTURER,
644 OPENTYPE_STRING_DESIGNER,
645 OPENTYPE_STRING_DESCRIPTION,
646 OPENTYPE_STRING_VENDOR_URL,
647 OPENTYPE_STRING_DESIGNER_URL,
648 OPENTYPE_STRING_LICENSE_DESCRIPTION,
649 OPENTYPE_STRING_LICENSE_INFO_URL,
650 OPENTYPE_STRING_RESERVED_ID15,
651 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
652 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
653 OPENTYPE_STRING_COMPATIBLE_FULLNAME,
654 OPENTYPE_STRING_SAMPLE_TEXT,
655 OPENTYPE_STRING_POSTSCRIPT_CID_NAME,
656 OPENTYPE_STRING_WWS_FAMILY_NAME,
657 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
660 static const UINT16 dwriteid_to_opentypeid[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1] =
662 (UINT16)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
663 OPENTYPE_STRING_COPYRIGHT_NOTICE,
664 OPENTYPE_STRING_VERSION_STRING,
665 OPENTYPE_STRING_TRADEMARK,
666 OPENTYPE_STRING_MANUFACTURER,
667 OPENTYPE_STRING_DESIGNER,
668 OPENTYPE_STRING_DESIGNER_URL,
669 OPENTYPE_STRING_DESCRIPTION,
670 OPENTYPE_STRING_VENDOR_URL,
671 OPENTYPE_STRING_LICENSE_DESCRIPTION,
672 OPENTYPE_STRING_LICENSE_INFO_URL,
673 OPENTYPE_STRING_FAMILY_NAME,
674 OPENTYPE_STRING_SUBFAMILY_NAME,
675 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
676 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
677 OPENTYPE_STRING_SAMPLE_TEXT,
678 OPENTYPE_STRING_FULL_FONTNAME,
679 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
680 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
683 /* CPAL table */
684 struct CPAL_Header_0
686 USHORT version;
687 USHORT numPaletteEntries;
688 USHORT numPalette;
689 USHORT numColorRecords;
690 ULONG offsetFirstColorRecord;
691 USHORT colorRecordIndices[1];
694 /* for version == 1, this comes after full CPAL_Header_0 */
695 struct CPAL_SubHeader_1
697 ULONG offsetPaletteTypeArray;
698 ULONG offsetPaletteLabelArray;
699 ULONG offsetPaletteEntryLabelArray;
702 struct CPAL_ColorRecord
704 BYTE blue;
705 BYTE green;
706 BYTE red;
707 BYTE alpha;
710 BOOL is_face_type_supported(DWRITE_FONT_FACE_TYPE type)
712 return (type == DWRITE_FONT_FACE_TYPE_CFF) ||
713 (type == DWRITE_FONT_FACE_TYPE_TRUETYPE) ||
714 (type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) ||
715 (type == DWRITE_FONT_FACE_TYPE_RAW_CFF);
718 HRESULT opentype_analyze_font(IDWriteFontFileStream *stream, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported)
720 /* TODO: Do font validation */
721 DWRITE_FONT_FACE_TYPE face;
722 const void *font_data;
723 const char* tag;
724 void *context;
725 HRESULT hr;
727 hr = IDWriteFontFileStream_ReadFileFragment(stream, &font_data, 0, sizeof(TTC_Header_V1), &context);
728 if (FAILED(hr))
729 return hr;
731 tag = font_data;
732 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
733 face = DWRITE_FONT_FACE_TYPE_UNKNOWN;
734 *font_count = 0;
736 if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_TTCF_TAG)
738 const TTC_Header_V1 *header = font_data;
739 *font_count = GET_BE_DWORD(header->numFonts);
740 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION;
741 face = DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION;
743 else if (GET_BE_DWORD(*(DWORD*)font_data) == 0x10000)
745 *font_count = 1;
746 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
747 face = DWRITE_FONT_FACE_TYPE_TRUETYPE;
749 else if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_OTTO_TAG)
751 *file_type = DWRITE_FONT_FILE_TYPE_CFF;
752 face = DWRITE_FONT_FACE_TYPE_CFF;
755 if (face_type)
756 *face_type = face;
758 *supported = is_face_type_supported(face);
760 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
761 return S_OK;
764 HRESULT opentype_get_font_table(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE type, UINT32 font_index, UINT32 tag,
765 const void **table_data, void **table_context, UINT32 *table_size, BOOL *found)
767 HRESULT hr;
768 TTC_SFNT_V1 *font_header = NULL;
769 void *sfnt_context;
770 TT_TableRecord *table_record = NULL;
771 void *table_record_context;
772 int table_count, table_offset = 0;
773 int i;
775 if (found) *found = FALSE;
776 if (table_size) *table_size = 0;
778 if (type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) {
779 const TTC_Header_V1 *ttc_header;
780 void * ttc_context;
781 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context);
782 if (SUCCEEDED(hr)) {
783 if (font_index >= GET_BE_DWORD(ttc_header->numFonts))
784 hr = E_INVALIDARG;
785 else {
786 table_offset = GET_BE_DWORD(ttc_header->OffsetTable[font_index]);
787 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context);
789 IDWriteFontFileStream_ReleaseFileFragment(stream, ttc_context);
792 else
793 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context);
795 if (FAILED(hr))
796 return hr;
798 table_count = GET_BE_WORD(font_header->numTables);
799 table_offset += sizeof(*font_header);
800 for (i = 0; i < table_count; i++)
802 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&table_record, table_offset, sizeof(*table_record), &table_record_context);
803 if (FAILED(hr))
804 break;
805 if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag)
806 break;
807 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
808 table_offset += sizeof(*table_record);
811 IDWriteFontFileStream_ReleaseFileFragment(stream, sfnt_context);
812 if (SUCCEEDED(hr) && i < table_count)
814 int offset = GET_BE_DWORD(table_record->offset);
815 int length = GET_BE_DWORD(table_record->length);
816 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
818 if (found) *found = TRUE;
819 if (table_size) *table_size = length;
820 hr = IDWriteFontFileStream_ReadFileFragment(stream, table_data, offset, length, table_context);
823 return hr;
826 /**********
827 * CMAP
828 **********/
830 static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table)
832 UINT32 count = 0;
833 int i;
835 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) {
836 WORD type;
837 WORD *table;
839 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
840 continue;
842 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
843 type = GET_BE_WORD(*table);
844 TRACE("table type %i\n", type);
846 switch (type)
848 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
850 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
851 count += GET_BE_WORD(format->segCountX2)/2;
852 break;
854 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
856 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
857 count += GET_BE_DWORD(format->nGroups);
858 break;
860 default:
861 FIXME("table type %i unhandled.\n", type);
865 return count;
868 HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
870 CMAP_Header *CMAP_Table = data;
871 int i, k = 0;
873 if (!CMAP_Table)
874 return E_FAIL;
876 *count = opentype_cmap_get_unicode_ranges_count(CMAP_Table);
878 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables) && k < max_count; i++)
880 WORD type;
881 WORD *table;
882 int j;
884 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
885 continue;
887 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
888 type = GET_BE_WORD(*table);
889 TRACE("table type %i\n", type);
891 switch (type)
893 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
895 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
896 UINT16 segment_count = GET_BE_WORD(format->segCountX2)/2;
897 UINT16 *startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
899 for (j = 0; j < segment_count && GET_BE_WORD(format->endCode[j]) < 0xffff && k < max_count; j++, k++) {
900 ranges[k].first = GET_BE_WORD(startCode[j]);
901 ranges[k].last = GET_BE_WORD(format->endCode[j]);
903 break;
905 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
907 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
908 for (j = 0; j < GET_BE_DWORD(format->nGroups) && k < max_count; j++, k++) {
909 ranges[k].first = GET_BE_DWORD(format->groups[j].startCharCode);
910 ranges[k].last = GET_BE_DWORD(format->groups[j].endCharCode);
912 break;
914 default:
915 FIXME("table type %i unhandled.\n", type);
919 return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK;
922 void opentype_get_font_metrics(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index,
923 DWRITE_FONT_METRICS1 *metrics, DWRITE_CARET_METRICS *caret)
925 void *os2_context, *head_context, *post_context, *hhea_context;
926 const TT_OS2_V2 *tt_os2;
927 const TT_HEAD *tt_head;
928 const TT_POST *tt_post;
929 const TT_HHEA *tt_hhea;
931 memset(metrics, 0, sizeof(*metrics));
933 opentype_get_font_table(stream, face_type, face_index, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
934 opentype_get_font_table(stream, face_type, face_index, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
935 opentype_get_font_table(stream, face_type, face_index, MS_POST_TAG, (const void**)&tt_post, &post_context, NULL, NULL);
936 opentype_get_font_table(stream, face_type, face_index, MS_HHEA_TAG, (const void**)&tt_hhea, &hhea_context, NULL, NULL);
938 if (tt_head) {
939 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
940 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
941 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
942 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
943 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
946 if (caret) {
947 if (tt_hhea) {
948 caret->slopeRise = GET_BE_WORD(tt_hhea->caretSlopeRise);
949 caret->slopeRun = GET_BE_WORD(tt_hhea->caretSlopeRun);
950 caret->offset = GET_BE_WORD(tt_hhea->caretOffset);
952 else {
953 caret->slopeRise = 0;
954 caret->slopeRun = 0;
955 caret->offset = 0;
959 if (tt_os2) {
960 USHORT version = GET_BE_WORD(tt_os2->version);
962 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
963 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
964 interpreted as large unsigned value. */
965 metrics->descent = abs((SHORT)GET_BE_WORD(tt_os2->usWinDescent));
967 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
968 if (tt_hhea) {
969 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
970 INT32 linegap;
972 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
973 metrics->ascent - metrics->descent;
974 metrics->lineGap = linegap > 0 ? linegap : 0;
977 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
978 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
979 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
980 /* Y offset is stored as positive offset below baseline */
981 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
982 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
983 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
984 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
985 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
986 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
987 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
989 /* version 2 fields */
990 if (version >= 2) {
991 metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight);
992 metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight);
995 /* version 4 fields */
996 if (version >= 4) {
997 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
998 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
999 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
1000 metrics->descent = descent < 0 ? -descent : 0;
1001 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
1002 metrics->hasTypographicMetrics = TRUE;
1007 if (tt_post) {
1008 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
1009 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
1012 /* estimate missing metrics */
1013 if (metrics->xHeight == 0)
1014 metrics->xHeight = metrics->designUnitsPerEm / 2;
1015 if (metrics->capHeight == 0)
1016 metrics->capHeight = metrics->designUnitsPerEm * 7 / 10;
1018 if (tt_os2)
1019 IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context);
1020 if (tt_head)
1021 IDWriteFontFileStream_ReleaseFileFragment(stream, head_context);
1022 if (tt_post)
1023 IDWriteFontFileStream_ReleaseFileFragment(stream, post_context);
1024 if (tt_hhea)
1025 IDWriteFontFileStream_ReleaseFileFragment(stream, hhea_context);
1028 void opentype_get_font_properties(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE type, UINT32 index,
1029 struct dwrite_font_props *props)
1031 void *os2_context, *head_context;
1032 const TT_OS2_V2 *tt_os2;
1033 const TT_HEAD *tt_head;
1035 opentype_get_font_table(stream, type, index, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1036 opentype_get_font_table(stream, type, index, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
1038 /* default stretch, weight and style to normal */
1039 props->stretch = DWRITE_FONT_STRETCH_NORMAL;
1040 props->weight = DWRITE_FONT_WEIGHT_NORMAL;
1041 props->style = DWRITE_FONT_STYLE_NORMAL;
1042 memset(&props->panose, 0, sizeof(props->panose));
1044 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1045 if (tt_os2) {
1046 USHORT version = GET_BE_WORD(tt_os2->version);
1047 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
1048 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
1050 if (GET_BE_WORD(tt_os2->usWidthClass) <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
1051 props->stretch = GET_BE_WORD(tt_os2->usWidthClass);
1053 if (usWeightClass >= 1 && usWeightClass <= 9)
1054 usWeightClass *= 100;
1056 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
1057 props->weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
1058 else
1059 props->weight = usWeightClass;
1061 if (version >= 4 && (fsSelection & OS2_FSSELECTION_OBLIQUE))
1062 props->style = DWRITE_FONT_STYLE_OBLIQUE;
1063 else if (fsSelection & OS2_FSSELECTION_ITALIC)
1064 props->style = DWRITE_FONT_STYLE_ITALIC;
1065 memcpy(&props->panose, &tt_os2->panose, sizeof(props->panose));
1067 else if (tt_head) {
1068 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
1070 if (macStyle & TT_HEAD_MACSTYLE_CONDENSED)
1071 props->stretch = DWRITE_FONT_STRETCH_CONDENSED;
1072 else if (macStyle & TT_HEAD_MACSTYLE_EXTENDED)
1073 props->stretch = DWRITE_FONT_STRETCH_EXPANDED;
1075 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
1076 props->weight = DWRITE_FONT_WEIGHT_BOLD;
1078 if (macStyle & TT_HEAD_MACSTYLE_ITALIC)
1079 props->style = DWRITE_FONT_STYLE_ITALIC;
1082 TRACE("stretch=%d, weight=%d, style %d\n", props->stretch, props->weight, props->style);
1084 if (tt_os2)
1085 IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context);
1086 if (tt_head)
1087 IDWriteFontFileStream_ReleaseFileFragment(stream, head_context);
1090 static UINT get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform, USHORT encoding)
1092 UINT codepage = 0;
1094 switch (platform) {
1095 case OPENTYPE_PLATFORM_UNICODE:
1096 break;
1097 case OPENTYPE_PLATFORM_MAC:
1098 switch (encoding)
1100 case TT_NAME_MAC_ENCODING_ROMAN:
1101 codepage = 10000;
1102 break;
1103 case TT_NAME_MAC_ENCODING_JAPANESE:
1104 codepage = 10001;
1105 break;
1106 case TT_NAME_MAC_ENCODING_TRAD_CHINESE:
1107 codepage = 10002;
1108 break;
1109 case TT_NAME_MAC_ENCODING_KOREAN:
1110 codepage = 10003;
1111 break;
1112 case TT_NAME_MAC_ENCODING_ARABIC:
1113 codepage = 10004;
1114 break;
1115 case TT_NAME_MAC_ENCODING_HEBREW:
1116 codepage = 10005;
1117 break;
1118 case TT_NAME_MAC_ENCODING_GREEK:
1119 codepage = 10006;
1120 break;
1121 case TT_NAME_MAC_ENCODING_RUSSIAN:
1122 codepage = 10007;
1123 break;
1124 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE:
1125 codepage = 10008;
1126 break;
1127 case TT_NAME_MAC_ENCODING_THAI:
1128 codepage = 10021;
1129 break;
1130 default:
1131 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1132 break;
1134 break;
1135 case OPENTYPE_PLATFORM_WIN:
1136 switch (encoding)
1138 case TT_NAME_WINDOWS_ENCODING_SYMBOL:
1139 case TT_NAME_WINDOWS_ENCODING_UCS2:
1140 break;
1141 case TT_NAME_WINDOWS_ENCODING_SJIS:
1142 codepage = 932;
1143 break;
1144 case TT_NAME_WINDOWS_ENCODING_PRC:
1145 codepage = 936;
1146 break;
1147 case TT_NAME_WINDOWS_ENCODING_BIG5:
1148 codepage = 950;
1149 break;
1150 case TT_NAME_WINDOWS_ENCODING_WANSUNG:
1151 codepage = 20949;
1152 break;
1153 case TT_NAME_WINDOWS_ENCODING_JOHAB:
1154 codepage = 1361;
1155 break;
1156 default:
1157 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1158 break;
1160 break;
1161 default:
1162 FIXME("unknown platform %d\n", platform);
1165 return codepage;
1168 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform, USHORT lang_id, WCHAR *locale, USHORT locale_len)
1170 static const WCHAR enusW[] = {'e','n','-','U','S',0};
1172 switch (platform) {
1173 case OPENTYPE_PLATFORM_MAC:
1175 const char *locale_name = NULL;
1177 if (lang_id > TT_NAME_MAC_LANGID_AZER_ROMAN)
1178 ERR("invalid mac lang id %d\n", lang_id);
1179 else if (!name_mac_langid_to_locale[lang_id][0])
1180 FIXME("failed to map mac lang id %d to locale name\n", lang_id);
1181 else
1182 locale_name = name_mac_langid_to_locale[lang_id];
1184 if (locale_name)
1185 MultiByteToWideChar(CP_ACP, 0, name_mac_langid_to_locale[lang_id], -1, locale, locale_len);
1186 else
1187 strcpyW(locale, enusW);
1188 break;
1190 case OPENTYPE_PLATFORM_WIN:
1191 if (!LCIDToLocaleName(MAKELCID(lang_id, SORT_DEFAULT), locale, locale_len, 0)) {
1192 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id, SORT_DEFAULT));
1193 strcpyW(locale, enusW);
1195 break;
1196 default:
1197 FIXME("unknown platform %d\n", platform);
1201 static HRESULT opentype_get_font_strings_from_id(const void *table_data, enum OPENTYPE_STRING_ID id, IDWriteLocalizedStrings **strings)
1203 const TT_NAME_V0 *header;
1204 BYTE *storage_area = 0;
1205 USHORT count = 0;
1206 WORD format;
1207 BOOL exists;
1208 HRESULT hr;
1209 int i;
1211 if (!table_data)
1212 return E_FAIL;
1214 hr = create_localizedstrings(strings);
1215 if (FAILED(hr)) return hr;
1217 header = table_data;
1218 format = GET_BE_WORD(header->format);
1220 switch (format) {
1221 case 0:
1222 case 1:
1223 break;
1224 default:
1225 FIXME("unsupported NAME format %d\n", format);
1229 storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset);
1230 count = GET_BE_WORD(header->count);
1232 exists = FALSE;
1233 for (i = 0; i < count; i++) {
1234 const TT_NameRecord *record = &header->nameRecord[i];
1235 USHORT lang_id, length, offset, encoding, platform;
1237 if (GET_BE_WORD(record->nameID) != id)
1238 continue;
1240 exists = TRUE;
1242 /* Right now only accept unicode and windows encoded fonts */
1243 platform = GET_BE_WORD(record->platformID);
1244 if (platform != OPENTYPE_PLATFORM_UNICODE &&
1245 platform != OPENTYPE_PLATFORM_MAC &&
1246 platform != OPENTYPE_PLATFORM_WIN)
1248 FIXME("platform %i not supported\n", platform);
1249 continue;
1252 /* Skip such entries for now, as it's not clear which locale is implied when
1253 unicode platform is used. Also fonts tend to duplicate those strings as
1254 WIN platform entries. */
1255 if (platform == OPENTYPE_PLATFORM_UNICODE)
1256 continue;
1258 lang_id = GET_BE_WORD(record->languageID);
1259 length = GET_BE_WORD(record->length);
1260 offset = GET_BE_WORD(record->offset);
1261 encoding = GET_BE_WORD(record->encodingID);
1263 if (lang_id < 0x8000) {
1264 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
1265 WCHAR *name_string;
1266 UINT codepage;
1268 codepage = get_name_record_codepage(platform, encoding);
1269 get_name_record_locale(platform, lang_id, locale, sizeof(locale)/sizeof(WCHAR));
1271 if (codepage) {
1272 DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0);
1273 name_string = heap_alloc(sizeof(WCHAR) * (len+1));
1274 MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len);
1275 name_string[len] = 0;
1277 else {
1278 int i;
1280 length /= sizeof(WCHAR);
1281 name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length);
1282 for (i = 0; i < length; i++)
1283 name_string[i] = GET_BE_WORD(name_string[i]);
1286 TRACE("string %s for locale %s found\n", debugstr_w(name_string), debugstr_w(locale));
1287 add_localizedstring(*strings, locale, name_string);
1288 heap_free(name_string);
1290 else {
1291 FIXME("handle NAME format 1\n");
1292 continue;
1296 if (!exists) {
1297 IDWriteLocalizedStrings_Release(*strings);
1298 *strings = NULL;
1301 return exists ? S_OK : E_FAIL;
1304 /* Provides a conversion from DWRITE to OpenType name ids, input id be valid, it's not checked. */
1305 HRESULT opentype_get_font_info_strings(const void *table_data, DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings)
1307 return opentype_get_font_strings_from_id(table_data, dwriteid_to_opentypeid[id], strings);
1310 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
1311 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
1312 HRESULT opentype_get_font_familyname(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE facetype, UINT32 index,
1313 IDWriteLocalizedStrings **names)
1315 const TT_OS2_V2 *tt_os2;
1316 void *os2_context, *name_context;
1317 const void *name_table;
1318 HRESULT hr;
1320 opentype_get_font_table(stream, facetype, index, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1321 opentype_get_font_table(stream, facetype, index, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1323 *names = NULL;
1325 /* if Preferred Family doesn't conform to WWS model try WWS name */
1326 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1327 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_FAMILY_NAME, names);
1328 else
1329 hr = E_FAIL;
1331 if (FAILED(hr))
1332 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_FAMILY_NAME, names);
1333 if (FAILED(hr))
1334 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, names);
1336 if (tt_os2)
1337 IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context);
1338 if (name_context)
1339 IDWriteFontFileStream_ReleaseFileFragment(stream, name_context);
1341 return hr;
1344 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
1345 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
1346 HRESULT opentype_get_font_facename(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE facetype, UINT32 index,
1347 IDWriteLocalizedStrings **names)
1349 const TT_OS2_V2 *tt_os2;
1350 void *os2_context, *name_context;
1351 const void *name_table;
1352 HRESULT hr;
1354 opentype_get_font_table(stream, facetype, index, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1355 opentype_get_font_table(stream, facetype, index, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1357 *names = NULL;
1359 /* if Preferred Family doesn't conform to WWS model try WWS name */
1360 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1361 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_SUBFAMILY_NAME, names);
1362 else
1363 hr = E_FAIL;
1365 if (FAILED(hr))
1366 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME, names);
1367 if (FAILED(hr))
1368 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_SUBFAMILY_NAME, names);
1370 if (tt_os2)
1371 IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context);
1372 if (name_context)
1373 IDWriteFontFileStream_ReleaseFileFragment(stream, name_context);
1375 return hr;
1378 static inline const OT_Script *opentype_get_script(const OT_ScriptList *scriptlist, UINT32 scripttag)
1380 UINT16 j;
1382 for (j = 0; j < GET_BE_WORD(scriptlist->ScriptCount); j++) {
1383 const char *tag = scriptlist->ScriptRecord[j].ScriptTag;
1384 if (scripttag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1385 return (OT_Script*)((BYTE*)scriptlist + GET_BE_WORD(scriptlist->ScriptRecord[j].Script));
1388 return NULL;
1391 static inline const OT_LangSys *opentype_get_langsys(const OT_Script *script, UINT32 languagetag)
1393 UINT16 j;
1395 for (j = 0; j < GET_BE_WORD(script->LangSysCount); j++) {
1396 const char *tag = script->LangSysRecord[j].LangSysTag;
1397 if (languagetag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1398 return (OT_LangSys*)((BYTE*)script + GET_BE_WORD(script->LangSysRecord[j].LangSys));
1401 return NULL;
1404 static void opentype_add_font_features(const GPOS_GSUB_Header *header, const OT_LangSys *langsys,
1405 UINT32 max_tagcount, UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1407 const OT_FeatureList *features = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
1408 UINT16 j;
1410 for (j = 0; j < GET_BE_WORD(langsys->FeatureCount); j++) {
1411 const OT_FeatureRecord *feature = &features->FeatureRecord[langsys->FeatureIndex[j]];
1412 const char *tag = feature->FeatureTag;
1414 if (*count < max_tagcount)
1415 tags[*count] = DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]);
1417 (*count)++;
1421 HRESULT opentype_get_typographic_features(IDWriteFontFace *fontface, UINT32 scripttag, UINT32 languagetag, UINT32 max_tagcount,
1422 UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1424 UINT32 tables[2] = { MS_GSUB_TAG, MS_GPOS_TAG };
1425 HRESULT hr;
1426 UINT8 i;
1428 *count = 0;
1429 for (i = 0; i < sizeof(tables)/sizeof(tables[0]); i++) {
1430 const OT_ScriptList *scriptlist;
1431 const GPOS_GSUB_Header *header;
1432 const OT_Script *script;
1433 const void *ptr;
1434 void *context;
1435 UINT32 size;
1436 BOOL exists;
1438 exists = FALSE;
1439 hr = IDWriteFontFace_TryGetFontTable(fontface, tables[i], &ptr, &size, &context, &exists);
1440 if (FAILED(hr))
1441 return hr;
1443 if (!exists)
1444 continue;
1446 header = (const GPOS_GSUB_Header*)ptr;
1447 scriptlist = (const OT_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
1449 script = opentype_get_script(scriptlist, scripttag);
1450 if (script) {
1451 const OT_LangSys *langsys = opentype_get_langsys(script, languagetag);
1452 if (langsys)
1453 opentype_add_font_features(header, langsys, max_tagcount, count, tags);
1456 IDWriteFontFace_ReleaseFontTable(fontface, context);
1459 return *count > max_tagcount ? E_NOT_SUFFICIENT_BUFFER : S_OK;
1462 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
1464 WORD num_ratios, i, group_offset = 0;
1465 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
1466 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
1468 num_ratios = GET_BE_WORD(hdr->numRatios);
1470 for (i = 0; i < num_ratios; i++) {
1472 if (!ratios[i].bCharSet) continue;
1474 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
1475 ratios[i].yEndRatio == 0) ||
1476 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
1477 ratios[i].yEndRatio >= dev_y_ratio))
1479 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
1480 break;
1483 if (group_offset)
1484 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
1485 return NULL;
1488 BOOL opentype_get_vdmx_size(const void *data, INT emsize, UINT16 *ascent, UINT16 *descent)
1490 const struct VDMX_Header *hdr = (const struct VDMX_Header*)data;
1491 const struct VDMX_group *group;
1492 const struct VDMX_vTable *tables;
1493 WORD recs, i;
1495 if (!data)
1496 return FALSE;
1498 group = find_vdmx_group(hdr);
1499 if (!group)
1500 return FALSE;
1502 recs = GET_BE_WORD(group->recs);
1503 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
1505 tables = (const struct VDMX_vTable *)(group + 1);
1506 for (i = 0; i < recs; i++) {
1507 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
1508 if (ppem > emsize) {
1509 FIXME("interpolate %d\n", emsize);
1510 return FALSE;
1513 if (ppem == emsize) {
1514 *ascent = (SHORT)GET_BE_WORD(tables[i].yMax);
1515 *descent = -(SHORT)GET_BE_WORD(tables[i].yMin);
1516 return TRUE;
1519 return FALSE;
1522 WORD opentype_get_gasp_flags(const WORD *ptr, UINT32 size, INT emsize)
1524 WORD num_recs, version;
1525 WORD flags = 0;
1527 if (!ptr)
1528 return 0;
1530 version = GET_BE_WORD( *ptr++ );
1531 num_recs = GET_BE_WORD( *ptr++ );
1532 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
1533 ERR("unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
1534 goto done;
1537 while (num_recs--) {
1538 flags = GET_BE_WORD( *(ptr + 1) );
1539 if (emsize <= GET_BE_WORD( *ptr )) break;
1540 ptr += 2;
1543 done:
1544 return flags;
1547 UINT32 opentype_get_cpal_palettecount(const void *cpal)
1549 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1550 return header ? GET_BE_WORD(header->numPalette) : 0;
1553 UINT32 opentype_get_cpal_paletteentrycount(const void *cpal)
1555 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1556 return header ? GET_BE_WORD(header->numPaletteEntries) : 0;
1559 HRESULT opentype_get_cpal_entries(const void *cpal, UINT32 palette, UINT32 first_entry_index, UINT32 entry_count,
1560 DWRITE_COLOR_F *entries)
1562 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1563 const struct CPAL_ColorRecord *records;
1564 UINT32 palettecount, entrycount, i;
1566 if (!header) return DWRITE_E_NOCOLOR;
1568 palettecount = GET_BE_WORD(header->numPalette);
1569 if (palette >= palettecount)
1570 return DWRITE_E_NOCOLOR;
1572 entrycount = GET_BE_WORD(header->numPaletteEntries);
1573 if (first_entry_index + entry_count > entrycount)
1574 return E_INVALIDARG;
1576 records = (const struct CPAL_ColorRecord*)((BYTE*)cpal + GET_BE_DWORD(header->offsetFirstColorRecord));
1577 first_entry_index += GET_BE_WORD(header->colorRecordIndices[palette]);
1579 for (i = 0; i < entry_count; i++) {
1580 entries[i].r = records[first_entry_index + i].red / 255.0f;
1581 entries[i].g = records[first_entry_index + i].green / 255.0f;
1582 entries[i].b = records[first_entry_index + i].blue / 255.0f;
1583 entries[i].a = records[first_entry_index + i].alpha / 255.0f;
1586 return S_OK;