wininet/tests: Added more persistent connection tests.
[wine.git] / dlls / dwrite / opentype.c
bloba66500a73b9dc1da57377cbbadf83f7d03ecfc82
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->lf, 0, sizeof(props->lf));
1322 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1323 if (tt_os2) {
1324 USHORT version = GET_BE_WORD(tt_os2->version);
1325 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
1326 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
1327 USHORT usWidthClass = GET_BE_WORD(tt_os2->usWidthClass);
1329 if (usWidthClass > DWRITE_FONT_STRETCH_UNDEFINED && usWidthClass <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
1330 props->stretch = usWidthClass;
1332 if (usWeightClass >= 1 && usWeightClass <= 9)
1333 usWeightClass *= 100;
1335 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
1336 props->weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
1337 else if (usWeightClass > 0)
1338 props->weight = usWeightClass;
1340 if (version >= 4 && (fsSelection & OS2_FSSELECTION_OBLIQUE))
1341 props->style = DWRITE_FONT_STYLE_OBLIQUE;
1342 else if (fsSelection & OS2_FSSELECTION_ITALIC)
1343 props->style = DWRITE_FONT_STYLE_ITALIC;
1345 memcpy(&props->panose, &tt_os2->panose, sizeof(props->panose));
1347 else if (tt_head) {
1348 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
1350 if (macStyle & TT_HEAD_MACSTYLE_CONDENSED)
1351 props->stretch = DWRITE_FONT_STRETCH_CONDENSED;
1352 else if (macStyle & TT_HEAD_MACSTYLE_EXTENDED)
1353 props->stretch = DWRITE_FONT_STRETCH_EXPANDED;
1355 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
1356 props->weight = DWRITE_FONT_WEIGHT_BOLD;
1358 if (macStyle & TT_HEAD_MACSTYLE_ITALIC)
1359 props->style = DWRITE_FONT_STYLE_ITALIC;
1362 props->lf.lfWeight = props->weight;
1363 props->lf.lfItalic = props->style == DWRITE_FONT_STYLE_ITALIC;
1365 TRACE("stretch=%d, weight=%d, style %d\n", props->stretch, props->weight, props->style);
1367 if (tt_os2)
1368 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1369 if (tt_head)
1370 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, head_context);
1373 static UINT get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform, USHORT encoding)
1375 UINT codepage = 0;
1377 switch (platform) {
1378 case OPENTYPE_PLATFORM_UNICODE:
1379 break;
1380 case OPENTYPE_PLATFORM_MAC:
1381 switch (encoding)
1383 case TT_NAME_MAC_ENCODING_ROMAN:
1384 codepage = 10000;
1385 break;
1386 case TT_NAME_MAC_ENCODING_JAPANESE:
1387 codepage = 10001;
1388 break;
1389 case TT_NAME_MAC_ENCODING_TRAD_CHINESE:
1390 codepage = 10002;
1391 break;
1392 case TT_NAME_MAC_ENCODING_KOREAN:
1393 codepage = 10003;
1394 break;
1395 case TT_NAME_MAC_ENCODING_ARABIC:
1396 codepage = 10004;
1397 break;
1398 case TT_NAME_MAC_ENCODING_HEBREW:
1399 codepage = 10005;
1400 break;
1401 case TT_NAME_MAC_ENCODING_GREEK:
1402 codepage = 10006;
1403 break;
1404 case TT_NAME_MAC_ENCODING_RUSSIAN:
1405 codepage = 10007;
1406 break;
1407 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE:
1408 codepage = 10008;
1409 break;
1410 case TT_NAME_MAC_ENCODING_THAI:
1411 codepage = 10021;
1412 break;
1413 default:
1414 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1415 break;
1417 break;
1418 case OPENTYPE_PLATFORM_WIN:
1419 switch (encoding)
1421 case TT_NAME_WINDOWS_ENCODING_SYMBOL:
1422 case TT_NAME_WINDOWS_ENCODING_UCS2:
1423 break;
1424 case TT_NAME_WINDOWS_ENCODING_SJIS:
1425 codepage = 932;
1426 break;
1427 case TT_NAME_WINDOWS_ENCODING_PRC:
1428 codepage = 936;
1429 break;
1430 case TT_NAME_WINDOWS_ENCODING_BIG5:
1431 codepage = 950;
1432 break;
1433 case TT_NAME_WINDOWS_ENCODING_WANSUNG:
1434 codepage = 20949;
1435 break;
1436 case TT_NAME_WINDOWS_ENCODING_JOHAB:
1437 codepage = 1361;
1438 break;
1439 default:
1440 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1441 break;
1443 break;
1444 default:
1445 FIXME("unknown platform %d\n", platform);
1448 return codepage;
1451 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform, USHORT lang_id, WCHAR *locale, USHORT locale_len)
1453 static const WCHAR enusW[] = {'e','n','-','U','S',0};
1455 switch (platform) {
1456 case OPENTYPE_PLATFORM_MAC:
1458 const char *locale_name = NULL;
1460 if (lang_id > TT_NAME_MAC_LANGID_AZER_ROMAN)
1461 WARN("invalid mac lang id %d\n", lang_id);
1462 else if (!name_mac_langid_to_locale[lang_id][0])
1463 FIXME("failed to map mac lang id %d to locale name\n", lang_id);
1464 else
1465 locale_name = name_mac_langid_to_locale[lang_id];
1467 if (locale_name)
1468 MultiByteToWideChar(CP_ACP, 0, name_mac_langid_to_locale[lang_id], -1, locale, locale_len);
1469 else
1470 strcpyW(locale, enusW);
1471 break;
1473 case OPENTYPE_PLATFORM_WIN:
1474 if (!LCIDToLocaleName(MAKELCID(lang_id, SORT_DEFAULT), locale, locale_len, 0)) {
1475 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id, SORT_DEFAULT));
1476 strcpyW(locale, enusW);
1478 break;
1479 case OPENTYPE_PLATFORM_UNICODE:
1480 strcpyW(locale, enusW);
1481 break;
1482 default:
1483 FIXME("unknown platform %d\n", platform);
1487 static BOOL opentype_decode_namerecord(const TT_NAME_V0 *header, BYTE *storage_area, USHORT recid, IDWriteLocalizedStrings *strings)
1489 const TT_NameRecord *record = &header->nameRecord[recid];
1490 USHORT lang_id, length, offset, encoding, platform;
1491 BOOL ret = FALSE;
1493 platform = GET_BE_WORD(record->platformID);
1494 lang_id = GET_BE_WORD(record->languageID);
1495 length = GET_BE_WORD(record->length);
1496 offset = GET_BE_WORD(record->offset);
1497 encoding = GET_BE_WORD(record->encodingID);
1499 if (lang_id < 0x8000) {
1500 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
1501 WCHAR *name_string;
1502 UINT codepage;
1504 codepage = get_name_record_codepage(platform, encoding);
1505 get_name_record_locale(platform, lang_id, locale, sizeof(locale)/sizeof(WCHAR));
1507 if (codepage) {
1508 DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0);
1509 name_string = heap_alloc(sizeof(WCHAR) * (len+1));
1510 MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len);
1511 name_string[len] = 0;
1513 else {
1514 int i;
1516 length /= sizeof(WCHAR);
1517 name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length);
1518 for (i = 0; i < length; i++)
1519 name_string[i] = GET_BE_WORD(name_string[i]);
1522 TRACE("string %s for locale %s found\n", debugstr_w(name_string), debugstr_w(locale));
1523 add_localizedstring(strings, locale, name_string);
1524 heap_free(name_string);
1525 ret = TRUE;
1527 else
1528 FIXME("handle NAME format 1\n");
1530 return ret;
1533 static HRESULT opentype_get_font_strings_from_id(const void *table_data, enum OPENTYPE_STRING_ID id, IDWriteLocalizedStrings **strings)
1535 const TT_NAME_V0 *header;
1536 BYTE *storage_area = 0;
1537 USHORT count = 0;
1538 int i, candidate;
1539 WORD format;
1540 BOOL exists;
1541 HRESULT hr;
1543 if (!table_data)
1544 return E_FAIL;
1546 hr = create_localizedstrings(strings);
1547 if (FAILED(hr)) return hr;
1549 header = table_data;
1550 format = GET_BE_WORD(header->format);
1552 switch (format) {
1553 case 0:
1554 case 1:
1555 break;
1556 default:
1557 FIXME("unsupported NAME format %d\n", format);
1560 storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset);
1561 count = GET_BE_WORD(header->count);
1563 exists = FALSE;
1564 candidate = -1;
1565 for (i = 0; i < count; i++) {
1566 const TT_NameRecord *record = &header->nameRecord[i];
1567 USHORT platform;
1569 if (GET_BE_WORD(record->nameID) != id)
1570 continue;
1572 /* Right now only accept unicode and windows encoded fonts */
1573 platform = GET_BE_WORD(record->platformID);
1574 if (platform != OPENTYPE_PLATFORM_UNICODE &&
1575 platform != OPENTYPE_PLATFORM_MAC &&
1576 platform != OPENTYPE_PLATFORM_WIN)
1578 FIXME("platform %i not supported\n", platform);
1579 continue;
1582 /* Skip such entries for now, fonts tend to duplicate those strings as
1583 WIN platform entries. If font does not have WIN or MAC entry for this id, we will
1584 use this Unicode platform entry while assuming en-US locale. */
1585 if (platform == OPENTYPE_PLATFORM_UNICODE) {
1586 candidate = i;
1587 continue;
1590 if (!opentype_decode_namerecord(header, storage_area, i, *strings))
1591 continue;
1593 exists = TRUE;
1596 if (!exists) {
1597 if (candidate != -1)
1598 exists = opentype_decode_namerecord(header, storage_area, candidate, *strings);
1599 else {
1600 IDWriteLocalizedStrings_Release(*strings);
1601 *strings = NULL;
1605 return exists ? S_OK : E_FAIL;
1608 /* Provides a conversion from DWRITE to OpenType name ids, input id should be valid, it's not checked. */
1609 HRESULT opentype_get_font_info_strings(const void *table_data, DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings)
1611 return opentype_get_font_strings_from_id(table_data, dwriteid_to_opentypeid[id], strings);
1614 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
1615 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
1616 HRESULT opentype_get_font_familyname(struct file_stream_desc *stream_desc, IDWriteLocalizedStrings **names)
1618 const TT_OS2_V2 *tt_os2;
1619 void *os2_context, *name_context;
1620 const void *name_table;
1621 HRESULT hr;
1623 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1624 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1626 *names = NULL;
1628 /* if Preferred Family doesn't conform to WWS model try WWS name */
1629 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1630 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_FAMILY_NAME, names);
1631 else
1632 hr = E_FAIL;
1634 if (FAILED(hr))
1635 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_FAMILY_NAME, names);
1636 if (FAILED(hr))
1637 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, names);
1639 if (tt_os2)
1640 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1641 if (name_context)
1642 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1644 return hr;
1647 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
1648 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
1649 HRESULT opentype_get_font_facename(struct file_stream_desc *stream_desc, WCHAR *lfname, IDWriteLocalizedStrings **names)
1651 IDWriteLocalizedStrings *lfnames;
1652 void *os2_context, *name_context;
1653 const TT_OS2_V2 *tt_os2;
1654 const void *name_table;
1655 HRESULT hr;
1657 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1658 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1660 *names = NULL;
1662 /* if Preferred Family doesn't conform to WWS model try WWS name */
1663 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1664 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_SUBFAMILY_NAME, names);
1665 else
1666 hr = E_FAIL;
1668 if (FAILED(hr))
1669 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME, names);
1670 if (FAILED(hr))
1671 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_SUBFAMILY_NAME, names);
1673 /* User locale is preferred, with fallback to en-us. */
1674 *lfname = 0;
1675 if (SUCCEEDED(opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, &lfnames))) {
1676 static const WCHAR enusW[] = {'e','n','-','u','s',0};
1677 WCHAR localeW[LOCALE_NAME_MAX_LENGTH];
1678 UINT32 index;
1679 BOOL exists;
1681 exists = FALSE;
1682 if (GetSystemDefaultLocaleName(localeW, sizeof(localeW)/sizeof(WCHAR)))
1683 IDWriteLocalizedStrings_FindLocaleName(lfnames, localeW, &index, &exists);
1685 if (!exists)
1686 IDWriteLocalizedStrings_FindLocaleName(lfnames, enusW, &index, &exists);
1688 if (exists)
1689 IDWriteLocalizedStrings_GetString(lfnames, index, lfname, LF_FACESIZE);
1691 IDWriteLocalizedStrings_Release(lfnames);
1694 if (tt_os2)
1695 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1696 if (name_context)
1697 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1699 return hr;
1702 static inline const OT_Script *opentype_get_script(const OT_ScriptList *scriptlist, UINT32 scripttag)
1704 UINT16 j;
1706 for (j = 0; j < GET_BE_WORD(scriptlist->ScriptCount); j++) {
1707 const char *tag = scriptlist->ScriptRecord[j].ScriptTag;
1708 if (scripttag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1709 return (OT_Script*)((BYTE*)scriptlist + GET_BE_WORD(scriptlist->ScriptRecord[j].Script));
1712 return NULL;
1715 static inline const OT_LangSys *opentype_get_langsys(const OT_Script *script, UINT32 languagetag)
1717 UINT16 j;
1719 for (j = 0; j < GET_BE_WORD(script->LangSysCount); j++) {
1720 const char *tag = script->LangSysRecord[j].LangSysTag;
1721 if (languagetag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1722 return (OT_LangSys*)((BYTE*)script + GET_BE_WORD(script->LangSysRecord[j].LangSys));
1725 return NULL;
1728 static void opentype_add_font_features(const GPOS_GSUB_Header *header, const OT_LangSys *langsys,
1729 UINT32 max_tagcount, UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1731 const OT_FeatureList *features = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
1732 UINT16 j;
1734 for (j = 0; j < GET_BE_WORD(langsys->FeatureCount); j++) {
1735 const OT_FeatureRecord *feature = &features->FeatureRecord[langsys->FeatureIndex[j]];
1736 const char *tag = feature->FeatureTag;
1738 if (*count < max_tagcount)
1739 tags[*count] = DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]);
1741 (*count)++;
1745 HRESULT opentype_get_typographic_features(IDWriteFontFace *fontface, UINT32 scripttag, UINT32 languagetag, UINT32 max_tagcount,
1746 UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1748 UINT32 tables[2] = { MS_GSUB_TAG, MS_GPOS_TAG };
1749 HRESULT hr;
1750 UINT8 i;
1752 *count = 0;
1753 for (i = 0; i < sizeof(tables)/sizeof(tables[0]); i++) {
1754 const OT_ScriptList *scriptlist;
1755 const GPOS_GSUB_Header *header;
1756 const OT_Script *script;
1757 const void *ptr;
1758 void *context;
1759 UINT32 size;
1760 BOOL exists;
1762 exists = FALSE;
1763 hr = IDWriteFontFace_TryGetFontTable(fontface, tables[i], &ptr, &size, &context, &exists);
1764 if (FAILED(hr))
1765 return hr;
1767 if (!exists)
1768 continue;
1770 header = (const GPOS_GSUB_Header*)ptr;
1771 scriptlist = (const OT_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
1773 script = opentype_get_script(scriptlist, scripttag);
1774 if (script) {
1775 const OT_LangSys *langsys = opentype_get_langsys(script, languagetag);
1776 if (langsys)
1777 opentype_add_font_features(header, langsys, max_tagcount, count, tags);
1780 IDWriteFontFace_ReleaseFontTable(fontface, context);
1783 return *count > max_tagcount ? E_NOT_SUFFICIENT_BUFFER : S_OK;
1786 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
1788 WORD num_ratios, i, group_offset = 0;
1789 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
1790 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
1792 num_ratios = GET_BE_WORD(hdr->numRatios);
1794 for (i = 0; i < num_ratios; i++) {
1796 if (!ratios[i].bCharSet) continue;
1798 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
1799 ratios[i].yEndRatio == 0) ||
1800 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
1801 ratios[i].yEndRatio >= dev_y_ratio))
1803 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
1804 break;
1807 if (group_offset)
1808 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
1809 return NULL;
1812 BOOL opentype_get_vdmx_size(const void *data, INT emsize, UINT16 *ascent, UINT16 *descent)
1814 const struct VDMX_Header *hdr = (const struct VDMX_Header*)data;
1815 const struct VDMX_group *group;
1816 const struct VDMX_vTable *tables;
1817 WORD recs, i;
1819 if (!data)
1820 return FALSE;
1822 group = find_vdmx_group(hdr);
1823 if (!group)
1824 return FALSE;
1826 recs = GET_BE_WORD(group->recs);
1827 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
1829 tables = (const struct VDMX_vTable *)(group + 1);
1830 for (i = 0; i < recs; i++) {
1831 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
1832 if (ppem > emsize) {
1833 FIXME("interpolate %d\n", emsize);
1834 return FALSE;
1837 if (ppem == emsize) {
1838 *ascent = (SHORT)GET_BE_WORD(tables[i].yMax);
1839 *descent = -(SHORT)GET_BE_WORD(tables[i].yMin);
1840 return TRUE;
1843 return FALSE;
1846 WORD opentype_get_gasp_flags(const WORD *ptr, UINT32 size, INT emsize)
1848 WORD num_recs, version;
1849 WORD flags = 0;
1851 if (!ptr)
1852 return 0;
1854 version = GET_BE_WORD( *ptr++ );
1855 num_recs = GET_BE_WORD( *ptr++ );
1856 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
1857 ERR("unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
1858 goto done;
1861 while (num_recs--) {
1862 flags = GET_BE_WORD( *(ptr + 1) );
1863 if (emsize <= GET_BE_WORD( *ptr )) break;
1864 ptr += 2;
1867 done:
1868 return flags;
1871 UINT32 opentype_get_cpal_palettecount(const void *cpal)
1873 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1874 return header ? GET_BE_WORD(header->numPalette) : 0;
1877 UINT32 opentype_get_cpal_paletteentrycount(const void *cpal)
1879 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1880 return header ? GET_BE_WORD(header->numPaletteEntries) : 0;
1883 HRESULT opentype_get_cpal_entries(const void *cpal, UINT32 palette, UINT32 first_entry_index, UINT32 entry_count,
1884 DWRITE_COLOR_F *entries)
1886 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1887 const struct CPAL_ColorRecord *records;
1888 UINT32 palettecount, entrycount, i;
1890 if (!header) return DWRITE_E_NOCOLOR;
1892 palettecount = GET_BE_WORD(header->numPalette);
1893 if (palette >= palettecount)
1894 return DWRITE_E_NOCOLOR;
1896 entrycount = GET_BE_WORD(header->numPaletteEntries);
1897 if (first_entry_index + entry_count > entrycount)
1898 return E_INVALIDARG;
1900 records = (const struct CPAL_ColorRecord*)((BYTE*)cpal + GET_BE_DWORD(header->offsetFirstColorRecord));
1901 first_entry_index += GET_BE_WORD(header->colorRecordIndices[palette]);
1903 for (i = 0; i < entry_count; i++) {
1904 entries[i].u1.r = records[first_entry_index + i].red / 255.0f;
1905 entries[i].u2.g = records[first_entry_index + i].green / 255.0f;
1906 entries[i].u3.b = records[first_entry_index + i].blue / 255.0f;
1907 entries[i].u4.a = records[first_entry_index + i].alpha / 255.0f;
1910 return S_OK;
1913 static int colr_compare_gid(const void *g, const void *r)
1915 const struct COLR_BaseGlyphRecord *record = r;
1916 UINT16 glyph = *(UINT16*)g, GID = GET_BE_WORD(record->GID);
1917 int ret = 0;
1919 if (glyph > GID)
1920 ret = 1;
1921 else if (glyph < GID)
1922 ret = -1;
1924 return ret;
1927 HRESULT opentype_get_colr_glyph(const void *colr, UINT16 glyph, struct dwrite_colorglyph *ret)
1929 const struct COLR_BaseGlyphRecord *record;
1930 const struct COLR_Header *header = colr;
1931 const struct COLR_LayerRecord *layer;
1932 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
1933 DWORD baserecordoffset = GET_BE_DWORD(header->offsetBaseGlyphRecord);
1934 WORD numbaserecords = GET_BE_WORD(header->numBaseGlyphRecords);
1936 record = bsearch(&glyph, (BYTE*)colr + baserecordoffset, numbaserecords, sizeof(struct COLR_BaseGlyphRecord),
1937 colr_compare_gid);
1938 if (!record) {
1939 ret->layer = 0;
1940 ret->first_layer = 0;
1941 ret->num_layers = 0;
1942 ret->glyph = glyph;
1943 ret->palette_index = 0xffff;
1944 return S_FALSE;
1947 ret->layer = 0;
1948 ret->first_layer = GET_BE_WORD(record->firstLayerIndex);
1949 ret->num_layers = GET_BE_WORD(record->numLayers);
1951 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + ret->first_layer + ret->layer;
1952 ret->glyph = GET_BE_WORD(layer->GID);
1953 ret->palette_index = GET_BE_WORD(layer->paletteIndex);
1955 return S_OK;
1958 void opentype_colr_next_glyph(const void *colr, struct dwrite_colorglyph *glyph)
1960 const struct COLR_Header *header = colr;
1961 const struct COLR_LayerRecord *layer;
1962 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
1964 /* iterated all the way through */
1965 if (glyph->layer == glyph->num_layers)
1966 return;
1968 glyph->layer++;
1969 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + glyph->first_layer + glyph->layer;
1970 glyph->glyph = GET_BE_WORD(layer->GID);
1971 glyph->palette_index = GET_BE_WORD(layer->paletteIndex);
1974 HRESULT opentype_get_font_signature(struct file_stream_desc *stream_desc, FONTSIGNATURE *fontsig)
1976 const TT_OS2_V2 *tt_os2;
1977 void *os2_context;
1978 HRESULT hr;
1980 hr = opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1981 if (tt_os2) {
1982 fontsig->fsUsb[0] = GET_BE_DWORD(tt_os2->ulUnicodeRange1);
1983 fontsig->fsUsb[1] = GET_BE_DWORD(tt_os2->ulUnicodeRange2);
1984 fontsig->fsUsb[2] = GET_BE_DWORD(tt_os2->ulUnicodeRange3);
1985 fontsig->fsUsb[3] = GET_BE_DWORD(tt_os2->ulUnicodeRange4);
1987 if (GET_BE_WORD(tt_os2->version) == 0) {
1988 fontsig->fsCsb[0] = 0;
1989 fontsig->fsCsb[1] = 0;
1991 else {
1992 fontsig->fsCsb[0] = GET_BE_DWORD(tt_os2->ulCodePageRange1);
1993 fontsig->fsCsb[1] = GET_BE_DWORD(tt_os2->ulCodePageRange2);
1996 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1999 return hr;
2002 BOOL opentype_has_vertical_variants(IDWriteFontFace4 *fontface)
2004 const OT_FeatureList *featurelist;
2005 const OT_LookupList *lookup_list;
2006 BOOL exists = FALSE, ret = FALSE;
2007 const GPOS_GSUB_Header *header;
2008 const void *data;
2009 void *context;
2010 UINT32 size;
2011 HRESULT hr;
2012 UINT16 i;
2014 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
2015 if (FAILED(hr) || !exists)
2016 return FALSE;
2018 header = data;
2019 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
2020 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
2022 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
2023 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
2024 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
2025 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
2026 const GSUB_SingleSubstFormat2 *subst2;
2027 const OT_LookupTable *lookup_table;
2028 UINT32 offset;
2030 if (lookup_count == 0)
2031 continue;
2033 for (i = 0; i < lookup_count; i++) {
2034 /* check if lookup is empty */
2035 index = GET_BE_WORD(feature->LookupListIndex[i]);
2036 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
2038 type = GET_BE_WORD(lookup_table->LookupType);
2039 if (type != OPENTYPE_GPOS_SINGLE_SUBST && type != OPENTYPE_GPOS_EXTENSION_SUBST)
2040 continue;
2042 count = GET_BE_WORD(lookup_table->SubTableCount);
2043 if (count == 0)
2044 continue;
2046 offset = GET_BE_WORD(lookup_table->SubTable[0]);
2047 if (type == OPENTYPE_GPOS_EXTENSION_SUBST) {
2048 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
2049 if (GET_BE_WORD(ext->SubstFormat) == 1)
2050 offset += GET_BE_DWORD(ext->ExtensionOffset);
2051 else
2052 FIXME("Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
2055 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
2056 index = GET_BE_WORD(subst2->SubstFormat);
2057 if (index == 1)
2058 FIXME("Validate Single Substitution Format 1\n");
2059 else if (index == 2) {
2060 /* SimSun-ExtB has 0 glyph count for this substitution */
2061 if (GET_BE_WORD(subst2->GlyphCount) > 0) {
2062 ret = TRUE;
2063 break;
2066 else
2067 WARN("Unknown Single Substitution Format, %u\n", index);
2072 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2074 return ret;
2077 static BOOL opentype_has_font_table(IDWriteFontFace4 *fontface, UINT32 tag)
2079 BOOL exists = FALSE;
2080 const void *data;
2081 void *context;
2082 UINT32 size;
2083 HRESULT hr;
2085 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, &data, &size, &context, &exists);
2086 if (FAILED(hr))
2087 return FALSE;
2089 if (exists)
2090 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2092 return exists;
2095 static DWORD opentype_get_sbix_formats(IDWriteFontFace4 *fontface)
2097 UINT32 size, s, num_strikes;
2098 const sbix_header *header;
2099 UINT16 g, num_glyphs;
2100 BOOL exists = FALSE;
2101 const maxp *maxp;
2102 const void *data;
2103 DWORD ret = 0;
2104 void *context;
2105 HRESULT hr;
2107 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_MAXP_TAG, &data, &size, &context, &exists);
2108 if (FAILED(hr) || !exists)
2109 return 0;
2111 maxp = data;
2112 num_glyphs = GET_BE_WORD(maxp->numGlyphs);
2114 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2116 if (FAILED(IDWriteFontFace4_TryGetFontTable(fontface, MS_SBIX_TAG, &data, &size, &context, &exists))) {
2117 WARN("Failed to get 'sbix' table, %#x\n", hr);
2118 return 0;
2121 header = data;
2122 num_strikes = GET_BE_DWORD(header->numStrikes);
2124 for (s = 0; s < num_strikes; s++) {
2125 sbix_strike *strike = (sbix_strike *)((BYTE *)header + GET_BE_DWORD(header->strikeOffset[s]));
2127 for (g = 0; g < num_glyphs; g++) {
2128 DWORD offset = GET_BE_DWORD(strike->glyphDataOffsets[g]);
2129 DWORD offset_next = GET_BE_DWORD(strike->glyphDataOffsets[g + 1]);
2130 sbix_glyph_data *glyph_data;
2131 DWORD format;
2133 if (offset == offset_next)
2134 continue;
2136 glyph_data = (sbix_glyph_data *)((BYTE *)strike + offset);
2137 switch (format = glyph_data->graphicType)
2139 case MS_PNG__TAG:
2140 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
2141 break;
2142 case MS_JPG__TAG:
2143 ret |= DWRITE_GLYPH_IMAGE_FORMATS_JPEG;
2144 break;
2145 case MS_TIFF_TAG:
2146 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TIFF;
2147 break;
2148 default:
2149 format = GET_BE_DWORD(format);
2150 FIXME("unexpected bitmap format %s\n", debugstr_an((char *)&format, 4));
2155 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2157 return ret;
2160 UINT32 opentype_get_glyph_image_formats(IDWriteFontFace4 *fontface)
2162 UINT32 ret = DWRITE_GLYPH_IMAGE_FORMATS_NONE;
2164 if (opentype_has_font_table(fontface, MS_GLYF_TAG))
2165 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
2167 if (opentype_has_font_table(fontface, MS_CFF__TAG))
2168 ret |= DWRITE_GLYPH_IMAGE_FORMATS_CFF;
2170 if (opentype_has_font_table(fontface, MS_COLR_TAG))
2171 ret |= DWRITE_GLYPH_IMAGE_FORMATS_COLR;
2173 if (opentype_has_font_table(fontface, MS_SVG__TAG))
2174 ret |= DWRITE_GLYPH_IMAGE_FORMATS_SVG;
2176 if (opentype_has_font_table(fontface, MS_SBIX_TAG))
2177 ret |= opentype_get_sbix_formats(fontface);
2179 /* TODO: handle embedded bitmaps tables */
2180 return ret;