reg/tests: Use a helper function to delete registry values.
[wine.git] / dlls / dwrite / opentype.c
blob36c34b630e4a4b6cf2bdc164c6f3754e75f8b51c
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
22 #define NONAMELESSUNION
24 #include "dwrite_private.h"
25 #include "winternl.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
29 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
30 #define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
31 #define MS_OTTO_TAG DWRITE_MAKE_OPENTYPE_TAG('O','T','T','O')
32 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
33 #define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
34 #define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f')
35 #define MS_GPOS_TAG DWRITE_MAKE_OPENTYPE_TAG('G','P','O','S')
36 #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B')
37 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
38 #define MS_GLYF_TAG DWRITE_MAKE_OPENTYPE_TAG('g','l','y','f')
39 #define MS_CFF__TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F',' ')
40 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
41 #define MS_SVG__TAG DWRITE_MAKE_OPENTYPE_TAG('S','V','G',' ')
42 #define MS_SBIX_TAG DWRITE_MAKE_OPENTYPE_TAG('s','b','i','x')
43 #define MS_MAXP_TAG DWRITE_MAKE_OPENTYPE_TAG('m','a','x','p')
45 /* 'sbix' formats */
46 #define MS_PNG__TAG DWRITE_MAKE_OPENTYPE_TAG('p','n','g',' ')
47 #define MS_JPG__TAG DWRITE_MAKE_OPENTYPE_TAG('j','p','g',' ')
48 #define MS_TIFF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','i','f','f')
50 #ifdef WORDS_BIGENDIAN
51 #define GET_BE_WORD(x) (x)
52 #define GET_BE_DWORD(x) (x)
53 #else
54 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
55 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
56 #endif
58 typedef struct {
59 CHAR TTCTag[4];
60 DWORD Version;
61 DWORD numFonts;
62 DWORD OffsetTable[1];
63 } TTC_Header_V1;
65 typedef struct {
66 DWORD version;
67 WORD numTables;
68 WORD searchRange;
69 WORD entrySelector;
70 WORD rangeShift;
71 } TTC_SFNT_V1;
73 typedef struct {
74 CHAR tag[4];
75 DWORD checkSum;
76 DWORD offset;
77 DWORD length;
78 } TT_TableRecord;
80 typedef struct {
81 WORD platformID;
82 WORD encodingID;
83 DWORD offset;
84 } CMAP_EncodingRecord;
86 typedef struct {
87 WORD version;
88 WORD numTables;
89 CMAP_EncodingRecord tables[1];
90 } CMAP_Header;
92 typedef struct {
93 DWORD startCharCode;
94 DWORD endCharCode;
95 DWORD startGlyphID;
96 } CMAP_SegmentedCoverage_group;
98 typedef struct {
99 WORD format;
100 WORD reserved;
101 DWORD length;
102 DWORD language;
103 DWORD nGroups;
104 CMAP_SegmentedCoverage_group groups[1];
105 } CMAP_SegmentedCoverage;
107 typedef struct {
108 WORD format;
109 WORD length;
110 WORD language;
111 WORD segCountX2;
112 WORD searchRange;
113 WORD entrySelector;
114 WORD rangeShift;
115 WORD endCode[1];
116 } CMAP_SegmentMapping_0;
118 enum OPENTYPE_CMAP_TABLE_FORMAT
120 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING = 4,
121 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE = 12
124 /* PANOSE is 10 bytes in size, need to pack the structure properly */
125 #include "pshpack2.h"
126 typedef struct
128 USHORT majorVersion;
129 USHORT minorVersion;
130 ULONG revision;
131 ULONG checksumadj;
132 ULONG magic;
133 USHORT flags;
134 USHORT unitsPerEm;
135 ULONGLONG created;
136 ULONGLONG modified;
137 SHORT xMin;
138 SHORT yMin;
139 SHORT xMax;
140 SHORT yMax;
141 USHORT macStyle;
142 USHORT lowestRecPPEM;
143 SHORT direction_hint;
144 SHORT index_format;
145 SHORT glyphdata_format;
146 } TT_HEAD;
148 enum TT_HEAD_MACSTYLE
150 TT_HEAD_MACSTYLE_BOLD = 1 << 0,
151 TT_HEAD_MACSTYLE_ITALIC = 1 << 1,
152 TT_HEAD_MACSTYLE_UNDERLINE = 1 << 2,
153 TT_HEAD_MACSTYLE_OUTLINE = 1 << 3,
154 TT_HEAD_MACSTYLE_SHADOW = 1 << 4,
155 TT_HEAD_MACSTYLE_CONDENSED = 1 << 5,
156 TT_HEAD_MACSTYLE_EXTENDED = 1 << 6,
159 typedef struct
161 ULONG Version;
162 ULONG italicAngle;
163 SHORT underlinePosition;
164 SHORT underlineThickness;
165 ULONG fixed_pitch;
166 ULONG minmemType42;
167 ULONG maxmemType42;
168 ULONG minmemType1;
169 ULONG maxmemType1;
170 } TT_POST;
172 typedef struct
174 USHORT version;
175 SHORT xAvgCharWidth;
176 USHORT usWeightClass;
177 USHORT usWidthClass;
178 SHORT fsType;
179 SHORT ySubscriptXSize;
180 SHORT ySubscriptYSize;
181 SHORT ySubscriptXOffset;
182 SHORT ySubscriptYOffset;
183 SHORT ySuperscriptXSize;
184 SHORT ySuperscriptYSize;
185 SHORT ySuperscriptXOffset;
186 SHORT ySuperscriptYOffset;
187 SHORT yStrikeoutSize;
188 SHORT yStrikeoutPosition;
189 SHORT sFamilyClass;
190 PANOSE panose;
191 ULONG ulUnicodeRange1;
192 ULONG ulUnicodeRange2;
193 ULONG ulUnicodeRange3;
194 ULONG ulUnicodeRange4;
195 CHAR achVendID[4];
196 USHORT fsSelection;
197 USHORT usFirstCharIndex;
198 USHORT usLastCharIndex;
199 /* According to the Apple spec, original version didn't have the below fields,
200 * version numbers were taken from the OpenType spec.
202 /* version 0 (TrueType 1.5) */
203 USHORT sTypoAscender;
204 USHORT sTypoDescender;
205 USHORT sTypoLineGap;
206 USHORT usWinAscent;
207 USHORT usWinDescent;
208 /* version 1 (TrueType 1.66) */
209 ULONG ulCodePageRange1;
210 ULONG ulCodePageRange2;
211 /* version 2 (OpenType 1.2) */
212 SHORT sxHeight;
213 SHORT sCapHeight;
214 USHORT usDefaultChar;
215 USHORT usBreakChar;
216 USHORT usMaxContext;
217 } TT_OS2_V2;
219 typedef struct {
220 USHORT majorVersion;
221 USHORT minorVersion;
222 SHORT ascender;
223 SHORT descender;
224 SHORT linegap;
225 USHORT advanceWidthMax;
226 SHORT minLeftSideBearing;
227 SHORT minRightSideBearing;
228 SHORT xMaxExtent;
229 SHORT caretSlopeRise;
230 SHORT caretSlopeRun;
231 SHORT caretOffset;
232 SHORT reserved[4];
233 SHORT metricDataFormat;
234 USHORT numberOfHMetrics;
235 } TT_HHEA;
237 typedef struct {
238 WORD version;
239 WORD flags;
240 DWORD numStrikes;
241 DWORD strikeOffset[1];
242 } sbix_header;
244 typedef struct {
245 WORD ppem;
246 WORD ppi;
247 DWORD glyphDataOffsets[1];
248 } sbix_strike;
250 typedef struct {
251 WORD originOffsetX;
252 WORD originOffsetY;
253 DWORD graphicType;
254 BYTE data[1];
255 } sbix_glyph_data;
257 typedef struct {
258 DWORD version;
259 WORD numGlyphs;
260 } maxp;
262 #include "poppack.h"
264 enum OS2_FSSELECTION {
265 OS2_FSSELECTION_ITALIC = 1 << 0,
266 OS2_FSSELECTION_UNDERSCORE = 1 << 1,
267 OS2_FSSELECTION_NEGATIVE = 1 << 2,
268 OS2_FSSELECTION_OUTLINED = 1 << 3,
269 OS2_FSSELECTION_STRIKEOUT = 1 << 4,
270 OS2_FSSELECTION_BOLD = 1 << 5,
271 OS2_FSSELECTION_REGULAR = 1 << 6,
272 OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7,
273 OS2_FSSELECTION_WWS = 1 << 8,
274 OS2_FSSELECTION_OBLIQUE = 1 << 9
277 typedef struct {
278 WORD platformID;
279 WORD encodingID;
280 WORD languageID;
281 WORD nameID;
282 WORD length;
283 WORD offset;
284 } TT_NameRecord;
286 typedef struct {
287 WORD format;
288 WORD count;
289 WORD stringOffset;
290 TT_NameRecord nameRecord[1];
291 } TT_NAME_V0;
293 struct VDMX_Header
295 WORD version;
296 WORD numRecs;
297 WORD numRatios;
300 struct VDMX_Ratio
302 BYTE bCharSet;
303 BYTE xRatio;
304 BYTE yStartRatio;
305 BYTE yEndRatio;
308 struct VDMX_group
310 WORD recs;
311 BYTE startsz;
312 BYTE endsz;
315 struct VDMX_vTable
317 WORD yPelHeight;
318 SHORT yMax;
319 SHORT yMin;
322 typedef struct {
323 CHAR FeatureTag[4];
324 WORD Feature;
325 } OT_FeatureRecord;
327 typedef struct {
328 WORD FeatureCount;
329 OT_FeatureRecord FeatureRecord[1];
330 } OT_FeatureList;
332 typedef struct {
333 WORD LookupOrder; /* Reserved */
334 WORD ReqFeatureIndex;
335 WORD FeatureCount;
336 WORD FeatureIndex[1];
337 } OT_LangSys;
339 typedef struct {
340 CHAR LangSysTag[4];
341 WORD LangSys;
342 } OT_LangSysRecord;
344 typedef struct {
345 WORD DefaultLangSys;
346 WORD LangSysCount;
347 OT_LangSysRecord LangSysRecord[1];
348 } OT_Script;
350 typedef struct {
351 CHAR ScriptTag[4];
352 WORD Script;
353 } OT_ScriptRecord;
355 typedef struct {
356 WORD ScriptCount;
357 OT_ScriptRecord ScriptRecord[1];
358 } OT_ScriptList;
360 typedef struct {
361 DWORD version;
362 WORD ScriptList;
363 WORD FeatureList;
364 WORD LookupList;
365 } GPOS_GSUB_Header;
367 enum OPENTYPE_PLATFORM_ID
369 OPENTYPE_PLATFORM_UNICODE = 0,
370 OPENTYPE_PLATFORM_MAC,
371 OPENTYPE_PLATFORM_ISO,
372 OPENTYPE_PLATFORM_WIN,
373 OPENTYPE_PLATFORM_CUSTOM
376 typedef struct {
377 WORD FeatureParams;
378 WORD LookupCount;
379 WORD LookupListIndex[1];
380 } OT_Feature;
382 typedef struct {
383 WORD LookupCount;
384 WORD Lookup[1];
385 } OT_LookupList;
387 typedef struct {
388 WORD LookupType;
389 WORD LookupFlag;
390 WORD SubTableCount;
391 WORD SubTable[1];
392 } OT_LookupTable;
394 typedef struct {
395 WORD SubstFormat;
396 WORD Coverage;
397 WORD DeltaGlyphID;
398 } GSUB_SingleSubstFormat1;
400 typedef struct {
401 WORD SubstFormat;
402 WORD Coverage;
403 WORD GlyphCount;
404 WORD Substitute[1];
405 } GSUB_SingleSubstFormat2;
407 typedef struct {
408 WORD SubstFormat;
409 WORD ExtensionLookupType;
410 DWORD ExtensionOffset;
411 } GSUB_ExtensionPosFormat1;
413 enum OPENTYPE_GPOS_LOOKUPS
415 OPENTYPE_GPOS_SINGLE_SUBST = 1,
416 OPENTYPE_GPOS_EXTENSION_SUBST = 7
419 enum TT_NAME_WINDOWS_ENCODING_ID
421 TT_NAME_WINDOWS_ENCODING_SYMBOL = 0,
422 TT_NAME_WINDOWS_ENCODING_UCS2,
423 TT_NAME_WINDOWS_ENCODING_SJIS,
424 TT_NAME_WINDOWS_ENCODING_PRC,
425 TT_NAME_WINDOWS_ENCODING_BIG5,
426 TT_NAME_WINDOWS_ENCODING_WANSUNG,
427 TT_NAME_WINDOWS_ENCODING_JOHAB,
428 TT_NAME_WINDOWS_ENCODING_RESERVED1,
429 TT_NAME_WINDOWS_ENCODING_RESERVED2,
430 TT_NAME_WINDOWS_ENCODING_RESERVED3,
431 TT_NAME_WINDOWS_ENCODING_UCS4
434 enum TT_NAME_MAC_ENCODING_ID
436 TT_NAME_MAC_ENCODING_ROMAN = 0,
437 TT_NAME_MAC_ENCODING_JAPANESE,
438 TT_NAME_MAC_ENCODING_TRAD_CHINESE,
439 TT_NAME_MAC_ENCODING_KOREAN,
440 TT_NAME_MAC_ENCODING_ARABIC,
441 TT_NAME_MAC_ENCODING_HEBREW,
442 TT_NAME_MAC_ENCODING_GREEK,
443 TT_NAME_MAC_ENCODING_RUSSIAN,
444 TT_NAME_MAC_ENCODING_RSYMBOL,
445 TT_NAME_MAC_ENCODING_DEVANAGARI,
446 TT_NAME_MAC_ENCODING_GURMUKHI,
447 TT_NAME_MAC_ENCODING_GUJARATI,
448 TT_NAME_MAC_ENCODING_ORIYA,
449 TT_NAME_MAC_ENCODING_BENGALI,
450 TT_NAME_MAC_ENCODING_TAMIL,
451 TT_NAME_MAC_ENCODING_TELUGU,
452 TT_NAME_MAC_ENCODING_KANNADA,
453 TT_NAME_MAC_ENCODING_MALAYALAM,
454 TT_NAME_MAC_ENCODING_SINHALESE,
455 TT_NAME_MAC_ENCODING_BURMESE,
456 TT_NAME_MAC_ENCODING_KHMER,
457 TT_NAME_MAC_ENCODING_THAI,
458 TT_NAME_MAC_ENCODING_LAOTIAN,
459 TT_NAME_MAC_ENCODING_GEORGIAN,
460 TT_NAME_MAC_ENCODING_ARMENIAN,
461 TT_NAME_MAC_ENCODING_SIMPL_CHINESE,
462 TT_NAME_MAC_ENCODING_TIBETAN,
463 TT_NAME_MAC_ENCODING_MONGOLIAN,
464 TT_NAME_MAC_ENCODING_GEEZ,
465 TT_NAME_MAC_ENCODING_SLAVIC,
466 TT_NAME_MAC_ENCODING_VIETNAMESE,
467 TT_NAME_MAC_ENCODING_SINDHI,
468 TT_NAME_MAC_ENCODING_UNINTERPRETED
471 enum TT_NAME_MAC_LANGUAGE_ID
473 TT_NAME_MAC_LANGID_ENGLISH = 0,
474 TT_NAME_MAC_LANGID_FRENCH,
475 TT_NAME_MAC_LANGID_GERMAN,
476 TT_NAME_MAC_LANGID_ITALIAN,
477 TT_NAME_MAC_LANGID_DUTCH,
478 TT_NAME_MAC_LANGID_SWEDISH,
479 TT_NAME_MAC_LANGID_SPANISH,
480 TT_NAME_MAC_LANGID_DANISH,
481 TT_NAME_MAC_LANGID_PORTUGUESE,
482 TT_NAME_MAC_LANGID_NORWEGIAN,
483 TT_NAME_MAC_LANGID_HEBREW,
484 TT_NAME_MAC_LANGID_JAPANESE,
485 TT_NAME_MAC_LANGID_ARABIC,
486 TT_NAME_MAC_LANGID_FINNISH,
487 TT_NAME_MAC_LANGID_GREEK,
488 TT_NAME_MAC_LANGID_ICELANDIC,
489 TT_NAME_MAC_LANGID_MALTESE,
490 TT_NAME_MAC_LANGID_TURKISH,
491 TT_NAME_MAC_LANGID_CROATIAN,
492 TT_NAME_MAC_LANGID_TRAD_CHINESE,
493 TT_NAME_MAC_LANGID_URDU,
494 TT_NAME_MAC_LANGID_HINDI,
495 TT_NAME_MAC_LANGID_THAI,
496 TT_NAME_MAC_LANGID_KOREAN,
497 TT_NAME_MAC_LANGID_LITHUANIAN,
498 TT_NAME_MAC_LANGID_POLISH,
499 TT_NAME_MAC_LANGID_HUNGARIAN,
500 TT_NAME_MAC_LANGID_ESTONIAN,
501 TT_NAME_MAC_LANGID_LATVIAN,
502 TT_NAME_MAC_LANGID_SAMI,
503 TT_NAME_MAC_LANGID_FAROESE,
504 TT_NAME_MAC_LANGID_FARSI,
505 TT_NAME_MAC_LANGID_RUSSIAN,
506 TT_NAME_MAC_LANGID_SIMPL_CHINESE,
507 TT_NAME_MAC_LANGID_FLEMISH,
508 TT_NAME_MAC_LANGID_GAELIC,
509 TT_NAME_MAC_LANGID_ALBANIAN,
510 TT_NAME_MAC_LANGID_ROMANIAN,
511 TT_NAME_MAC_LANGID_CZECH,
512 TT_NAME_MAC_LANGID_SLOVAK,
513 TT_NAME_MAC_LANGID_SLOVENIAN,
514 TT_NAME_MAC_LANGID_YIDDISH,
515 TT_NAME_MAC_LANGID_SERBIAN,
516 TT_NAME_MAC_LANGID_MACEDONIAN,
517 TT_NAME_MAC_LANGID_BULGARIAN,
518 TT_NAME_MAC_LANGID_UKRAINIAN,
519 TT_NAME_MAC_LANGID_BYELORUSSIAN,
520 TT_NAME_MAC_LANGID_UZBEK,
521 TT_NAME_MAC_LANGID_KAZAKH,
522 TT_NAME_MAC_LANGID_AZERB_CYR,
523 TT_NAME_MAC_LANGID_AZERB_ARABIC,
524 TT_NAME_MAC_LANGID_ARMENIAN,
525 TT_NAME_MAC_LANGID_GEORGIAN,
526 TT_NAME_MAC_LANGID_MOLDAVIAN,
527 TT_NAME_MAC_LANGID_KIRGHIZ,
528 TT_NAME_MAC_LANGID_TAJIKI,
529 TT_NAME_MAC_LANGID_TURKMEN,
530 TT_NAME_MAC_LANGID_MONGOLIAN,
531 TT_NAME_MAC_LANGID_MONGOLIAN_CYR,
532 TT_NAME_MAC_LANGID_PASHTO,
533 TT_NAME_MAC_LANGID_KURDISH,
534 TT_NAME_MAC_LANGID_KASHMIRI,
535 TT_NAME_MAC_LANGID_SINDHI,
536 TT_NAME_MAC_LANGID_TIBETAN,
537 TT_NAME_MAC_LANGID_NEPALI,
538 TT_NAME_MAC_LANGID_SANSKRIT,
539 TT_NAME_MAC_LANGID_MARATHI,
540 TT_NAME_MAC_LANGID_BENGALI,
541 TT_NAME_MAC_LANGID_ASSAMESE,
542 TT_NAME_MAC_LANGID_GUJARATI,
543 TT_NAME_MAC_LANGID_PUNJABI,
544 TT_NAME_MAC_LANGID_ORIYA,
545 TT_NAME_MAC_LANGID_MALAYALAM,
546 TT_NAME_MAC_LANGID_KANNADA,
547 TT_NAME_MAC_LANGID_TAMIL,
548 TT_NAME_MAC_LANGID_TELUGU,
549 TT_NAME_MAC_LANGID_SINHALESE,
550 TT_NAME_MAC_LANGID_BURMESE,
551 TT_NAME_MAC_LANGID_KHMER,
552 TT_NAME_MAC_LANGID_LAO,
553 TT_NAME_MAC_LANGID_VIETNAMESE,
554 TT_NAME_MAC_LANGID_INDONESIAN,
555 TT_NAME_MAC_LANGID_TAGALOG,
556 TT_NAME_MAC_LANGID_MALAY_ROMAN,
557 TT_NAME_MAC_LANGID_MALAY_ARABIC,
558 TT_NAME_MAC_LANGID_AMHARIC,
559 TT_NAME_MAC_LANGID_TIGRINYA,
560 TT_NAME_MAC_LANGID_GALLA,
561 TT_NAME_MAC_LANGID_SOMALI,
562 TT_NAME_MAC_LANGID_SWAHILI,
563 TT_NAME_MAC_LANGID_KINYARWANDA,
564 TT_NAME_MAC_LANGID_RUNDI,
565 TT_NAME_MAC_LANGID_NYANJA,
566 TT_NAME_MAC_LANGID_MALAGASY,
567 TT_NAME_MAC_LANGID_ESPERANTO,
568 TT_NAME_MAC_LANGID_WELSH = 128,
569 TT_NAME_MAC_LANGID_BASQUE,
570 TT_NAME_MAC_LANGID_CATALAN,
571 TT_NAME_MAC_LANGID_LATIN,
572 TT_NAME_MAC_LANGID_QUECHUA,
573 TT_NAME_MAC_LANGID_GUARANI,
574 TT_NAME_MAC_LANGID_AYMARA,
575 TT_NAME_MAC_LANGID_TATAR,
576 TT_NAME_MAC_LANGID_UIGHUR,
577 TT_NAME_MAC_LANGID_DZONGKHA,
578 TT_NAME_MAC_LANGID_JAVANESE,
579 TT_NAME_MAC_LANGID_SUNDANESE,
580 TT_NAME_MAC_LANGID_GALICIAN,
581 TT_NAME_MAC_LANGID_AFRIKAANS,
582 TT_NAME_MAC_LANGID_BRETON,
583 TT_NAME_MAC_LANGID_INUKTITUT,
584 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC,
585 TT_NAME_MAC_LANGID_MANX_GAELIC,
586 TT_NAME_MAC_LANGID_IRISH_GAELIC,
587 TT_NAME_MAC_LANGID_TONGAN,
588 TT_NAME_MAC_LANGID_GREEK_POLYTONIC,
589 TT_NAME_MAC_LANGID_GREENLANDIC,
590 TT_NAME_MAC_LANGID_AZER_ROMAN
593 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
594 static const char name_mac_langid_to_locale[][10] = {
595 "en-US",
596 "fr-FR",
597 "de-DE",
598 "it-IT",
599 "nl-NL",
600 "sv-SE",
601 "es-ES",
602 "da-DA",
603 "pt-PT",
604 "no-NO",
605 "he-IL",
606 "ja-JP",
607 "ar-AR",
608 "fi-FI",
609 "el-GR",
610 "is-IS",
611 "mt-MT",
612 "tr-TR",
613 "hr-HR",
614 "zh-HK",
615 "ur-PK",
616 "hi-IN",
617 "th-TH",
618 "ko-KR",
619 "lt-LT",
620 "pl-PL",
621 "hu-HU",
622 "et-EE",
623 "lv-LV",
624 "se-NO",
625 "fo-FO",
626 "fa-IR",
627 "ru-RU",
628 "zh-CN",
629 "nl-BE",
630 "gd-GB",
631 "sq-AL",
632 "ro-RO",
633 "cs-CZ",
634 "sk-SK",
635 "sl-SI",
637 "sr-Latn",
638 "mk-MK",
639 "bg-BG",
640 "uk-UA",
641 "be-BY",
642 "uz-Latn",
643 "kk-KZ",
644 "az-Cyrl-AZ",
645 "az-AZ",
646 "hy-AM",
647 "ka-GE",
650 "tg-TJ",
651 "tk-TM",
652 "mn-Mong",
653 "mn-MN",
654 "ps-AF",
655 "ku-Arab",
657 "sd-Arab",
658 "bo-CN",
659 "ne-NP",
660 "sa-IN",
661 "mr-IN",
662 "bn-IN",
663 "as-IN",
664 "gu-IN",
665 "pa-Arab",
666 "or-IN",
667 "ml-IN",
668 "kn-IN",
669 "ta-LK",
670 "te-IN",
671 "si-LK",
673 "km-KH",
674 "lo-LA",
675 "vi-VN",
676 "id-ID",
678 "ms-MY",
679 "ms-Arab",
680 "am-ET",
681 "ti-ET",
684 "sw-KE",
685 "rw-RW",
723 "cy-GB",
724 "eu-ES",
725 "ca-ES",
730 "tt-RU",
731 "ug-CN",
735 "gl-ES",
736 "af-ZA",
737 "br-FR",
738 "iu-Latn-CA",
739 "gd-GB",
741 "ga-IE",
744 "kl-GL",
745 "az-Latn"
748 enum OPENTYPE_STRING_ID
750 OPENTYPE_STRING_COPYRIGHT_NOTICE = 0,
751 OPENTYPE_STRING_FAMILY_NAME,
752 OPENTYPE_STRING_SUBFAMILY_NAME,
753 OPENTYPE_STRING_UNIQUE_IDENTIFIER,
754 OPENTYPE_STRING_FULL_FONTNAME,
755 OPENTYPE_STRING_VERSION_STRING,
756 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
757 OPENTYPE_STRING_TRADEMARK,
758 OPENTYPE_STRING_MANUFACTURER,
759 OPENTYPE_STRING_DESIGNER,
760 OPENTYPE_STRING_DESCRIPTION,
761 OPENTYPE_STRING_VENDOR_URL,
762 OPENTYPE_STRING_DESIGNER_URL,
763 OPENTYPE_STRING_LICENSE_DESCRIPTION,
764 OPENTYPE_STRING_LICENSE_INFO_URL,
765 OPENTYPE_STRING_RESERVED_ID15,
766 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
767 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
768 OPENTYPE_STRING_COMPATIBLE_FULLNAME,
769 OPENTYPE_STRING_SAMPLE_TEXT,
770 OPENTYPE_STRING_POSTSCRIPT_CID_NAME,
771 OPENTYPE_STRING_WWS_FAMILY_NAME,
772 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
775 static const UINT16 dwriteid_to_opentypeid[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1] =
777 (UINT16)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
778 OPENTYPE_STRING_COPYRIGHT_NOTICE,
779 OPENTYPE_STRING_VERSION_STRING,
780 OPENTYPE_STRING_TRADEMARK,
781 OPENTYPE_STRING_MANUFACTURER,
782 OPENTYPE_STRING_DESIGNER,
783 OPENTYPE_STRING_DESIGNER_URL,
784 OPENTYPE_STRING_DESCRIPTION,
785 OPENTYPE_STRING_VENDOR_URL,
786 OPENTYPE_STRING_LICENSE_DESCRIPTION,
787 OPENTYPE_STRING_LICENSE_INFO_URL,
788 OPENTYPE_STRING_FAMILY_NAME,
789 OPENTYPE_STRING_SUBFAMILY_NAME,
790 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
791 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
792 OPENTYPE_STRING_SAMPLE_TEXT,
793 OPENTYPE_STRING_FULL_FONTNAME,
794 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
795 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
798 /* CPAL table */
799 struct CPAL_Header_0
801 USHORT version;
802 USHORT numPaletteEntries;
803 USHORT numPalette;
804 USHORT numColorRecords;
805 ULONG offsetFirstColorRecord;
806 USHORT colorRecordIndices[1];
809 /* for version == 1, this comes after full CPAL_Header_0 */
810 struct CPAL_SubHeader_1
812 ULONG offsetPaletteTypeArray;
813 ULONG offsetPaletteLabelArray;
814 ULONG offsetPaletteEntryLabelArray;
817 struct CPAL_ColorRecord
819 BYTE blue;
820 BYTE green;
821 BYTE red;
822 BYTE alpha;
825 /* COLR table */
826 struct COLR_Header
828 USHORT version;
829 USHORT numBaseGlyphRecords;
830 ULONG offsetBaseGlyphRecord;
831 ULONG offsetLayerRecord;
832 USHORT numLayerRecords;
835 struct COLR_BaseGlyphRecord
837 USHORT GID;
838 USHORT firstLayerIndex;
839 USHORT numLayers;
842 struct COLR_LayerRecord
844 USHORT GID;
845 USHORT paletteIndex;
848 BOOL is_face_type_supported(DWRITE_FONT_FACE_TYPE type)
850 return (type == DWRITE_FONT_FACE_TYPE_CFF) ||
851 (type == DWRITE_FONT_FACE_TYPE_TRUETYPE) ||
852 (type == DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION) ||
853 (type == DWRITE_FONT_FACE_TYPE_RAW_CFF);
856 typedef HRESULT (*dwrite_fontfile_analyzer)(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
857 DWRITE_FONT_FACE_TYPE *face_type);
859 static HRESULT opentype_ttc_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
860 DWRITE_FONT_FACE_TYPE *face_type)
862 static const DWORD ttctag = MS_TTCF_TAG;
863 const TTC_Header_V1 *header;
864 void *context;
865 HRESULT hr;
867 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(header), &context);
868 if (FAILED(hr))
869 return hr;
871 if (!memcmp(header->TTCTag, &ttctag, sizeof(ttctag))) {
872 *font_count = GET_BE_DWORD(header->numFonts);
873 *file_type = DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION;
874 *face_type = DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION;
877 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
879 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
882 static HRESULT opentype_ttf_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
883 DWRITE_FONT_FACE_TYPE *face_type)
885 const DWORD *header;
886 void *context;
887 HRESULT hr;
889 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(*header), &context);
890 if (FAILED(hr))
891 return hr;
893 if (GET_BE_DWORD(*header) == 0x10000) {
894 *font_count = 1;
895 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
896 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
899 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
901 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
904 static HRESULT opentype_otf_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
905 DWRITE_FONT_FACE_TYPE *face_type)
907 const DWORD *header;
908 void *context;
909 HRESULT hr;
911 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(*header), &context);
912 if (FAILED(hr))
913 return hr;
915 if (GET_BE_DWORD(*header) == MS_OTTO_TAG) {
916 *font_count = 1;
917 *file_type = DWRITE_FONT_FILE_TYPE_CFF;
918 *face_type = DWRITE_FONT_FACE_TYPE_CFF;
921 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
923 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
926 static HRESULT opentype_type1_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
927 DWRITE_FONT_FACE_TYPE *face_type)
929 #include "pshpack1.h"
930 /* Specified in Adobe TechNote #5178 */
931 struct pfm_header {
932 WORD dfVersion;
933 DWORD dfSize;
934 char data0[95];
935 DWORD dfDevice;
936 char data1[12];
938 #include "poppack.h"
939 struct type1_header {
940 WORD tag;
941 char data[14];
943 const struct type1_header *header;
944 void *context;
945 HRESULT hr;
947 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(*header), &context);
948 if (FAILED(hr))
949 return hr;
951 /* tag is followed by plain text section */
952 if (header->tag == 0x8001 &&
953 (!memcmp(header->data, "%!PS-AdobeFont", 14) ||
954 !memcmp(header->data, "%!FontType", 10))) {
955 *font_count = 1;
956 *file_type = DWRITE_FONT_FILE_TYPE_TYPE1_PFB;
957 *face_type = DWRITE_FONT_FACE_TYPE_TYPE1;
960 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
962 /* let's see if it's a .pfm metrics file */
963 if (*file_type == DWRITE_FONT_FILE_TYPE_UNKNOWN) {
964 const struct pfm_header *pfm_header;
965 UINT64 filesize;
966 DWORD offset;
967 BOOL header_checked;
969 hr = IDWriteFontFileStream_GetFileSize(stream, &filesize);
970 if (FAILED(hr))
971 return hr;
973 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&pfm_header, 0, sizeof(*pfm_header), &context);
974 if (FAILED(hr))
975 return hr;
977 offset = pfm_header->dfDevice;
978 header_checked = pfm_header->dfVersion == 0x100 && pfm_header->dfSize == filesize;
979 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
981 /* as a last test check static string in PostScript information section */
982 if (header_checked) {
983 static const char postscript[] = "PostScript";
984 char *devtype_name;
986 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&devtype_name, offset, sizeof(postscript), &context);
987 if (FAILED(hr))
988 return hr;
990 if (!memcmp(devtype_name, postscript, sizeof(postscript))) {
991 *font_count = 1;
992 *file_type = DWRITE_FONT_FILE_TYPE_TYPE1_PFM;
993 *face_type = DWRITE_FONT_FACE_TYPE_TYPE1;
996 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
1000 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
1003 HRESULT opentype_analyze_font(IDWriteFontFileStream *stream, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported)
1005 static dwrite_fontfile_analyzer fontfile_analyzers[] = {
1006 opentype_ttf_analyzer,
1007 opentype_otf_analyzer,
1008 opentype_ttc_analyzer,
1009 opentype_type1_analyzer,
1010 NULL
1012 dwrite_fontfile_analyzer *analyzer = fontfile_analyzers;
1013 DWRITE_FONT_FACE_TYPE face;
1014 HRESULT hr;
1016 if (!face_type)
1017 face_type = &face;
1019 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
1020 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
1021 *font_count = 0;
1023 while (*analyzer) {
1024 hr = (*analyzer)(stream, font_count, file_type, face_type);
1025 if (FAILED(hr))
1026 return hr;
1028 if (hr == S_OK)
1029 break;
1031 analyzer++;
1034 *supported = is_face_type_supported(*face_type);
1035 return S_OK;
1038 HRESULT opentype_get_font_table(struct file_stream_desc *stream_desc, UINT32 tag, const void **table_data,
1039 void **table_context, UINT32 *table_size, BOOL *found)
1041 HRESULT hr;
1042 TTC_SFNT_V1 *font_header = NULL;
1043 void *sfnt_context;
1044 TT_TableRecord *table_record = NULL;
1045 void *table_record_context;
1046 int table_count, table_offset = 0;
1047 int i;
1049 if (found) *found = FALSE;
1050 if (table_size) *table_size = 0;
1052 *table_data = NULL;
1053 *table_context = NULL;
1055 if (stream_desc->face_type == DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION) {
1056 const TTC_Header_V1 *ttc_header;
1057 void * ttc_context;
1058 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context);
1059 if (SUCCEEDED(hr)) {
1060 if (stream_desc->face_index >= GET_BE_DWORD(ttc_header->numFonts))
1061 hr = E_INVALIDARG;
1062 else {
1063 table_offset = GET_BE_DWORD(ttc_header->OffsetTable[stream_desc->face_index]);
1064 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context);
1066 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, ttc_context);
1069 else
1070 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context);
1072 if (FAILED(hr))
1073 return hr;
1075 table_count = GET_BE_WORD(font_header->numTables);
1076 table_offset += sizeof(*font_header);
1077 for (i = 0; i < table_count; i++)
1079 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&table_record, table_offset, sizeof(*table_record), &table_record_context);
1080 if (FAILED(hr))
1081 break;
1082 if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag)
1083 break;
1084 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, table_record_context);
1085 table_offset += sizeof(*table_record);
1088 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, sfnt_context);
1089 if (SUCCEEDED(hr) && i < table_count)
1091 int offset = GET_BE_DWORD(table_record->offset);
1092 int length = GET_BE_DWORD(table_record->length);
1093 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, table_record_context);
1095 if (found) *found = TRUE;
1096 if (table_size) *table_size = length;
1097 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, table_data, offset, length, table_context);
1100 return hr;
1103 /**********
1104 * CMAP
1105 **********/
1107 static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table)
1109 UINT32 count = 0;
1110 int i;
1112 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) {
1113 WORD type;
1114 WORD *table;
1116 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
1117 continue;
1119 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
1120 type = GET_BE_WORD(*table);
1121 TRACE("table type %i\n", type);
1123 switch (type)
1125 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
1127 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
1128 count += GET_BE_WORD(format->segCountX2)/2;
1129 break;
1131 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
1133 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
1134 count += GET_BE_DWORD(format->nGroups);
1135 break;
1137 default:
1138 FIXME("table type %i unhandled.\n", type);
1142 return count;
1145 HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1147 CMAP_Header *CMAP_Table = data;
1148 int i, k = 0;
1150 if (!CMAP_Table)
1151 return E_FAIL;
1153 *count = opentype_cmap_get_unicode_ranges_count(CMAP_Table);
1155 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables) && k < max_count; i++)
1157 WORD type;
1158 WORD *table;
1159 int j;
1161 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
1162 continue;
1164 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
1165 type = GET_BE_WORD(*table);
1166 TRACE("table type %i\n", type);
1168 switch (type)
1170 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
1172 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
1173 UINT16 segment_count = GET_BE_WORD(format->segCountX2)/2;
1174 UINT16 *startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
1176 for (j = 0; j < segment_count && GET_BE_WORD(format->endCode[j]) < 0xffff && k < max_count; j++, k++) {
1177 ranges[k].first = GET_BE_WORD(startCode[j]);
1178 ranges[k].last = GET_BE_WORD(format->endCode[j]);
1180 break;
1182 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
1184 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
1185 for (j = 0; j < GET_BE_DWORD(format->nGroups) && k < max_count; j++, k++) {
1186 ranges[k].first = GET_BE_DWORD(format->groups[j].startCharCode);
1187 ranges[k].last = GET_BE_DWORD(format->groups[j].endCharCode);
1189 break;
1191 default:
1192 FIXME("table type %i unhandled.\n", type);
1196 return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK;
1199 void opentype_get_font_metrics(struct file_stream_desc *stream_desc, DWRITE_FONT_METRICS1 *metrics, DWRITE_CARET_METRICS *caret)
1201 void *os2_context, *head_context, *post_context, *hhea_context;
1202 const TT_OS2_V2 *tt_os2;
1203 const TT_HEAD *tt_head;
1204 const TT_POST *tt_post;
1205 const TT_HHEA *tt_hhea;
1207 memset(metrics, 0, sizeof(*metrics));
1209 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1210 opentype_get_font_table(stream_desc, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
1211 opentype_get_font_table(stream_desc, MS_POST_TAG, (const void**)&tt_post, &post_context, NULL, NULL);
1212 opentype_get_font_table(stream_desc, MS_HHEA_TAG, (const void**)&tt_hhea, &hhea_context, NULL, NULL);
1214 if (tt_head) {
1215 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
1216 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
1217 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
1218 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
1219 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
1222 if (caret) {
1223 if (tt_hhea) {
1224 caret->slopeRise = GET_BE_WORD(tt_hhea->caretSlopeRise);
1225 caret->slopeRun = GET_BE_WORD(tt_hhea->caretSlopeRun);
1226 caret->offset = GET_BE_WORD(tt_hhea->caretOffset);
1228 else {
1229 caret->slopeRise = 0;
1230 caret->slopeRun = 0;
1231 caret->offset = 0;
1235 if (tt_os2) {
1236 USHORT version = GET_BE_WORD(tt_os2->version);
1238 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
1239 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
1240 interpreted as large unsigned value. */
1241 metrics->descent = abs((SHORT)GET_BE_WORD(tt_os2->usWinDescent));
1243 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
1244 if (tt_hhea) {
1245 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
1246 INT32 linegap;
1248 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
1249 metrics->ascent - metrics->descent;
1250 metrics->lineGap = linegap > 0 ? linegap : 0;
1253 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
1254 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
1255 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
1256 /* Y offset is stored as positive offset below baseline */
1257 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
1258 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
1259 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
1260 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
1261 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
1262 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
1263 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
1265 /* version 2 fields */
1266 if (version >= 2) {
1267 metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight);
1268 metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight);
1271 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
1272 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
1273 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
1274 metrics->descent = descent < 0 ? -descent : 0;
1275 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
1276 metrics->hasTypographicMetrics = TRUE;
1280 if (tt_post) {
1281 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
1282 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
1285 if (metrics->underlineThickness == 0)
1286 metrics->underlineThickness = metrics->designUnitsPerEm / 14;
1287 if (metrics->strikethroughThickness == 0)
1288 metrics->strikethroughThickness = metrics->underlineThickness;
1290 /* estimate missing metrics */
1291 if (metrics->xHeight == 0)
1292 metrics->xHeight = metrics->designUnitsPerEm / 2;
1293 if (metrics->capHeight == 0)
1294 metrics->capHeight = metrics->designUnitsPerEm * 7 / 10;
1296 if (tt_os2)
1297 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1298 if (tt_head)
1299 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, head_context);
1300 if (tt_post)
1301 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, post_context);
1302 if (tt_hhea)
1303 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, hhea_context);
1306 void opentype_get_font_properties(struct file_stream_desc *stream_desc, struct dwrite_font_props *props)
1308 void *os2_context, *head_context;
1309 const TT_OS2_V2 *tt_os2;
1310 const TT_HEAD *tt_head;
1312 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1313 opentype_get_font_table(stream_desc, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
1315 /* default stretch, weight and style to normal */
1316 props->stretch = DWRITE_FONT_STRETCH_NORMAL;
1317 props->weight = DWRITE_FONT_WEIGHT_NORMAL;
1318 props->style = DWRITE_FONT_STYLE_NORMAL;
1319 memset(&props->panose, 0, sizeof(props->panose));
1320 memset(&props->fontsig, 0, sizeof(props->fontsig));
1321 memset(&props->lf, 0, sizeof(props->lf));
1323 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1324 if (tt_os2) {
1325 USHORT version = GET_BE_WORD(tt_os2->version);
1326 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
1327 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
1328 USHORT usWidthClass = GET_BE_WORD(tt_os2->usWidthClass);
1330 if (usWidthClass > DWRITE_FONT_STRETCH_UNDEFINED && usWidthClass <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
1331 props->stretch = usWidthClass;
1333 if (usWeightClass >= 1 && usWeightClass <= 9)
1334 usWeightClass *= 100;
1336 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
1337 props->weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
1338 else if (usWeightClass > 0)
1339 props->weight = usWeightClass;
1341 if (version >= 4 && (fsSelection & OS2_FSSELECTION_OBLIQUE))
1342 props->style = DWRITE_FONT_STYLE_OBLIQUE;
1343 else if (fsSelection & OS2_FSSELECTION_ITALIC)
1344 props->style = DWRITE_FONT_STYLE_ITALIC;
1346 memcpy(&props->panose, &tt_os2->panose, sizeof(props->panose));
1348 /* FONTSIGNATURE */
1349 props->fontsig.fsUsb[0] = GET_BE_DWORD(tt_os2->ulUnicodeRange1);
1350 props->fontsig.fsUsb[1] = GET_BE_DWORD(tt_os2->ulUnicodeRange2);
1351 props->fontsig.fsUsb[2] = GET_BE_DWORD(tt_os2->ulUnicodeRange3);
1352 props->fontsig.fsUsb[3] = GET_BE_DWORD(tt_os2->ulUnicodeRange4);
1354 if (GET_BE_WORD(tt_os2->version) == 0) {
1355 props->fontsig.fsCsb[0] = 0;
1356 props->fontsig.fsCsb[1] = 0;
1358 else {
1359 props->fontsig.fsCsb[0] = GET_BE_DWORD(tt_os2->ulCodePageRange1);
1360 props->fontsig.fsCsb[1] = GET_BE_DWORD(tt_os2->ulCodePageRange2);
1363 else if (tt_head) {
1364 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
1366 if (macStyle & TT_HEAD_MACSTYLE_CONDENSED)
1367 props->stretch = DWRITE_FONT_STRETCH_CONDENSED;
1368 else if (macStyle & TT_HEAD_MACSTYLE_EXTENDED)
1369 props->stretch = DWRITE_FONT_STRETCH_EXPANDED;
1371 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
1372 props->weight = DWRITE_FONT_WEIGHT_BOLD;
1374 if (macStyle & TT_HEAD_MACSTYLE_ITALIC)
1375 props->style = DWRITE_FONT_STYLE_ITALIC;
1378 props->lf.lfWeight = props->weight;
1379 props->lf.lfItalic = props->style == DWRITE_FONT_STYLE_ITALIC;
1381 TRACE("stretch=%d, weight=%d, style %d\n", props->stretch, props->weight, props->style);
1383 if (tt_os2)
1384 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1385 if (tt_head)
1386 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, head_context);
1389 static UINT get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform, USHORT encoding)
1391 UINT codepage = 0;
1393 switch (platform) {
1394 case OPENTYPE_PLATFORM_UNICODE:
1395 break;
1396 case OPENTYPE_PLATFORM_MAC:
1397 switch (encoding)
1399 case TT_NAME_MAC_ENCODING_ROMAN:
1400 codepage = 10000;
1401 break;
1402 case TT_NAME_MAC_ENCODING_JAPANESE:
1403 codepage = 10001;
1404 break;
1405 case TT_NAME_MAC_ENCODING_TRAD_CHINESE:
1406 codepage = 10002;
1407 break;
1408 case TT_NAME_MAC_ENCODING_KOREAN:
1409 codepage = 10003;
1410 break;
1411 case TT_NAME_MAC_ENCODING_ARABIC:
1412 codepage = 10004;
1413 break;
1414 case TT_NAME_MAC_ENCODING_HEBREW:
1415 codepage = 10005;
1416 break;
1417 case TT_NAME_MAC_ENCODING_GREEK:
1418 codepage = 10006;
1419 break;
1420 case TT_NAME_MAC_ENCODING_RUSSIAN:
1421 codepage = 10007;
1422 break;
1423 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE:
1424 codepage = 10008;
1425 break;
1426 case TT_NAME_MAC_ENCODING_THAI:
1427 codepage = 10021;
1428 break;
1429 default:
1430 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1431 break;
1433 break;
1434 case OPENTYPE_PLATFORM_WIN:
1435 switch (encoding)
1437 case TT_NAME_WINDOWS_ENCODING_SYMBOL:
1438 case TT_NAME_WINDOWS_ENCODING_UCS2:
1439 break;
1440 case TT_NAME_WINDOWS_ENCODING_SJIS:
1441 codepage = 932;
1442 break;
1443 case TT_NAME_WINDOWS_ENCODING_PRC:
1444 codepage = 936;
1445 break;
1446 case TT_NAME_WINDOWS_ENCODING_BIG5:
1447 codepage = 950;
1448 break;
1449 case TT_NAME_WINDOWS_ENCODING_WANSUNG:
1450 codepage = 20949;
1451 break;
1452 case TT_NAME_WINDOWS_ENCODING_JOHAB:
1453 codepage = 1361;
1454 break;
1455 default:
1456 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1457 break;
1459 break;
1460 default:
1461 FIXME("unknown platform %d\n", platform);
1464 return codepage;
1467 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform, USHORT lang_id, WCHAR *locale, USHORT locale_len)
1469 static const WCHAR enusW[] = {'e','n','-','U','S',0};
1471 switch (platform) {
1472 case OPENTYPE_PLATFORM_MAC:
1474 const char *locale_name = NULL;
1476 if (lang_id > TT_NAME_MAC_LANGID_AZER_ROMAN)
1477 WARN("invalid mac lang id %d\n", lang_id);
1478 else if (!name_mac_langid_to_locale[lang_id][0])
1479 FIXME("failed to map mac lang id %d to locale name\n", lang_id);
1480 else
1481 locale_name = name_mac_langid_to_locale[lang_id];
1483 if (locale_name)
1484 MultiByteToWideChar(CP_ACP, 0, name_mac_langid_to_locale[lang_id], -1, locale, locale_len);
1485 else
1486 strcpyW(locale, enusW);
1487 break;
1489 case OPENTYPE_PLATFORM_WIN:
1490 if (!LCIDToLocaleName(MAKELCID(lang_id, SORT_DEFAULT), locale, locale_len, 0)) {
1491 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id, SORT_DEFAULT));
1492 strcpyW(locale, enusW);
1494 break;
1495 case OPENTYPE_PLATFORM_UNICODE:
1496 strcpyW(locale, enusW);
1497 break;
1498 default:
1499 FIXME("unknown platform %d\n", platform);
1503 static BOOL opentype_decode_namerecord(const TT_NAME_V0 *header, BYTE *storage_area, USHORT recid, IDWriteLocalizedStrings *strings)
1505 const TT_NameRecord *record = &header->nameRecord[recid];
1506 USHORT lang_id, length, offset, encoding, platform;
1507 BOOL ret = FALSE;
1509 platform = GET_BE_WORD(record->platformID);
1510 lang_id = GET_BE_WORD(record->languageID);
1511 length = GET_BE_WORD(record->length);
1512 offset = GET_BE_WORD(record->offset);
1513 encoding = GET_BE_WORD(record->encodingID);
1515 if (lang_id < 0x8000) {
1516 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
1517 WCHAR *name_string;
1518 UINT codepage;
1520 codepage = get_name_record_codepage(platform, encoding);
1521 get_name_record_locale(platform, lang_id, locale, sizeof(locale)/sizeof(WCHAR));
1523 if (codepage) {
1524 DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0);
1525 name_string = heap_alloc(sizeof(WCHAR) * (len+1));
1526 MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len);
1527 name_string[len] = 0;
1529 else {
1530 int i;
1532 length /= sizeof(WCHAR);
1533 name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length);
1534 for (i = 0; i < length; i++)
1535 name_string[i] = GET_BE_WORD(name_string[i]);
1538 TRACE("string %s for locale %s found\n", debugstr_w(name_string), debugstr_w(locale));
1539 add_localizedstring(strings, locale, name_string);
1540 heap_free(name_string);
1541 ret = TRUE;
1543 else
1544 FIXME("handle NAME format 1\n");
1546 return ret;
1549 static HRESULT opentype_get_font_strings_from_id(const void *table_data, enum OPENTYPE_STRING_ID id, IDWriteLocalizedStrings **strings)
1551 const TT_NAME_V0 *header;
1552 BYTE *storage_area = 0;
1553 USHORT count = 0;
1554 int i, candidate;
1555 WORD format;
1556 BOOL exists;
1557 HRESULT hr;
1559 if (!table_data)
1560 return E_FAIL;
1562 hr = create_localizedstrings(strings);
1563 if (FAILED(hr)) return hr;
1565 header = table_data;
1566 format = GET_BE_WORD(header->format);
1568 switch (format) {
1569 case 0:
1570 case 1:
1571 break;
1572 default:
1573 FIXME("unsupported NAME format %d\n", format);
1576 storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset);
1577 count = GET_BE_WORD(header->count);
1579 exists = FALSE;
1580 candidate = -1;
1581 for (i = 0; i < count; i++) {
1582 const TT_NameRecord *record = &header->nameRecord[i];
1583 USHORT platform;
1585 if (GET_BE_WORD(record->nameID) != id)
1586 continue;
1588 /* Right now only accept unicode and windows encoded fonts */
1589 platform = GET_BE_WORD(record->platformID);
1590 if (platform != OPENTYPE_PLATFORM_UNICODE &&
1591 platform != OPENTYPE_PLATFORM_MAC &&
1592 platform != OPENTYPE_PLATFORM_WIN)
1594 FIXME("platform %i not supported\n", platform);
1595 continue;
1598 /* Skip such entries for now, fonts tend to duplicate those strings as
1599 WIN platform entries. If font does not have WIN or MAC entry for this id, we will
1600 use this Unicode platform entry while assuming en-US locale. */
1601 if (platform == OPENTYPE_PLATFORM_UNICODE) {
1602 candidate = i;
1603 continue;
1606 if (!opentype_decode_namerecord(header, storage_area, i, *strings))
1607 continue;
1609 exists = TRUE;
1612 if (!exists) {
1613 if (candidate != -1)
1614 exists = opentype_decode_namerecord(header, storage_area, candidate, *strings);
1615 else {
1616 IDWriteLocalizedStrings_Release(*strings);
1617 *strings = NULL;
1621 return exists ? S_OK : E_FAIL;
1624 /* Provides a conversion from DWRITE to OpenType name ids, input id should be valid, it's not checked. */
1625 HRESULT opentype_get_font_info_strings(const void *table_data, DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings)
1627 return opentype_get_font_strings_from_id(table_data, dwriteid_to_opentypeid[id], strings);
1630 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
1631 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
1632 HRESULT opentype_get_font_familyname(struct file_stream_desc *stream_desc, IDWriteLocalizedStrings **names)
1634 const TT_OS2_V2 *tt_os2;
1635 void *os2_context, *name_context;
1636 const void *name_table;
1637 HRESULT hr;
1639 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1640 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1642 *names = NULL;
1644 /* if Preferred Family doesn't conform to WWS model try WWS name */
1645 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1646 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_FAMILY_NAME, names);
1647 else
1648 hr = E_FAIL;
1650 if (FAILED(hr))
1651 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_FAMILY_NAME, names);
1652 if (FAILED(hr))
1653 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, names);
1655 if (tt_os2)
1656 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1657 if (name_context)
1658 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1660 return hr;
1663 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
1664 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
1665 HRESULT opentype_get_font_facename(struct file_stream_desc *stream_desc, WCHAR *lfname, IDWriteLocalizedStrings **names)
1667 IDWriteLocalizedStrings *lfnames;
1668 void *os2_context, *name_context;
1669 const TT_OS2_V2 *tt_os2;
1670 const void *name_table;
1671 HRESULT hr;
1673 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1674 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1676 *names = NULL;
1678 /* if Preferred Family doesn't conform to WWS model try WWS name */
1679 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1680 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_SUBFAMILY_NAME, names);
1681 else
1682 hr = E_FAIL;
1684 if (FAILED(hr))
1685 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME, names);
1686 if (FAILED(hr))
1687 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_SUBFAMILY_NAME, names);
1689 /* User locale is preferred, with fallback to en-us. */
1690 *lfname = 0;
1691 if (SUCCEEDED(opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, &lfnames))) {
1692 static const WCHAR enusW[] = {'e','n','-','u','s',0};
1693 WCHAR localeW[LOCALE_NAME_MAX_LENGTH];
1694 UINT32 index;
1695 BOOL exists;
1697 exists = FALSE;
1698 if (GetSystemDefaultLocaleName(localeW, sizeof(localeW)/sizeof(WCHAR)))
1699 IDWriteLocalizedStrings_FindLocaleName(lfnames, localeW, &index, &exists);
1701 if (!exists)
1702 IDWriteLocalizedStrings_FindLocaleName(lfnames, enusW, &index, &exists);
1704 if (exists)
1705 IDWriteLocalizedStrings_GetString(lfnames, index, lfname, LF_FACESIZE);
1707 IDWriteLocalizedStrings_Release(lfnames);
1710 if (tt_os2)
1711 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1712 if (name_context)
1713 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1715 return hr;
1718 static inline const OT_Script *opentype_get_script(const OT_ScriptList *scriptlist, UINT32 scripttag)
1720 UINT16 j;
1722 for (j = 0; j < GET_BE_WORD(scriptlist->ScriptCount); j++) {
1723 const char *tag = scriptlist->ScriptRecord[j].ScriptTag;
1724 if (scripttag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1725 return (OT_Script*)((BYTE*)scriptlist + GET_BE_WORD(scriptlist->ScriptRecord[j].Script));
1728 return NULL;
1731 static inline const OT_LangSys *opentype_get_langsys(const OT_Script *script, UINT32 languagetag)
1733 UINT16 j;
1735 for (j = 0; j < GET_BE_WORD(script->LangSysCount); j++) {
1736 const char *tag = script->LangSysRecord[j].LangSysTag;
1737 if (languagetag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1738 return (OT_LangSys*)((BYTE*)script + GET_BE_WORD(script->LangSysRecord[j].LangSys));
1741 return NULL;
1744 static void opentype_add_font_features(const GPOS_GSUB_Header *header, const OT_LangSys *langsys,
1745 UINT32 max_tagcount, UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1747 const OT_FeatureList *features = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
1748 UINT16 j;
1750 for (j = 0; j < GET_BE_WORD(langsys->FeatureCount); j++) {
1751 const OT_FeatureRecord *feature = &features->FeatureRecord[langsys->FeatureIndex[j]];
1752 const char *tag = feature->FeatureTag;
1754 if (*count < max_tagcount)
1755 tags[*count] = DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]);
1757 (*count)++;
1761 HRESULT opentype_get_typographic_features(IDWriteFontFace *fontface, UINT32 scripttag, UINT32 languagetag, UINT32 max_tagcount,
1762 UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1764 UINT32 tables[2] = { MS_GSUB_TAG, MS_GPOS_TAG };
1765 HRESULT hr;
1766 UINT8 i;
1768 *count = 0;
1769 for (i = 0; i < sizeof(tables)/sizeof(tables[0]); i++) {
1770 const OT_ScriptList *scriptlist;
1771 const GPOS_GSUB_Header *header;
1772 const OT_Script *script;
1773 const void *ptr;
1774 void *context;
1775 UINT32 size;
1776 BOOL exists;
1778 exists = FALSE;
1779 hr = IDWriteFontFace_TryGetFontTable(fontface, tables[i], &ptr, &size, &context, &exists);
1780 if (FAILED(hr))
1781 return hr;
1783 if (!exists)
1784 continue;
1786 header = (const GPOS_GSUB_Header*)ptr;
1787 scriptlist = (const OT_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
1789 script = opentype_get_script(scriptlist, scripttag);
1790 if (script) {
1791 const OT_LangSys *langsys = opentype_get_langsys(script, languagetag);
1792 if (langsys)
1793 opentype_add_font_features(header, langsys, max_tagcount, count, tags);
1796 IDWriteFontFace_ReleaseFontTable(fontface, context);
1799 return *count > max_tagcount ? E_NOT_SUFFICIENT_BUFFER : S_OK;
1802 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
1804 WORD num_ratios, i, group_offset = 0;
1805 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
1806 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
1808 num_ratios = GET_BE_WORD(hdr->numRatios);
1810 for (i = 0; i < num_ratios; i++) {
1812 if (!ratios[i].bCharSet) continue;
1814 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
1815 ratios[i].yEndRatio == 0) ||
1816 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
1817 ratios[i].yEndRatio >= dev_y_ratio))
1819 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
1820 break;
1823 if (group_offset)
1824 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
1825 return NULL;
1828 BOOL opentype_get_vdmx_size(const void *data, INT emsize, UINT16 *ascent, UINT16 *descent)
1830 const struct VDMX_Header *hdr = (const struct VDMX_Header*)data;
1831 const struct VDMX_group *group;
1832 const struct VDMX_vTable *tables;
1833 WORD recs, i;
1835 if (!data)
1836 return FALSE;
1838 group = find_vdmx_group(hdr);
1839 if (!group)
1840 return FALSE;
1842 recs = GET_BE_WORD(group->recs);
1843 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
1845 tables = (const struct VDMX_vTable *)(group + 1);
1846 for (i = 0; i < recs; i++) {
1847 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
1848 if (ppem > emsize) {
1849 FIXME("interpolate %d\n", emsize);
1850 return FALSE;
1853 if (ppem == emsize) {
1854 *ascent = (SHORT)GET_BE_WORD(tables[i].yMax);
1855 *descent = -(SHORT)GET_BE_WORD(tables[i].yMin);
1856 return TRUE;
1859 return FALSE;
1862 WORD opentype_get_gasp_flags(const WORD *ptr, UINT32 size, INT emsize)
1864 WORD num_recs, version;
1865 WORD flags = 0;
1867 if (!ptr)
1868 return 0;
1870 version = GET_BE_WORD( *ptr++ );
1871 num_recs = GET_BE_WORD( *ptr++ );
1872 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
1873 ERR("unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
1874 goto done;
1877 while (num_recs--) {
1878 flags = GET_BE_WORD( *(ptr + 1) );
1879 if (emsize <= GET_BE_WORD( *ptr )) break;
1880 ptr += 2;
1883 done:
1884 return flags;
1887 UINT32 opentype_get_cpal_palettecount(const void *cpal)
1889 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1890 return header ? GET_BE_WORD(header->numPalette) : 0;
1893 UINT32 opentype_get_cpal_paletteentrycount(const void *cpal)
1895 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1896 return header ? GET_BE_WORD(header->numPaletteEntries) : 0;
1899 HRESULT opentype_get_cpal_entries(const void *cpal, UINT32 palette, UINT32 first_entry_index, UINT32 entry_count,
1900 DWRITE_COLOR_F *entries)
1902 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1903 const struct CPAL_ColorRecord *records;
1904 UINT32 palettecount, entrycount, i;
1906 if (!header) return DWRITE_E_NOCOLOR;
1908 palettecount = GET_BE_WORD(header->numPalette);
1909 if (palette >= palettecount)
1910 return DWRITE_E_NOCOLOR;
1912 entrycount = GET_BE_WORD(header->numPaletteEntries);
1913 if (first_entry_index + entry_count > entrycount)
1914 return E_INVALIDARG;
1916 records = (const struct CPAL_ColorRecord*)((BYTE*)cpal + GET_BE_DWORD(header->offsetFirstColorRecord));
1917 first_entry_index += GET_BE_WORD(header->colorRecordIndices[palette]);
1919 for (i = 0; i < entry_count; i++) {
1920 entries[i].u1.r = records[first_entry_index + i].red / 255.0f;
1921 entries[i].u2.g = records[first_entry_index + i].green / 255.0f;
1922 entries[i].u3.b = records[first_entry_index + i].blue / 255.0f;
1923 entries[i].u4.a = records[first_entry_index + i].alpha / 255.0f;
1926 return S_OK;
1929 static int colr_compare_gid(const void *g, const void *r)
1931 const struct COLR_BaseGlyphRecord *record = r;
1932 UINT16 glyph = *(UINT16*)g, GID = GET_BE_WORD(record->GID);
1933 int ret = 0;
1935 if (glyph > GID)
1936 ret = 1;
1937 else if (glyph < GID)
1938 ret = -1;
1940 return ret;
1943 HRESULT opentype_get_colr_glyph(const void *colr, UINT16 glyph, struct dwrite_colorglyph *ret)
1945 const struct COLR_BaseGlyphRecord *record;
1946 const struct COLR_Header *header = colr;
1947 const struct COLR_LayerRecord *layer;
1948 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
1949 DWORD baserecordoffset = GET_BE_DWORD(header->offsetBaseGlyphRecord);
1950 WORD numbaserecords = GET_BE_WORD(header->numBaseGlyphRecords);
1952 record = bsearch(&glyph, (BYTE*)colr + baserecordoffset, numbaserecords, sizeof(struct COLR_BaseGlyphRecord),
1953 colr_compare_gid);
1954 if (!record) {
1955 ret->layer = 0;
1956 ret->first_layer = 0;
1957 ret->num_layers = 0;
1958 ret->glyph = glyph;
1959 ret->palette_index = 0xffff;
1960 return S_FALSE;
1963 ret->layer = 0;
1964 ret->first_layer = GET_BE_WORD(record->firstLayerIndex);
1965 ret->num_layers = GET_BE_WORD(record->numLayers);
1967 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + ret->first_layer + ret->layer;
1968 ret->glyph = GET_BE_WORD(layer->GID);
1969 ret->palette_index = GET_BE_WORD(layer->paletteIndex);
1971 return S_OK;
1974 void opentype_colr_next_glyph(const void *colr, struct dwrite_colorglyph *glyph)
1976 const struct COLR_Header *header = colr;
1977 const struct COLR_LayerRecord *layer;
1978 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
1980 /* iterated all the way through */
1981 if (glyph->layer == glyph->num_layers)
1982 return;
1984 glyph->layer++;
1985 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + glyph->first_layer + glyph->layer;
1986 glyph->glyph = GET_BE_WORD(layer->GID);
1987 glyph->palette_index = GET_BE_WORD(layer->paletteIndex);
1990 BOOL opentype_has_vertical_variants(IDWriteFontFace4 *fontface)
1992 const OT_FeatureList *featurelist;
1993 const OT_LookupList *lookup_list;
1994 BOOL exists = FALSE, ret = FALSE;
1995 const GPOS_GSUB_Header *header;
1996 const void *data;
1997 void *context;
1998 UINT32 size;
1999 HRESULT hr;
2000 UINT16 i;
2002 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
2003 if (FAILED(hr) || !exists)
2004 return FALSE;
2006 header = data;
2007 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
2008 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
2010 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
2011 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
2012 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
2013 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
2014 const GSUB_SingleSubstFormat2 *subst2;
2015 const OT_LookupTable *lookup_table;
2016 UINT32 offset;
2018 if (lookup_count == 0)
2019 continue;
2021 for (i = 0; i < lookup_count; i++) {
2022 /* check if lookup is empty */
2023 index = GET_BE_WORD(feature->LookupListIndex[i]);
2024 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
2026 type = GET_BE_WORD(lookup_table->LookupType);
2027 if (type != OPENTYPE_GPOS_SINGLE_SUBST && type != OPENTYPE_GPOS_EXTENSION_SUBST)
2028 continue;
2030 count = GET_BE_WORD(lookup_table->SubTableCount);
2031 if (count == 0)
2032 continue;
2034 offset = GET_BE_WORD(lookup_table->SubTable[0]);
2035 if (type == OPENTYPE_GPOS_EXTENSION_SUBST) {
2036 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
2037 if (GET_BE_WORD(ext->SubstFormat) == 1)
2038 offset += GET_BE_DWORD(ext->ExtensionOffset);
2039 else
2040 FIXME("Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
2043 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
2044 index = GET_BE_WORD(subst2->SubstFormat);
2045 if (index == 1)
2046 FIXME("Validate Single Substitution Format 1\n");
2047 else if (index == 2) {
2048 /* SimSun-ExtB has 0 glyph count for this substitution */
2049 if (GET_BE_WORD(subst2->GlyphCount) > 0) {
2050 ret = TRUE;
2051 break;
2054 else
2055 WARN("Unknown Single Substitution Format, %u\n", index);
2060 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2062 return ret;
2065 static BOOL opentype_has_font_table(IDWriteFontFace4 *fontface, UINT32 tag)
2067 BOOL exists = FALSE;
2068 const void *data;
2069 void *context;
2070 UINT32 size;
2071 HRESULT hr;
2073 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, &data, &size, &context, &exists);
2074 if (FAILED(hr))
2075 return FALSE;
2077 if (exists)
2078 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2080 return exists;
2083 static DWORD opentype_get_sbix_formats(IDWriteFontFace4 *fontface)
2085 UINT32 size, s, num_strikes;
2086 const sbix_header *header;
2087 UINT16 g, num_glyphs;
2088 BOOL exists = FALSE;
2089 const maxp *maxp;
2090 const void *data;
2091 DWORD ret = 0;
2092 void *context;
2093 HRESULT hr;
2095 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_MAXP_TAG, &data, &size, &context, &exists);
2096 if (FAILED(hr) || !exists)
2097 return 0;
2099 maxp = data;
2100 num_glyphs = GET_BE_WORD(maxp->numGlyphs);
2102 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2104 if (FAILED(IDWriteFontFace4_TryGetFontTable(fontface, MS_SBIX_TAG, &data, &size, &context, &exists))) {
2105 WARN("Failed to get 'sbix' table, %#x\n", hr);
2106 return 0;
2109 header = data;
2110 num_strikes = GET_BE_DWORD(header->numStrikes);
2112 for (s = 0; s < num_strikes; s++) {
2113 sbix_strike *strike = (sbix_strike *)((BYTE *)header + GET_BE_DWORD(header->strikeOffset[s]));
2115 for (g = 0; g < num_glyphs; g++) {
2116 DWORD offset = GET_BE_DWORD(strike->glyphDataOffsets[g]);
2117 DWORD offset_next = GET_BE_DWORD(strike->glyphDataOffsets[g + 1]);
2118 sbix_glyph_data *glyph_data;
2119 DWORD format;
2121 if (offset == offset_next)
2122 continue;
2124 glyph_data = (sbix_glyph_data *)((BYTE *)strike + offset);
2125 switch (format = glyph_data->graphicType)
2127 case MS_PNG__TAG:
2128 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
2129 break;
2130 case MS_JPG__TAG:
2131 ret |= DWRITE_GLYPH_IMAGE_FORMATS_JPEG;
2132 break;
2133 case MS_TIFF_TAG:
2134 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TIFF;
2135 break;
2136 default:
2137 format = GET_BE_DWORD(format);
2138 FIXME("unexpected bitmap format %s\n", debugstr_an((char *)&format, 4));
2143 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2145 return ret;
2148 UINT32 opentype_get_glyph_image_formats(IDWriteFontFace4 *fontface)
2150 UINT32 ret = DWRITE_GLYPH_IMAGE_FORMATS_NONE;
2152 if (opentype_has_font_table(fontface, MS_GLYF_TAG))
2153 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
2155 if (opentype_has_font_table(fontface, MS_CFF__TAG))
2156 ret |= DWRITE_GLYPH_IMAGE_FORMATS_CFF;
2158 if (opentype_has_font_table(fontface, MS_COLR_TAG))
2159 ret |= DWRITE_GLYPH_IMAGE_FORMATS_COLR;
2161 if (opentype_has_font_table(fontface, MS_SVG__TAG))
2162 ret |= DWRITE_GLYPH_IMAGE_FORMATS_SVG;
2164 if (opentype_has_font_table(fontface, MS_SBIX_TAG))
2165 ret |= opentype_get_sbix_formats(fontface);
2167 /* TODO: handle embedded bitmaps tables */
2168 return ret;