include: Use the hard-float calling convention for Windows APIs on ARM
[wine.git] / dlls / dwrite / opentype.c
blob4f570f586c2d33cbf3606a75db9eb68fb2f3b3e1
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_CFF2_TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F','2')
41 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
42 #define MS_SVG__TAG DWRITE_MAKE_OPENTYPE_TAG('S','V','G',' ')
43 #define MS_SBIX_TAG DWRITE_MAKE_OPENTYPE_TAG('s','b','i','x')
44 #define MS_MAXP_TAG DWRITE_MAKE_OPENTYPE_TAG('m','a','x','p')
45 #define MS_CBLC_TAG DWRITE_MAKE_OPENTYPE_TAG('C','B','L','C')
47 /* 'sbix' formats */
48 #define MS_PNG__TAG DWRITE_MAKE_OPENTYPE_TAG('p','n','g',' ')
49 #define MS_JPG__TAG DWRITE_MAKE_OPENTYPE_TAG('j','p','g',' ')
50 #define MS_TIFF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','i','f','f')
52 #define MS_WOFF_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','F')
53 #define MS_WOF2_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','2')
55 #ifdef WORDS_BIGENDIAN
56 #define GET_BE_WORD(x) (x)
57 #define GET_BE_DWORD(x) (x)
58 #else
59 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
60 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
61 #endif
63 typedef struct {
64 CHAR TTCTag[4];
65 DWORD Version;
66 DWORD numFonts;
67 DWORD OffsetTable[1];
68 } TTC_Header_V1;
70 typedef struct {
71 DWORD version;
72 WORD numTables;
73 WORD searchRange;
74 WORD entrySelector;
75 WORD rangeShift;
76 } TTC_SFNT_V1;
78 typedef struct {
79 DWORD tag;
80 DWORD checkSum;
81 DWORD offset;
82 DWORD length;
83 } TT_TableRecord;
85 typedef struct {
86 WORD platformID;
87 WORD encodingID;
88 DWORD offset;
89 } CMAP_EncodingRecord;
91 typedef struct {
92 WORD version;
93 WORD numTables;
94 CMAP_EncodingRecord tables[1];
95 } CMAP_Header;
97 typedef struct {
98 DWORD startCharCode;
99 DWORD endCharCode;
100 DWORD startGlyphID;
101 } CMAP_SegmentedCoverage_group;
103 typedef struct {
104 WORD format;
105 WORD reserved;
106 DWORD length;
107 DWORD language;
108 DWORD nGroups;
109 CMAP_SegmentedCoverage_group groups[1];
110 } CMAP_SegmentedCoverage;
112 typedef struct {
113 WORD format;
114 WORD length;
115 WORD language;
116 WORD segCountX2;
117 WORD searchRange;
118 WORD entrySelector;
119 WORD rangeShift;
120 WORD endCode[1];
121 } CMAP_SegmentMapping_0;
123 enum OPENTYPE_CMAP_TABLE_FORMAT
125 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING = 4,
126 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE = 12
129 /* PANOSE is 10 bytes in size, need to pack the structure properly */
130 #include "pshpack2.h"
131 typedef struct
133 USHORT majorVersion;
134 USHORT minorVersion;
135 ULONG revision;
136 ULONG checksumadj;
137 ULONG magic;
138 USHORT flags;
139 USHORT unitsPerEm;
140 ULONGLONG created;
141 ULONGLONG modified;
142 SHORT xMin;
143 SHORT yMin;
144 SHORT xMax;
145 SHORT yMax;
146 USHORT macStyle;
147 USHORT lowestRecPPEM;
148 SHORT direction_hint;
149 SHORT index_format;
150 SHORT glyphdata_format;
151 } TT_HEAD;
153 enum TT_HEAD_MACSTYLE
155 TT_HEAD_MACSTYLE_BOLD = 1 << 0,
156 TT_HEAD_MACSTYLE_ITALIC = 1 << 1,
157 TT_HEAD_MACSTYLE_UNDERLINE = 1 << 2,
158 TT_HEAD_MACSTYLE_OUTLINE = 1 << 3,
159 TT_HEAD_MACSTYLE_SHADOW = 1 << 4,
160 TT_HEAD_MACSTYLE_CONDENSED = 1 << 5,
161 TT_HEAD_MACSTYLE_EXTENDED = 1 << 6,
164 typedef struct
166 ULONG Version;
167 ULONG italicAngle;
168 SHORT underlinePosition;
169 SHORT underlineThickness;
170 ULONG fixed_pitch;
171 ULONG minmemType42;
172 ULONG maxmemType42;
173 ULONG minmemType1;
174 ULONG maxmemType1;
175 } TT_POST;
177 typedef struct
179 USHORT version;
180 SHORT xAvgCharWidth;
181 USHORT usWeightClass;
182 USHORT usWidthClass;
183 SHORT fsType;
184 SHORT ySubscriptXSize;
185 SHORT ySubscriptYSize;
186 SHORT ySubscriptXOffset;
187 SHORT ySubscriptYOffset;
188 SHORT ySuperscriptXSize;
189 SHORT ySuperscriptYSize;
190 SHORT ySuperscriptXOffset;
191 SHORT ySuperscriptYOffset;
192 SHORT yStrikeoutSize;
193 SHORT yStrikeoutPosition;
194 SHORT sFamilyClass;
195 PANOSE panose;
196 ULONG ulUnicodeRange1;
197 ULONG ulUnicodeRange2;
198 ULONG ulUnicodeRange3;
199 ULONG ulUnicodeRange4;
200 CHAR achVendID[4];
201 USHORT fsSelection;
202 USHORT usFirstCharIndex;
203 USHORT usLastCharIndex;
204 /* According to the Apple spec, original version didn't have the below fields,
205 * version numbers were taken from the OpenType spec.
207 /* version 0 (TrueType 1.5) */
208 USHORT sTypoAscender;
209 USHORT sTypoDescender;
210 USHORT sTypoLineGap;
211 USHORT usWinAscent;
212 USHORT usWinDescent;
213 /* version 1 (TrueType 1.66) */
214 ULONG ulCodePageRange1;
215 ULONG ulCodePageRange2;
216 /* version 2 (OpenType 1.2) */
217 SHORT sxHeight;
218 SHORT sCapHeight;
219 USHORT usDefaultChar;
220 USHORT usBreakChar;
221 USHORT usMaxContext;
222 } TT_OS2_V2;
224 typedef struct {
225 USHORT majorVersion;
226 USHORT minorVersion;
227 SHORT ascender;
228 SHORT descender;
229 SHORT linegap;
230 USHORT advanceWidthMax;
231 SHORT minLeftSideBearing;
232 SHORT minRightSideBearing;
233 SHORT xMaxExtent;
234 SHORT caretSlopeRise;
235 SHORT caretSlopeRun;
236 SHORT caretOffset;
237 SHORT reserved[4];
238 SHORT metricDataFormat;
239 USHORT numberOfHMetrics;
240 } TT_HHEA;
242 typedef struct {
243 WORD version;
244 WORD flags;
245 DWORD numStrikes;
246 DWORD strikeOffset[1];
247 } sbix_header;
249 typedef struct {
250 WORD ppem;
251 WORD ppi;
252 DWORD glyphDataOffsets[1];
253 } sbix_strike;
255 typedef struct {
256 WORD originOffsetX;
257 WORD originOffsetY;
258 DWORD graphicType;
259 BYTE data[1];
260 } sbix_glyph_data;
262 typedef struct {
263 DWORD version;
264 WORD numGlyphs;
265 } maxp;
267 typedef struct {
268 WORD majorVersion;
269 WORD minorVersion;
270 DWORD numSizes;
271 } CBLCHeader;
273 typedef struct {
274 BYTE res[12];
275 } sbitLineMetrics;
277 typedef struct {
278 DWORD indexSubTableArrayOffset;
279 DWORD indexTablesSize;
280 DWORD numberofIndexSubTables;
281 DWORD colorRef;
282 sbitLineMetrics hori;
283 sbitLineMetrics vert;
284 WORD startGlyphIndex;
285 WORD endGlyphIndex;
286 BYTE ppemX;
287 BYTE ppemY;
288 BYTE bitDepth;
289 BYTE flags;
290 } CBLCBitmapSizeTable;
291 #include "poppack.h"
293 enum OS2_FSSELECTION {
294 OS2_FSSELECTION_ITALIC = 1 << 0,
295 OS2_FSSELECTION_UNDERSCORE = 1 << 1,
296 OS2_FSSELECTION_NEGATIVE = 1 << 2,
297 OS2_FSSELECTION_OUTLINED = 1 << 3,
298 OS2_FSSELECTION_STRIKEOUT = 1 << 4,
299 OS2_FSSELECTION_BOLD = 1 << 5,
300 OS2_FSSELECTION_REGULAR = 1 << 6,
301 OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7,
302 OS2_FSSELECTION_WWS = 1 << 8,
303 OS2_FSSELECTION_OBLIQUE = 1 << 9
306 typedef struct {
307 WORD platformID;
308 WORD encodingID;
309 WORD languageID;
310 WORD nameID;
311 WORD length;
312 WORD offset;
313 } TT_NameRecord;
315 typedef struct {
316 WORD format;
317 WORD count;
318 WORD stringOffset;
319 TT_NameRecord nameRecord[1];
320 } TT_NAME_V0;
322 struct VDMX_Header
324 WORD version;
325 WORD numRecs;
326 WORD numRatios;
329 struct VDMX_Ratio
331 BYTE bCharSet;
332 BYTE xRatio;
333 BYTE yStartRatio;
334 BYTE yEndRatio;
337 struct VDMX_group
339 WORD recs;
340 BYTE startsz;
341 BYTE endsz;
344 struct VDMX_vTable
346 WORD yPelHeight;
347 SHORT yMax;
348 SHORT yMin;
351 typedef struct {
352 CHAR FeatureTag[4];
353 WORD Feature;
354 } OT_FeatureRecord;
356 typedef struct {
357 WORD FeatureCount;
358 OT_FeatureRecord FeatureRecord[1];
359 } OT_FeatureList;
361 typedef struct {
362 WORD LookupOrder; /* Reserved */
363 WORD ReqFeatureIndex;
364 WORD FeatureCount;
365 WORD FeatureIndex[1];
366 } OT_LangSys;
368 typedef struct {
369 CHAR LangSysTag[4];
370 WORD LangSys;
371 } OT_LangSysRecord;
373 typedef struct {
374 WORD DefaultLangSys;
375 WORD LangSysCount;
376 OT_LangSysRecord LangSysRecord[1];
377 } OT_Script;
379 typedef struct {
380 CHAR ScriptTag[4];
381 WORD Script;
382 } OT_ScriptRecord;
384 typedef struct {
385 WORD ScriptCount;
386 OT_ScriptRecord ScriptRecord[1];
387 } OT_ScriptList;
389 typedef struct {
390 DWORD version;
391 WORD ScriptList;
392 WORD FeatureList;
393 WORD LookupList;
394 } GPOS_GSUB_Header;
396 enum OPENTYPE_PLATFORM_ID
398 OPENTYPE_PLATFORM_UNICODE = 0,
399 OPENTYPE_PLATFORM_MAC,
400 OPENTYPE_PLATFORM_ISO,
401 OPENTYPE_PLATFORM_WIN,
402 OPENTYPE_PLATFORM_CUSTOM
405 typedef struct {
406 WORD FeatureParams;
407 WORD LookupCount;
408 WORD LookupListIndex[1];
409 } OT_Feature;
411 typedef struct {
412 WORD LookupCount;
413 WORD Lookup[1];
414 } OT_LookupList;
416 typedef struct {
417 WORD LookupType;
418 WORD LookupFlag;
419 WORD SubTableCount;
420 WORD SubTable[1];
421 } OT_LookupTable;
423 typedef struct {
424 WORD SubstFormat;
425 WORD Coverage;
426 WORD DeltaGlyphID;
427 } GSUB_SingleSubstFormat1;
429 typedef struct {
430 WORD SubstFormat;
431 WORD Coverage;
432 WORD GlyphCount;
433 WORD Substitute[1];
434 } GSUB_SingleSubstFormat2;
436 typedef struct {
437 WORD SubstFormat;
438 WORD ExtensionLookupType;
439 DWORD ExtensionOffset;
440 } GSUB_ExtensionPosFormat1;
442 enum OPENTYPE_GPOS_LOOKUPS
444 OPENTYPE_GPOS_SINGLE_SUBST = 1,
445 OPENTYPE_GPOS_EXTENSION_SUBST = 7
448 enum TT_NAME_WINDOWS_ENCODING_ID
450 TT_NAME_WINDOWS_ENCODING_SYMBOL = 0,
451 TT_NAME_WINDOWS_ENCODING_UCS2,
452 TT_NAME_WINDOWS_ENCODING_SJIS,
453 TT_NAME_WINDOWS_ENCODING_PRC,
454 TT_NAME_WINDOWS_ENCODING_BIG5,
455 TT_NAME_WINDOWS_ENCODING_WANSUNG,
456 TT_NAME_WINDOWS_ENCODING_JOHAB,
457 TT_NAME_WINDOWS_ENCODING_RESERVED1,
458 TT_NAME_WINDOWS_ENCODING_RESERVED2,
459 TT_NAME_WINDOWS_ENCODING_RESERVED3,
460 TT_NAME_WINDOWS_ENCODING_UCS4
463 enum TT_NAME_MAC_ENCODING_ID
465 TT_NAME_MAC_ENCODING_ROMAN = 0,
466 TT_NAME_MAC_ENCODING_JAPANESE,
467 TT_NAME_MAC_ENCODING_TRAD_CHINESE,
468 TT_NAME_MAC_ENCODING_KOREAN,
469 TT_NAME_MAC_ENCODING_ARABIC,
470 TT_NAME_MAC_ENCODING_HEBREW,
471 TT_NAME_MAC_ENCODING_GREEK,
472 TT_NAME_MAC_ENCODING_RUSSIAN,
473 TT_NAME_MAC_ENCODING_RSYMBOL,
474 TT_NAME_MAC_ENCODING_DEVANAGARI,
475 TT_NAME_MAC_ENCODING_GURMUKHI,
476 TT_NAME_MAC_ENCODING_GUJARATI,
477 TT_NAME_MAC_ENCODING_ORIYA,
478 TT_NAME_MAC_ENCODING_BENGALI,
479 TT_NAME_MAC_ENCODING_TAMIL,
480 TT_NAME_MAC_ENCODING_TELUGU,
481 TT_NAME_MAC_ENCODING_KANNADA,
482 TT_NAME_MAC_ENCODING_MALAYALAM,
483 TT_NAME_MAC_ENCODING_SINHALESE,
484 TT_NAME_MAC_ENCODING_BURMESE,
485 TT_NAME_MAC_ENCODING_KHMER,
486 TT_NAME_MAC_ENCODING_THAI,
487 TT_NAME_MAC_ENCODING_LAOTIAN,
488 TT_NAME_MAC_ENCODING_GEORGIAN,
489 TT_NAME_MAC_ENCODING_ARMENIAN,
490 TT_NAME_MAC_ENCODING_SIMPL_CHINESE,
491 TT_NAME_MAC_ENCODING_TIBETAN,
492 TT_NAME_MAC_ENCODING_MONGOLIAN,
493 TT_NAME_MAC_ENCODING_GEEZ,
494 TT_NAME_MAC_ENCODING_SLAVIC,
495 TT_NAME_MAC_ENCODING_VIETNAMESE,
496 TT_NAME_MAC_ENCODING_SINDHI,
497 TT_NAME_MAC_ENCODING_UNINTERPRETED
500 enum TT_NAME_MAC_LANGUAGE_ID
502 TT_NAME_MAC_LANGID_ENGLISH = 0,
503 TT_NAME_MAC_LANGID_FRENCH,
504 TT_NAME_MAC_LANGID_GERMAN,
505 TT_NAME_MAC_LANGID_ITALIAN,
506 TT_NAME_MAC_LANGID_DUTCH,
507 TT_NAME_MAC_LANGID_SWEDISH,
508 TT_NAME_MAC_LANGID_SPANISH,
509 TT_NAME_MAC_LANGID_DANISH,
510 TT_NAME_MAC_LANGID_PORTUGUESE,
511 TT_NAME_MAC_LANGID_NORWEGIAN,
512 TT_NAME_MAC_LANGID_HEBREW,
513 TT_NAME_MAC_LANGID_JAPANESE,
514 TT_NAME_MAC_LANGID_ARABIC,
515 TT_NAME_MAC_LANGID_FINNISH,
516 TT_NAME_MAC_LANGID_GREEK,
517 TT_NAME_MAC_LANGID_ICELANDIC,
518 TT_NAME_MAC_LANGID_MALTESE,
519 TT_NAME_MAC_LANGID_TURKISH,
520 TT_NAME_MAC_LANGID_CROATIAN,
521 TT_NAME_MAC_LANGID_TRAD_CHINESE,
522 TT_NAME_MAC_LANGID_URDU,
523 TT_NAME_MAC_LANGID_HINDI,
524 TT_NAME_MAC_LANGID_THAI,
525 TT_NAME_MAC_LANGID_KOREAN,
526 TT_NAME_MAC_LANGID_LITHUANIAN,
527 TT_NAME_MAC_LANGID_POLISH,
528 TT_NAME_MAC_LANGID_HUNGARIAN,
529 TT_NAME_MAC_LANGID_ESTONIAN,
530 TT_NAME_MAC_LANGID_LATVIAN,
531 TT_NAME_MAC_LANGID_SAMI,
532 TT_NAME_MAC_LANGID_FAROESE,
533 TT_NAME_MAC_LANGID_FARSI,
534 TT_NAME_MAC_LANGID_RUSSIAN,
535 TT_NAME_MAC_LANGID_SIMPL_CHINESE,
536 TT_NAME_MAC_LANGID_FLEMISH,
537 TT_NAME_MAC_LANGID_GAELIC,
538 TT_NAME_MAC_LANGID_ALBANIAN,
539 TT_NAME_MAC_LANGID_ROMANIAN,
540 TT_NAME_MAC_LANGID_CZECH,
541 TT_NAME_MAC_LANGID_SLOVAK,
542 TT_NAME_MAC_LANGID_SLOVENIAN,
543 TT_NAME_MAC_LANGID_YIDDISH,
544 TT_NAME_MAC_LANGID_SERBIAN,
545 TT_NAME_MAC_LANGID_MACEDONIAN,
546 TT_NAME_MAC_LANGID_BULGARIAN,
547 TT_NAME_MAC_LANGID_UKRAINIAN,
548 TT_NAME_MAC_LANGID_BYELORUSSIAN,
549 TT_NAME_MAC_LANGID_UZBEK,
550 TT_NAME_MAC_LANGID_KAZAKH,
551 TT_NAME_MAC_LANGID_AZERB_CYR,
552 TT_NAME_MAC_LANGID_AZERB_ARABIC,
553 TT_NAME_MAC_LANGID_ARMENIAN,
554 TT_NAME_MAC_LANGID_GEORGIAN,
555 TT_NAME_MAC_LANGID_MOLDAVIAN,
556 TT_NAME_MAC_LANGID_KIRGHIZ,
557 TT_NAME_MAC_LANGID_TAJIKI,
558 TT_NAME_MAC_LANGID_TURKMEN,
559 TT_NAME_MAC_LANGID_MONGOLIAN,
560 TT_NAME_MAC_LANGID_MONGOLIAN_CYR,
561 TT_NAME_MAC_LANGID_PASHTO,
562 TT_NAME_MAC_LANGID_KURDISH,
563 TT_NAME_MAC_LANGID_KASHMIRI,
564 TT_NAME_MAC_LANGID_SINDHI,
565 TT_NAME_MAC_LANGID_TIBETAN,
566 TT_NAME_MAC_LANGID_NEPALI,
567 TT_NAME_MAC_LANGID_SANSKRIT,
568 TT_NAME_MAC_LANGID_MARATHI,
569 TT_NAME_MAC_LANGID_BENGALI,
570 TT_NAME_MAC_LANGID_ASSAMESE,
571 TT_NAME_MAC_LANGID_GUJARATI,
572 TT_NAME_MAC_LANGID_PUNJABI,
573 TT_NAME_MAC_LANGID_ORIYA,
574 TT_NAME_MAC_LANGID_MALAYALAM,
575 TT_NAME_MAC_LANGID_KANNADA,
576 TT_NAME_MAC_LANGID_TAMIL,
577 TT_NAME_MAC_LANGID_TELUGU,
578 TT_NAME_MAC_LANGID_SINHALESE,
579 TT_NAME_MAC_LANGID_BURMESE,
580 TT_NAME_MAC_LANGID_KHMER,
581 TT_NAME_MAC_LANGID_LAO,
582 TT_NAME_MAC_LANGID_VIETNAMESE,
583 TT_NAME_MAC_LANGID_INDONESIAN,
584 TT_NAME_MAC_LANGID_TAGALOG,
585 TT_NAME_MAC_LANGID_MALAY_ROMAN,
586 TT_NAME_MAC_LANGID_MALAY_ARABIC,
587 TT_NAME_MAC_LANGID_AMHARIC,
588 TT_NAME_MAC_LANGID_TIGRINYA,
589 TT_NAME_MAC_LANGID_GALLA,
590 TT_NAME_MAC_LANGID_SOMALI,
591 TT_NAME_MAC_LANGID_SWAHILI,
592 TT_NAME_MAC_LANGID_KINYARWANDA,
593 TT_NAME_MAC_LANGID_RUNDI,
594 TT_NAME_MAC_LANGID_NYANJA,
595 TT_NAME_MAC_LANGID_MALAGASY,
596 TT_NAME_MAC_LANGID_ESPERANTO,
597 TT_NAME_MAC_LANGID_WELSH = 128,
598 TT_NAME_MAC_LANGID_BASQUE,
599 TT_NAME_MAC_LANGID_CATALAN,
600 TT_NAME_MAC_LANGID_LATIN,
601 TT_NAME_MAC_LANGID_QUECHUA,
602 TT_NAME_MAC_LANGID_GUARANI,
603 TT_NAME_MAC_LANGID_AYMARA,
604 TT_NAME_MAC_LANGID_TATAR,
605 TT_NAME_MAC_LANGID_UIGHUR,
606 TT_NAME_MAC_LANGID_DZONGKHA,
607 TT_NAME_MAC_LANGID_JAVANESE,
608 TT_NAME_MAC_LANGID_SUNDANESE,
609 TT_NAME_MAC_LANGID_GALICIAN,
610 TT_NAME_MAC_LANGID_AFRIKAANS,
611 TT_NAME_MAC_LANGID_BRETON,
612 TT_NAME_MAC_LANGID_INUKTITUT,
613 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC,
614 TT_NAME_MAC_LANGID_MANX_GAELIC,
615 TT_NAME_MAC_LANGID_IRISH_GAELIC,
616 TT_NAME_MAC_LANGID_TONGAN,
617 TT_NAME_MAC_LANGID_GREEK_POLYTONIC,
618 TT_NAME_MAC_LANGID_GREENLANDIC,
619 TT_NAME_MAC_LANGID_AZER_ROMAN
622 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
623 static const char name_mac_langid_to_locale[][10] = {
624 "en-US",
625 "fr-FR",
626 "de-DE",
627 "it-IT",
628 "nl-NL",
629 "sv-SE",
630 "es-ES",
631 "da-DA",
632 "pt-PT",
633 "no-NO",
634 "he-IL",
635 "ja-JP",
636 "ar-AR",
637 "fi-FI",
638 "el-GR",
639 "is-IS",
640 "mt-MT",
641 "tr-TR",
642 "hr-HR",
643 "zh-HK",
644 "ur-PK",
645 "hi-IN",
646 "th-TH",
647 "ko-KR",
648 "lt-LT",
649 "pl-PL",
650 "hu-HU",
651 "et-EE",
652 "lv-LV",
653 "se-NO",
654 "fo-FO",
655 "fa-IR",
656 "ru-RU",
657 "zh-CN",
658 "nl-BE",
659 "gd-GB",
660 "sq-AL",
661 "ro-RO",
662 "cs-CZ",
663 "sk-SK",
664 "sl-SI",
666 "sr-Latn",
667 "mk-MK",
668 "bg-BG",
669 "uk-UA",
670 "be-BY",
671 "uz-Latn",
672 "kk-KZ",
673 "az-Cyrl-AZ",
674 "az-AZ",
675 "hy-AM",
676 "ka-GE",
679 "tg-TJ",
680 "tk-TM",
681 "mn-Mong",
682 "mn-MN",
683 "ps-AF",
684 "ku-Arab",
686 "sd-Arab",
687 "bo-CN",
688 "ne-NP",
689 "sa-IN",
690 "mr-IN",
691 "bn-IN",
692 "as-IN",
693 "gu-IN",
694 "pa-Arab",
695 "or-IN",
696 "ml-IN",
697 "kn-IN",
698 "ta-LK",
699 "te-IN",
700 "si-LK",
702 "km-KH",
703 "lo-LA",
704 "vi-VN",
705 "id-ID",
707 "ms-MY",
708 "ms-Arab",
709 "am-ET",
710 "ti-ET",
713 "sw-KE",
714 "rw-RW",
752 "cy-GB",
753 "eu-ES",
754 "ca-ES",
759 "tt-RU",
760 "ug-CN",
764 "gl-ES",
765 "af-ZA",
766 "br-FR",
767 "iu-Latn-CA",
768 "gd-GB",
770 "ga-IE",
773 "kl-GL",
774 "az-Latn"
777 enum OPENTYPE_STRING_ID
779 OPENTYPE_STRING_COPYRIGHT_NOTICE = 0,
780 OPENTYPE_STRING_FAMILY_NAME,
781 OPENTYPE_STRING_SUBFAMILY_NAME,
782 OPENTYPE_STRING_UNIQUE_IDENTIFIER,
783 OPENTYPE_STRING_FULL_FONTNAME,
784 OPENTYPE_STRING_VERSION_STRING,
785 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
786 OPENTYPE_STRING_TRADEMARK,
787 OPENTYPE_STRING_MANUFACTURER,
788 OPENTYPE_STRING_DESIGNER,
789 OPENTYPE_STRING_DESCRIPTION,
790 OPENTYPE_STRING_VENDOR_URL,
791 OPENTYPE_STRING_DESIGNER_URL,
792 OPENTYPE_STRING_LICENSE_DESCRIPTION,
793 OPENTYPE_STRING_LICENSE_INFO_URL,
794 OPENTYPE_STRING_RESERVED_ID15,
795 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
796 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
797 OPENTYPE_STRING_COMPATIBLE_FULLNAME,
798 OPENTYPE_STRING_SAMPLE_TEXT,
799 OPENTYPE_STRING_POSTSCRIPT_CID_NAME,
800 OPENTYPE_STRING_WWS_FAMILY_NAME,
801 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
804 static const UINT16 dwriteid_to_opentypeid[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1] =
806 (UINT16)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
807 OPENTYPE_STRING_COPYRIGHT_NOTICE,
808 OPENTYPE_STRING_VERSION_STRING,
809 OPENTYPE_STRING_TRADEMARK,
810 OPENTYPE_STRING_MANUFACTURER,
811 OPENTYPE_STRING_DESIGNER,
812 OPENTYPE_STRING_DESIGNER_URL,
813 OPENTYPE_STRING_DESCRIPTION,
814 OPENTYPE_STRING_VENDOR_URL,
815 OPENTYPE_STRING_LICENSE_DESCRIPTION,
816 OPENTYPE_STRING_LICENSE_INFO_URL,
817 OPENTYPE_STRING_FAMILY_NAME,
818 OPENTYPE_STRING_SUBFAMILY_NAME,
819 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
820 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
821 OPENTYPE_STRING_SAMPLE_TEXT,
822 OPENTYPE_STRING_FULL_FONTNAME,
823 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
824 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
827 /* CPAL table */
828 struct CPAL_Header_0
830 USHORT version;
831 USHORT numPaletteEntries;
832 USHORT numPalette;
833 USHORT numColorRecords;
834 ULONG offsetFirstColorRecord;
835 USHORT colorRecordIndices[1];
838 /* for version == 1, this comes after full CPAL_Header_0 */
839 struct CPAL_SubHeader_1
841 ULONG offsetPaletteTypeArray;
842 ULONG offsetPaletteLabelArray;
843 ULONG offsetPaletteEntryLabelArray;
846 struct CPAL_ColorRecord
848 BYTE blue;
849 BYTE green;
850 BYTE red;
851 BYTE alpha;
854 /* COLR table */
855 struct COLR_Header
857 USHORT version;
858 USHORT numBaseGlyphRecords;
859 ULONG offsetBaseGlyphRecord;
860 ULONG offsetLayerRecord;
861 USHORT numLayerRecords;
864 struct COLR_BaseGlyphRecord
866 USHORT GID;
867 USHORT firstLayerIndex;
868 USHORT numLayers;
871 struct COLR_LayerRecord
873 USHORT GID;
874 USHORT paletteIndex;
877 BOOL is_face_type_supported(DWRITE_FONT_FACE_TYPE type)
879 return (type == DWRITE_FONT_FACE_TYPE_CFF) ||
880 (type == DWRITE_FONT_FACE_TYPE_TRUETYPE) ||
881 (type == DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION) ||
882 (type == DWRITE_FONT_FACE_TYPE_RAW_CFF);
885 typedef HRESULT (*dwrite_fontfile_analyzer)(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
886 DWRITE_FONT_FACE_TYPE *face_type);
888 static HRESULT opentype_ttc_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
889 DWRITE_FONT_FACE_TYPE *face_type)
891 static const DWORD ttctag = MS_TTCF_TAG;
892 const TTC_Header_V1 *header;
893 void *context;
894 HRESULT hr;
896 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(header), &context);
897 if (FAILED(hr))
898 return hr;
900 if (!memcmp(header->TTCTag, &ttctag, sizeof(ttctag))) {
901 *font_count = GET_BE_DWORD(header->numFonts);
902 *file_type = DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION;
903 *face_type = DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION;
906 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
908 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
911 static HRESULT opentype_ttf_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
912 DWRITE_FONT_FACE_TYPE *face_type)
914 const DWORD *header;
915 void *context;
916 HRESULT hr;
918 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(*header), &context);
919 if (FAILED(hr))
920 return hr;
922 if (GET_BE_DWORD(*header) == 0x10000) {
923 *font_count = 1;
924 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
925 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
928 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
930 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
933 static HRESULT opentype_otf_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
934 DWRITE_FONT_FACE_TYPE *face_type)
936 const DWORD *header;
937 void *context;
938 HRESULT hr;
940 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(*header), &context);
941 if (FAILED(hr))
942 return hr;
944 if (GET_BE_DWORD(*header) == MS_OTTO_TAG) {
945 *font_count = 1;
946 *file_type = DWRITE_FONT_FILE_TYPE_CFF;
947 *face_type = DWRITE_FONT_FACE_TYPE_CFF;
950 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
952 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
955 static HRESULT opentype_type1_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
956 DWRITE_FONT_FACE_TYPE *face_type)
958 #include "pshpack1.h"
959 /* Specified in Adobe TechNote #5178 */
960 struct pfm_header {
961 WORD dfVersion;
962 DWORD dfSize;
963 char data0[95];
964 DWORD dfDevice;
965 char data1[12];
967 #include "poppack.h"
968 struct type1_header {
969 WORD tag;
970 char data[14];
972 const struct type1_header *header;
973 void *context;
974 HRESULT hr;
976 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(*header), &context);
977 if (FAILED(hr))
978 return hr;
980 /* tag is followed by plain text section */
981 if (header->tag == 0x8001 &&
982 (!memcmp(header->data, "%!PS-AdobeFont", 14) ||
983 !memcmp(header->data, "%!FontType", 10))) {
984 *font_count = 1;
985 *file_type = DWRITE_FONT_FILE_TYPE_TYPE1_PFB;
986 *face_type = DWRITE_FONT_FACE_TYPE_TYPE1;
989 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
991 /* let's see if it's a .pfm metrics file */
992 if (*file_type == DWRITE_FONT_FILE_TYPE_UNKNOWN) {
993 const struct pfm_header *pfm_header;
994 UINT64 filesize;
995 DWORD offset;
996 BOOL header_checked;
998 hr = IDWriteFontFileStream_GetFileSize(stream, &filesize);
999 if (FAILED(hr))
1000 return hr;
1002 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&pfm_header, 0, sizeof(*pfm_header), &context);
1003 if (FAILED(hr))
1004 return hr;
1006 offset = pfm_header->dfDevice;
1007 header_checked = pfm_header->dfVersion == 0x100 && pfm_header->dfSize == filesize;
1008 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
1010 /* as a last test check static string in PostScript information section */
1011 if (header_checked) {
1012 static const char postscript[] = "PostScript";
1013 char *devtype_name;
1015 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&devtype_name, offset, sizeof(postscript), &context);
1016 if (FAILED(hr))
1017 return hr;
1019 if (!memcmp(devtype_name, postscript, sizeof(postscript))) {
1020 *font_count = 1;
1021 *file_type = DWRITE_FONT_FILE_TYPE_TYPE1_PFM;
1022 *face_type = DWRITE_FONT_FACE_TYPE_TYPE1;
1025 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
1029 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
1032 HRESULT opentype_analyze_font(IDWriteFontFileStream *stream, BOOL *supported, DWRITE_FONT_FILE_TYPE *file_type,
1033 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
1035 static dwrite_fontfile_analyzer fontfile_analyzers[] = {
1036 opentype_ttf_analyzer,
1037 opentype_otf_analyzer,
1038 opentype_ttc_analyzer,
1039 opentype_type1_analyzer,
1040 NULL
1042 dwrite_fontfile_analyzer *analyzer = fontfile_analyzers;
1043 DWRITE_FONT_FACE_TYPE face;
1044 HRESULT hr;
1046 if (!face_type)
1047 face_type = &face;
1049 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
1050 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
1051 *face_count = 0;
1053 while (*analyzer) {
1054 hr = (*analyzer)(stream, face_count, file_type, face_type);
1055 if (FAILED(hr))
1056 return hr;
1058 if (hr == S_OK)
1059 break;
1061 analyzer++;
1064 *supported = is_face_type_supported(*face_type);
1065 return S_OK;
1068 HRESULT opentype_get_font_table(struct file_stream_desc *stream_desc, UINT32 tag, const void **table_data,
1069 void **table_context, UINT32 *table_size, BOOL *found)
1071 void *table_directory_context, *sfnt_context;
1072 TT_TableRecord *table_record = NULL;
1073 TTC_SFNT_V1 *font_header = NULL;
1074 UINT32 table_offset = 0;
1075 UINT16 table_count;
1076 HRESULT hr;
1078 if (found) *found = FALSE;
1079 if (table_size) *table_size = 0;
1081 *table_data = NULL;
1082 *table_context = NULL;
1084 if (stream_desc->face_type == DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION) {
1085 const TTC_Header_V1 *ttc_header;
1086 void * ttc_context;
1087 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context);
1088 if (SUCCEEDED(hr)) {
1089 if (stream_desc->face_index >= GET_BE_DWORD(ttc_header->numFonts))
1090 hr = E_INVALIDARG;
1091 else {
1092 table_offset = GET_BE_DWORD(ttc_header->OffsetTable[stream_desc->face_index]);
1093 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context);
1095 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, ttc_context);
1098 else
1099 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context);
1101 if (FAILED(hr))
1102 return hr;
1104 table_count = GET_BE_WORD(font_header->numTables);
1105 table_offset += sizeof(*font_header);
1107 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, sfnt_context);
1109 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void **)&table_record, table_offset,
1110 table_count * sizeof(*table_record), &table_directory_context);
1111 if (hr == S_OK) {
1112 UINT16 i;
1114 for (i = 0; i < table_count; i++) {
1115 if (table_record->tag == tag) {
1116 UINT32 offset = GET_BE_DWORD(table_record->offset);
1117 UINT32 length = GET_BE_DWORD(table_record->length);
1119 if (found)
1120 *found = TRUE;
1121 if (table_size)
1122 *table_size = length;
1123 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, table_data, offset,
1124 length, table_context);
1125 break;
1127 table_record++;
1130 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, table_directory_context);
1133 return hr;
1136 /**********
1137 * CMAP
1138 **********/
1140 static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table)
1142 UINT32 count = 0;
1143 int i;
1145 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) {
1146 WORD type;
1147 WORD *table;
1149 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
1150 continue;
1152 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
1153 type = GET_BE_WORD(*table);
1154 TRACE("table type %i\n", type);
1156 switch (type)
1158 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
1160 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
1161 count += GET_BE_WORD(format->segCountX2)/2;
1162 break;
1164 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
1166 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
1167 count += GET_BE_DWORD(format->nGroups);
1168 break;
1170 default:
1171 FIXME("table type %i unhandled.\n", type);
1175 return count;
1178 HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1180 CMAP_Header *CMAP_Table = data;
1181 int i, k = 0;
1183 if (!CMAP_Table)
1184 return E_FAIL;
1186 *count = opentype_cmap_get_unicode_ranges_count(CMAP_Table);
1188 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables) && k < max_count; i++)
1190 WORD type;
1191 WORD *table;
1192 int j;
1194 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
1195 continue;
1197 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
1198 type = GET_BE_WORD(*table);
1199 TRACE("table type %i\n", type);
1201 switch (type)
1203 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
1205 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
1206 UINT16 segment_count = GET_BE_WORD(format->segCountX2)/2;
1207 UINT16 *startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
1209 for (j = 0; j < segment_count && GET_BE_WORD(format->endCode[j]) < 0xffff && k < max_count; j++, k++) {
1210 ranges[k].first = GET_BE_WORD(startCode[j]);
1211 ranges[k].last = GET_BE_WORD(format->endCode[j]);
1213 break;
1215 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
1217 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
1218 for (j = 0; j < GET_BE_DWORD(format->nGroups) && k < max_count; j++, k++) {
1219 ranges[k].first = GET_BE_DWORD(format->groups[j].startCharCode);
1220 ranges[k].last = GET_BE_DWORD(format->groups[j].endCharCode);
1222 break;
1224 default:
1225 FIXME("table type %i unhandled.\n", type);
1229 return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK;
1232 void opentype_get_font_metrics(struct file_stream_desc *stream_desc, DWRITE_FONT_METRICS1 *metrics, DWRITE_CARET_METRICS *caret)
1234 void *os2_context, *head_context, *post_context, *hhea_context;
1235 const TT_OS2_V2 *tt_os2;
1236 const TT_HEAD *tt_head;
1237 const TT_POST *tt_post;
1238 const TT_HHEA *tt_hhea;
1240 memset(metrics, 0, sizeof(*metrics));
1242 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1243 opentype_get_font_table(stream_desc, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
1244 opentype_get_font_table(stream_desc, MS_POST_TAG, (const void**)&tt_post, &post_context, NULL, NULL);
1245 opentype_get_font_table(stream_desc, MS_HHEA_TAG, (const void**)&tt_hhea, &hhea_context, NULL, NULL);
1247 if (tt_head) {
1248 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
1249 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
1250 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
1251 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
1252 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
1255 if (caret) {
1256 if (tt_hhea) {
1257 caret->slopeRise = GET_BE_WORD(tt_hhea->caretSlopeRise);
1258 caret->slopeRun = GET_BE_WORD(tt_hhea->caretSlopeRun);
1259 caret->offset = GET_BE_WORD(tt_hhea->caretOffset);
1261 else {
1262 caret->slopeRise = 0;
1263 caret->slopeRun = 0;
1264 caret->offset = 0;
1268 if (tt_os2) {
1269 USHORT version = GET_BE_WORD(tt_os2->version);
1271 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
1272 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
1273 interpreted as large unsigned value. */
1274 metrics->descent = abs((SHORT)GET_BE_WORD(tt_os2->usWinDescent));
1276 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
1277 if (tt_hhea) {
1278 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
1279 INT32 linegap;
1281 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
1282 metrics->ascent - metrics->descent;
1283 metrics->lineGap = linegap > 0 ? linegap : 0;
1286 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
1287 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
1288 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
1289 /* Y offset is stored as positive offset below baseline */
1290 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
1291 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
1292 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
1293 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
1294 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
1295 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
1296 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
1298 /* version 2 fields */
1299 if (version >= 2) {
1300 metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight);
1301 metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight);
1304 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
1305 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
1306 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
1307 metrics->descent = descent < 0 ? -descent : 0;
1308 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
1309 metrics->hasTypographicMetrics = TRUE;
1313 if (tt_post) {
1314 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
1315 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
1318 if (metrics->underlineThickness == 0)
1319 metrics->underlineThickness = metrics->designUnitsPerEm / 14;
1320 if (metrics->strikethroughThickness == 0)
1321 metrics->strikethroughThickness = metrics->underlineThickness;
1323 /* estimate missing metrics */
1324 if (metrics->xHeight == 0)
1325 metrics->xHeight = metrics->designUnitsPerEm / 2;
1326 if (metrics->capHeight == 0)
1327 metrics->capHeight = metrics->designUnitsPerEm * 7 / 10;
1329 if (tt_os2)
1330 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1331 if (tt_head)
1332 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, head_context);
1333 if (tt_post)
1334 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, post_context);
1335 if (tt_hhea)
1336 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, hhea_context);
1339 void opentype_get_font_properties(struct file_stream_desc *stream_desc, struct dwrite_font_props *props)
1341 void *os2_context, *head_context;
1342 const TT_OS2_V2 *tt_os2;
1343 const TT_HEAD *tt_head;
1345 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1346 opentype_get_font_table(stream_desc, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
1348 /* default stretch, weight and style to normal */
1349 props->stretch = DWRITE_FONT_STRETCH_NORMAL;
1350 props->weight = DWRITE_FONT_WEIGHT_NORMAL;
1351 props->style = DWRITE_FONT_STYLE_NORMAL;
1352 memset(&props->panose, 0, sizeof(props->panose));
1353 memset(&props->fontsig, 0, sizeof(props->fontsig));
1354 memset(&props->lf, 0, sizeof(props->lf));
1356 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1357 if (tt_os2) {
1358 USHORT version = GET_BE_WORD(tt_os2->version);
1359 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
1360 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
1361 USHORT usWidthClass = GET_BE_WORD(tt_os2->usWidthClass);
1363 if (usWidthClass > DWRITE_FONT_STRETCH_UNDEFINED && usWidthClass <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
1364 props->stretch = usWidthClass;
1366 if (usWeightClass >= 1 && usWeightClass <= 9)
1367 usWeightClass *= 100;
1369 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
1370 props->weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
1371 else if (usWeightClass > 0)
1372 props->weight = usWeightClass;
1374 if (version >= 4 && (fsSelection & OS2_FSSELECTION_OBLIQUE))
1375 props->style = DWRITE_FONT_STYLE_OBLIQUE;
1376 else if (fsSelection & OS2_FSSELECTION_ITALIC)
1377 props->style = DWRITE_FONT_STYLE_ITALIC;
1379 memcpy(&props->panose, &tt_os2->panose, sizeof(props->panose));
1381 /* FONTSIGNATURE */
1382 props->fontsig.fsUsb[0] = GET_BE_DWORD(tt_os2->ulUnicodeRange1);
1383 props->fontsig.fsUsb[1] = GET_BE_DWORD(tt_os2->ulUnicodeRange2);
1384 props->fontsig.fsUsb[2] = GET_BE_DWORD(tt_os2->ulUnicodeRange3);
1385 props->fontsig.fsUsb[3] = GET_BE_DWORD(tt_os2->ulUnicodeRange4);
1387 if (GET_BE_WORD(tt_os2->version) == 0) {
1388 props->fontsig.fsCsb[0] = 0;
1389 props->fontsig.fsCsb[1] = 0;
1391 else {
1392 props->fontsig.fsCsb[0] = GET_BE_DWORD(tt_os2->ulCodePageRange1);
1393 props->fontsig.fsCsb[1] = GET_BE_DWORD(tt_os2->ulCodePageRange2);
1396 else if (tt_head) {
1397 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
1399 if (macStyle & TT_HEAD_MACSTYLE_CONDENSED)
1400 props->stretch = DWRITE_FONT_STRETCH_CONDENSED;
1401 else if (macStyle & TT_HEAD_MACSTYLE_EXTENDED)
1402 props->stretch = DWRITE_FONT_STRETCH_EXPANDED;
1404 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
1405 props->weight = DWRITE_FONT_WEIGHT_BOLD;
1407 if (macStyle & TT_HEAD_MACSTYLE_ITALIC)
1408 props->style = DWRITE_FONT_STYLE_ITALIC;
1411 props->lf.lfWeight = props->weight;
1412 props->lf.lfItalic = props->style == DWRITE_FONT_STYLE_ITALIC;
1414 TRACE("stretch=%d, weight=%d, style %d\n", props->stretch, props->weight, props->style);
1416 if (tt_os2)
1417 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1418 if (tt_head)
1419 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, head_context);
1422 static UINT get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform, USHORT encoding)
1424 UINT codepage = 0;
1426 switch (platform) {
1427 case OPENTYPE_PLATFORM_UNICODE:
1428 break;
1429 case OPENTYPE_PLATFORM_MAC:
1430 switch (encoding)
1432 case TT_NAME_MAC_ENCODING_ROMAN:
1433 codepage = 10000;
1434 break;
1435 case TT_NAME_MAC_ENCODING_JAPANESE:
1436 codepage = 10001;
1437 break;
1438 case TT_NAME_MAC_ENCODING_TRAD_CHINESE:
1439 codepage = 10002;
1440 break;
1441 case TT_NAME_MAC_ENCODING_KOREAN:
1442 codepage = 10003;
1443 break;
1444 case TT_NAME_MAC_ENCODING_ARABIC:
1445 codepage = 10004;
1446 break;
1447 case TT_NAME_MAC_ENCODING_HEBREW:
1448 codepage = 10005;
1449 break;
1450 case TT_NAME_MAC_ENCODING_GREEK:
1451 codepage = 10006;
1452 break;
1453 case TT_NAME_MAC_ENCODING_RUSSIAN:
1454 codepage = 10007;
1455 break;
1456 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE:
1457 codepage = 10008;
1458 break;
1459 case TT_NAME_MAC_ENCODING_THAI:
1460 codepage = 10021;
1461 break;
1462 default:
1463 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1464 break;
1466 break;
1467 case OPENTYPE_PLATFORM_WIN:
1468 switch (encoding)
1470 case TT_NAME_WINDOWS_ENCODING_SYMBOL:
1471 case TT_NAME_WINDOWS_ENCODING_UCS2:
1472 break;
1473 case TT_NAME_WINDOWS_ENCODING_SJIS:
1474 codepage = 932;
1475 break;
1476 case TT_NAME_WINDOWS_ENCODING_PRC:
1477 codepage = 936;
1478 break;
1479 case TT_NAME_WINDOWS_ENCODING_BIG5:
1480 codepage = 950;
1481 break;
1482 case TT_NAME_WINDOWS_ENCODING_WANSUNG:
1483 codepage = 20949;
1484 break;
1485 case TT_NAME_WINDOWS_ENCODING_JOHAB:
1486 codepage = 1361;
1487 break;
1488 default:
1489 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1490 break;
1492 break;
1493 default:
1494 FIXME("unknown platform %d\n", platform);
1497 return codepage;
1500 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform, USHORT lang_id, WCHAR *locale, USHORT locale_len)
1502 static const WCHAR enusW[] = {'e','n','-','U','S',0};
1504 switch (platform) {
1505 case OPENTYPE_PLATFORM_MAC:
1507 const char *locale_name = NULL;
1509 if (lang_id > TT_NAME_MAC_LANGID_AZER_ROMAN)
1510 WARN("invalid mac lang id %d\n", lang_id);
1511 else if (!name_mac_langid_to_locale[lang_id][0])
1512 FIXME("failed to map mac lang id %d to locale name\n", lang_id);
1513 else
1514 locale_name = name_mac_langid_to_locale[lang_id];
1516 if (locale_name)
1517 MultiByteToWideChar(CP_ACP, 0, name_mac_langid_to_locale[lang_id], -1, locale, locale_len);
1518 else
1519 strcpyW(locale, enusW);
1520 break;
1522 case OPENTYPE_PLATFORM_WIN:
1523 if (!LCIDToLocaleName(MAKELCID(lang_id, SORT_DEFAULT), locale, locale_len, 0)) {
1524 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id, SORT_DEFAULT));
1525 strcpyW(locale, enusW);
1527 break;
1528 case OPENTYPE_PLATFORM_UNICODE:
1529 strcpyW(locale, enusW);
1530 break;
1531 default:
1532 FIXME("unknown platform %d\n", platform);
1536 static BOOL opentype_decode_namerecord(const TT_NAME_V0 *header, BYTE *storage_area, USHORT recid, IDWriteLocalizedStrings *strings)
1538 const TT_NameRecord *record = &header->nameRecord[recid];
1539 USHORT lang_id, length, offset, encoding, platform;
1540 BOOL ret = FALSE;
1542 platform = GET_BE_WORD(record->platformID);
1543 lang_id = GET_BE_WORD(record->languageID);
1544 length = GET_BE_WORD(record->length);
1545 offset = GET_BE_WORD(record->offset);
1546 encoding = GET_BE_WORD(record->encodingID);
1548 if (lang_id < 0x8000) {
1549 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
1550 WCHAR *name_string;
1551 UINT codepage;
1553 codepage = get_name_record_codepage(platform, encoding);
1554 get_name_record_locale(platform, lang_id, locale, sizeof(locale)/sizeof(WCHAR));
1556 if (codepage) {
1557 DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0);
1558 name_string = heap_alloc(sizeof(WCHAR) * (len+1));
1559 MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len);
1560 name_string[len] = 0;
1562 else {
1563 int i;
1565 length /= sizeof(WCHAR);
1566 name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length);
1567 for (i = 0; i < length; i++)
1568 name_string[i] = GET_BE_WORD(name_string[i]);
1571 TRACE("string %s for locale %s found\n", debugstr_w(name_string), debugstr_w(locale));
1572 add_localizedstring(strings, locale, name_string);
1573 heap_free(name_string);
1574 ret = TRUE;
1576 else
1577 FIXME("handle NAME format 1\n");
1579 return ret;
1582 static HRESULT opentype_get_font_strings_from_id(const void *table_data, enum OPENTYPE_STRING_ID id, IDWriteLocalizedStrings **strings)
1584 const TT_NAME_V0 *header;
1585 BYTE *storage_area = 0;
1586 USHORT count = 0;
1587 int i, candidate;
1588 WORD format;
1589 BOOL exists;
1590 HRESULT hr;
1592 if (!table_data)
1593 return E_FAIL;
1595 hr = create_localizedstrings(strings);
1596 if (FAILED(hr)) return hr;
1598 header = table_data;
1599 format = GET_BE_WORD(header->format);
1601 switch (format) {
1602 case 0:
1603 case 1:
1604 break;
1605 default:
1606 FIXME("unsupported NAME format %d\n", format);
1609 storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset);
1610 count = GET_BE_WORD(header->count);
1612 exists = FALSE;
1613 candidate = -1;
1614 for (i = 0; i < count; i++) {
1615 const TT_NameRecord *record = &header->nameRecord[i];
1616 USHORT platform;
1618 if (GET_BE_WORD(record->nameID) != id)
1619 continue;
1621 /* Right now only accept unicode and windows encoded fonts */
1622 platform = GET_BE_WORD(record->platformID);
1623 if (platform != OPENTYPE_PLATFORM_UNICODE &&
1624 platform != OPENTYPE_PLATFORM_MAC &&
1625 platform != OPENTYPE_PLATFORM_WIN)
1627 FIXME("platform %i not supported\n", platform);
1628 continue;
1631 /* Skip such entries for now, fonts tend to duplicate those strings as
1632 WIN platform entries. If font does not have WIN or MAC entry for this id, we will
1633 use this Unicode platform entry while assuming en-US locale. */
1634 if (platform == OPENTYPE_PLATFORM_UNICODE) {
1635 candidate = i;
1636 continue;
1639 if (!opentype_decode_namerecord(header, storage_area, i, *strings))
1640 continue;
1642 exists = TRUE;
1645 if (!exists) {
1646 if (candidate != -1)
1647 exists = opentype_decode_namerecord(header, storage_area, candidate, *strings);
1648 else {
1649 IDWriteLocalizedStrings_Release(*strings);
1650 *strings = NULL;
1654 return exists ? S_OK : E_FAIL;
1657 /* Provides a conversion from DWRITE to OpenType name ids, input id should be valid, it's not checked. */
1658 HRESULT opentype_get_font_info_strings(const void *table_data, DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings)
1660 return opentype_get_font_strings_from_id(table_data, dwriteid_to_opentypeid[id], strings);
1663 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
1664 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
1665 HRESULT opentype_get_font_familyname(struct file_stream_desc *stream_desc, IDWriteLocalizedStrings **names)
1667 const TT_OS2_V2 *tt_os2;
1668 void *os2_context, *name_context;
1669 const void *name_table;
1670 HRESULT hr;
1672 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1673 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1675 *names = NULL;
1677 /* if Preferred Family doesn't conform to WWS model try WWS name */
1678 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1679 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_FAMILY_NAME, names);
1680 else
1681 hr = E_FAIL;
1683 if (FAILED(hr))
1684 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_FAMILY_NAME, names);
1685 if (FAILED(hr))
1686 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, names);
1688 if (tt_os2)
1689 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1690 if (name_context)
1691 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1693 return hr;
1696 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
1697 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
1698 HRESULT opentype_get_font_facename(struct file_stream_desc *stream_desc, WCHAR *lfname, IDWriteLocalizedStrings **names)
1700 IDWriteLocalizedStrings *lfnames;
1701 void *os2_context, *name_context;
1702 const TT_OS2_V2 *tt_os2;
1703 const void *name_table;
1704 HRESULT hr;
1706 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1707 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1709 *names = NULL;
1711 /* if Preferred Family doesn't conform to WWS model try WWS name */
1712 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1713 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_SUBFAMILY_NAME, names);
1714 else
1715 hr = E_FAIL;
1717 if (FAILED(hr))
1718 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME, names);
1719 if (FAILED(hr))
1720 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_SUBFAMILY_NAME, names);
1722 /* User locale is preferred, with fallback to en-us. */
1723 *lfname = 0;
1724 if (SUCCEEDED(opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, &lfnames))) {
1725 static const WCHAR enusW[] = {'e','n','-','u','s',0};
1726 WCHAR localeW[LOCALE_NAME_MAX_LENGTH];
1727 UINT32 index;
1728 BOOL exists;
1730 exists = FALSE;
1731 if (GetSystemDefaultLocaleName(localeW, sizeof(localeW)/sizeof(WCHAR)))
1732 IDWriteLocalizedStrings_FindLocaleName(lfnames, localeW, &index, &exists);
1734 if (!exists)
1735 IDWriteLocalizedStrings_FindLocaleName(lfnames, enusW, &index, &exists);
1737 if (exists)
1738 IDWriteLocalizedStrings_GetString(lfnames, index, lfname, LF_FACESIZE);
1740 IDWriteLocalizedStrings_Release(lfnames);
1743 if (tt_os2)
1744 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1745 if (name_context)
1746 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1748 return hr;
1751 static inline const OT_Script *opentype_get_script(const OT_ScriptList *scriptlist, UINT32 scripttag)
1753 UINT16 j;
1755 for (j = 0; j < GET_BE_WORD(scriptlist->ScriptCount); j++) {
1756 const char *tag = scriptlist->ScriptRecord[j].ScriptTag;
1757 if (scripttag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1758 return (OT_Script*)((BYTE*)scriptlist + GET_BE_WORD(scriptlist->ScriptRecord[j].Script));
1761 return NULL;
1764 static inline const OT_LangSys *opentype_get_langsys(const OT_Script *script, UINT32 languagetag)
1766 UINT16 j;
1768 for (j = 0; j < GET_BE_WORD(script->LangSysCount); j++) {
1769 const char *tag = script->LangSysRecord[j].LangSysTag;
1770 if (languagetag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1771 return (OT_LangSys*)((BYTE*)script + GET_BE_WORD(script->LangSysRecord[j].LangSys));
1774 return NULL;
1777 static void opentype_add_font_features(const GPOS_GSUB_Header *header, const OT_LangSys *langsys,
1778 UINT32 max_tagcount, UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1780 const OT_FeatureList *features = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
1781 UINT16 j;
1783 for (j = 0; j < GET_BE_WORD(langsys->FeatureCount); j++) {
1784 const OT_FeatureRecord *feature = &features->FeatureRecord[langsys->FeatureIndex[j]];
1785 const char *tag = feature->FeatureTag;
1787 if (*count < max_tagcount)
1788 tags[*count] = DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]);
1790 (*count)++;
1794 HRESULT opentype_get_typographic_features(IDWriteFontFace *fontface, UINT32 scripttag, UINT32 languagetag, UINT32 max_tagcount,
1795 UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1797 UINT32 tables[2] = { MS_GSUB_TAG, MS_GPOS_TAG };
1798 HRESULT hr;
1799 UINT8 i;
1801 *count = 0;
1802 for (i = 0; i < sizeof(tables)/sizeof(tables[0]); i++) {
1803 const OT_ScriptList *scriptlist;
1804 const GPOS_GSUB_Header *header;
1805 const OT_Script *script;
1806 const void *ptr;
1807 void *context;
1808 UINT32 size;
1809 BOOL exists;
1811 exists = FALSE;
1812 hr = IDWriteFontFace_TryGetFontTable(fontface, tables[i], &ptr, &size, &context, &exists);
1813 if (FAILED(hr))
1814 return hr;
1816 if (!exists)
1817 continue;
1819 header = (const GPOS_GSUB_Header*)ptr;
1820 scriptlist = (const OT_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
1822 script = opentype_get_script(scriptlist, scripttag);
1823 if (script) {
1824 const OT_LangSys *langsys = opentype_get_langsys(script, languagetag);
1825 if (langsys)
1826 opentype_add_font_features(header, langsys, max_tagcount, count, tags);
1829 IDWriteFontFace_ReleaseFontTable(fontface, context);
1832 return *count > max_tagcount ? E_NOT_SUFFICIENT_BUFFER : S_OK;
1835 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
1837 WORD num_ratios, i, group_offset = 0;
1838 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
1839 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
1841 num_ratios = GET_BE_WORD(hdr->numRatios);
1843 for (i = 0; i < num_ratios; i++) {
1845 if (!ratios[i].bCharSet) continue;
1847 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
1848 ratios[i].yEndRatio == 0) ||
1849 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
1850 ratios[i].yEndRatio >= dev_y_ratio))
1852 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
1853 break;
1856 if (group_offset)
1857 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
1858 return NULL;
1861 BOOL opentype_get_vdmx_size(const void *data, INT emsize, UINT16 *ascent, UINT16 *descent)
1863 const struct VDMX_Header *hdr = (const struct VDMX_Header*)data;
1864 const struct VDMX_group *group;
1865 const struct VDMX_vTable *tables;
1866 WORD recs, i;
1868 if (!data)
1869 return FALSE;
1871 group = find_vdmx_group(hdr);
1872 if (!group)
1873 return FALSE;
1875 recs = GET_BE_WORD(group->recs);
1876 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
1878 tables = (const struct VDMX_vTable *)(group + 1);
1879 for (i = 0; i < recs; i++) {
1880 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
1881 if (ppem > emsize) {
1882 FIXME("interpolate %d\n", emsize);
1883 return FALSE;
1886 if (ppem == emsize) {
1887 *ascent = (SHORT)GET_BE_WORD(tables[i].yMax);
1888 *descent = -(SHORT)GET_BE_WORD(tables[i].yMin);
1889 return TRUE;
1892 return FALSE;
1895 WORD opentype_get_gasp_flags(const WORD *ptr, UINT32 size, INT emsize)
1897 WORD num_recs, version;
1898 WORD flags = 0;
1900 if (!ptr)
1901 return 0;
1903 version = GET_BE_WORD( *ptr++ );
1904 num_recs = GET_BE_WORD( *ptr++ );
1905 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
1906 ERR("unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
1907 goto done;
1910 while (num_recs--) {
1911 flags = GET_BE_WORD( *(ptr + 1) );
1912 if (emsize <= GET_BE_WORD( *ptr )) break;
1913 ptr += 2;
1916 done:
1917 return flags;
1920 UINT32 opentype_get_cpal_palettecount(const void *cpal)
1922 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1923 return header ? GET_BE_WORD(header->numPalette) : 0;
1926 UINT32 opentype_get_cpal_paletteentrycount(const void *cpal)
1928 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1929 return header ? GET_BE_WORD(header->numPaletteEntries) : 0;
1932 HRESULT opentype_get_cpal_entries(const void *cpal, UINT32 palette, UINT32 first_entry_index, UINT32 entry_count,
1933 DWRITE_COLOR_F *entries)
1935 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1936 const struct CPAL_ColorRecord *records;
1937 UINT32 palettecount, entrycount, i;
1939 if (!header) return DWRITE_E_NOCOLOR;
1941 palettecount = GET_BE_WORD(header->numPalette);
1942 if (palette >= palettecount)
1943 return DWRITE_E_NOCOLOR;
1945 entrycount = GET_BE_WORD(header->numPaletteEntries);
1946 if (first_entry_index + entry_count > entrycount)
1947 return E_INVALIDARG;
1949 records = (const struct CPAL_ColorRecord*)((BYTE*)cpal + GET_BE_DWORD(header->offsetFirstColorRecord));
1950 first_entry_index += GET_BE_WORD(header->colorRecordIndices[palette]);
1952 for (i = 0; i < entry_count; i++) {
1953 entries[i].u1.r = records[first_entry_index + i].red / 255.0f;
1954 entries[i].u2.g = records[first_entry_index + i].green / 255.0f;
1955 entries[i].u3.b = records[first_entry_index + i].blue / 255.0f;
1956 entries[i].u4.a = records[first_entry_index + i].alpha / 255.0f;
1959 return S_OK;
1962 static int colr_compare_gid(const void *g, const void *r)
1964 const struct COLR_BaseGlyphRecord *record = r;
1965 UINT16 glyph = *(UINT16*)g, GID = GET_BE_WORD(record->GID);
1966 int ret = 0;
1968 if (glyph > GID)
1969 ret = 1;
1970 else if (glyph < GID)
1971 ret = -1;
1973 return ret;
1976 HRESULT opentype_get_colr_glyph(const void *colr, UINT16 glyph, struct dwrite_colorglyph *ret)
1978 const struct COLR_BaseGlyphRecord *record;
1979 const struct COLR_Header *header = colr;
1980 const struct COLR_LayerRecord *layer;
1981 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
1982 DWORD baserecordoffset = GET_BE_DWORD(header->offsetBaseGlyphRecord);
1983 WORD numbaserecords = GET_BE_WORD(header->numBaseGlyphRecords);
1985 record = bsearch(&glyph, (BYTE*)colr + baserecordoffset, numbaserecords, sizeof(struct COLR_BaseGlyphRecord),
1986 colr_compare_gid);
1987 if (!record) {
1988 ret->layer = 0;
1989 ret->first_layer = 0;
1990 ret->num_layers = 0;
1991 ret->glyph = glyph;
1992 ret->palette_index = 0xffff;
1993 return S_FALSE;
1996 ret->layer = 0;
1997 ret->first_layer = GET_BE_WORD(record->firstLayerIndex);
1998 ret->num_layers = GET_BE_WORD(record->numLayers);
2000 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + ret->first_layer + ret->layer;
2001 ret->glyph = GET_BE_WORD(layer->GID);
2002 ret->palette_index = GET_BE_WORD(layer->paletteIndex);
2004 return S_OK;
2007 void opentype_colr_next_glyph(const void *colr, struct dwrite_colorglyph *glyph)
2009 const struct COLR_Header *header = colr;
2010 const struct COLR_LayerRecord *layer;
2011 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
2013 /* iterated all the way through */
2014 if (glyph->layer == glyph->num_layers)
2015 return;
2017 glyph->layer++;
2018 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + glyph->first_layer + glyph->layer;
2019 glyph->glyph = GET_BE_WORD(layer->GID);
2020 glyph->palette_index = GET_BE_WORD(layer->paletteIndex);
2023 BOOL opentype_has_vertical_variants(IDWriteFontFace4 *fontface)
2025 const OT_FeatureList *featurelist;
2026 const OT_LookupList *lookup_list;
2027 BOOL exists = FALSE, ret = FALSE;
2028 const GPOS_GSUB_Header *header;
2029 const void *data;
2030 void *context;
2031 UINT32 size;
2032 HRESULT hr;
2033 UINT16 i;
2035 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
2036 if (FAILED(hr) || !exists)
2037 return FALSE;
2039 header = data;
2040 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
2041 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
2043 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
2044 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
2045 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
2046 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
2047 const GSUB_SingleSubstFormat2 *subst2;
2048 const OT_LookupTable *lookup_table;
2049 UINT32 offset;
2051 if (lookup_count == 0)
2052 continue;
2054 for (i = 0; i < lookup_count; i++) {
2055 /* check if lookup is empty */
2056 index = GET_BE_WORD(feature->LookupListIndex[i]);
2057 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
2059 type = GET_BE_WORD(lookup_table->LookupType);
2060 if (type != OPENTYPE_GPOS_SINGLE_SUBST && type != OPENTYPE_GPOS_EXTENSION_SUBST)
2061 continue;
2063 count = GET_BE_WORD(lookup_table->SubTableCount);
2064 if (count == 0)
2065 continue;
2067 offset = GET_BE_WORD(lookup_table->SubTable[0]);
2068 if (type == OPENTYPE_GPOS_EXTENSION_SUBST) {
2069 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
2070 if (GET_BE_WORD(ext->SubstFormat) == 1)
2071 offset += GET_BE_DWORD(ext->ExtensionOffset);
2072 else
2073 FIXME("Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
2076 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
2077 index = GET_BE_WORD(subst2->SubstFormat);
2078 if (index == 1)
2079 FIXME("Validate Single Substitution Format 1\n");
2080 else if (index == 2) {
2081 /* SimSun-ExtB has 0 glyph count for this substitution */
2082 if (GET_BE_WORD(subst2->GlyphCount) > 0) {
2083 ret = TRUE;
2084 break;
2087 else
2088 WARN("Unknown Single Substitution Format, %u\n", index);
2093 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2095 return ret;
2098 static BOOL opentype_has_font_table(IDWriteFontFace4 *fontface, UINT32 tag)
2100 BOOL exists = FALSE;
2101 const void *data;
2102 void *context;
2103 UINT32 size;
2104 HRESULT hr;
2106 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, &data, &size, &context, &exists);
2107 if (FAILED(hr))
2108 return FALSE;
2110 if (exists)
2111 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2113 return exists;
2116 static DWORD opentype_get_sbix_formats(IDWriteFontFace4 *fontface)
2118 UINT32 size, s, num_strikes;
2119 const sbix_header *header;
2120 UINT16 g, num_glyphs;
2121 BOOL exists = FALSE;
2122 const maxp *maxp;
2123 const void *data;
2124 DWORD ret = 0;
2125 void *context;
2126 HRESULT hr;
2128 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_MAXP_TAG, &data, &size, &context, &exists);
2129 if (FAILED(hr) || !exists)
2130 return 0;
2132 maxp = data;
2133 num_glyphs = GET_BE_WORD(maxp->numGlyphs);
2135 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2137 if (FAILED(IDWriteFontFace4_TryGetFontTable(fontface, MS_SBIX_TAG, &data, &size, &context, &exists))) {
2138 WARN("Failed to get 'sbix' table, %#x\n", hr);
2139 return 0;
2142 header = data;
2143 num_strikes = GET_BE_DWORD(header->numStrikes);
2145 for (s = 0; s < num_strikes; s++) {
2146 sbix_strike *strike = (sbix_strike *)((BYTE *)header + GET_BE_DWORD(header->strikeOffset[s]));
2148 for (g = 0; g < num_glyphs; g++) {
2149 DWORD offset = GET_BE_DWORD(strike->glyphDataOffsets[g]);
2150 DWORD offset_next = GET_BE_DWORD(strike->glyphDataOffsets[g + 1]);
2151 sbix_glyph_data *glyph_data;
2152 DWORD format;
2154 if (offset == offset_next)
2155 continue;
2157 glyph_data = (sbix_glyph_data *)((BYTE *)strike + offset);
2158 switch (format = glyph_data->graphicType)
2160 case MS_PNG__TAG:
2161 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
2162 break;
2163 case MS_JPG__TAG:
2164 ret |= DWRITE_GLYPH_IMAGE_FORMATS_JPEG;
2165 break;
2166 case MS_TIFF_TAG:
2167 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TIFF;
2168 break;
2169 default:
2170 format = GET_BE_DWORD(format);
2171 FIXME("unexpected bitmap format %s\n", debugstr_an((char *)&format, 4));
2176 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2178 return ret;
2181 static UINT32 opentype_get_cblc_formats(IDWriteFontFace4 *fontface)
2183 CBLCBitmapSizeTable *sizes;
2184 UINT32 num_sizes, size, s;
2185 BOOL exists = FALSE;
2186 CBLCHeader *header;
2187 UINT32 ret = 0;
2188 void *context;
2189 HRESULT hr;
2191 if (FAILED(hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_CBLC_TAG, (const void **)&header, &size,
2192 &context, &exists)))
2193 return 0;
2195 if (!exists)
2196 return 0;
2198 num_sizes = GET_BE_DWORD(header->numSizes);
2199 sizes = (CBLCBitmapSizeTable *)(header + 1);
2201 for (s = 0; s < num_sizes; s++) {
2202 BYTE bpp = sizes->bitDepth;
2204 if (bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8)
2205 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
2206 else if (bpp == 32)
2207 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8;
2210 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2212 return ret;
2215 UINT32 opentype_get_glyph_image_formats(IDWriteFontFace4 *fontface)
2217 UINT32 ret = DWRITE_GLYPH_IMAGE_FORMATS_NONE;
2219 if (opentype_has_font_table(fontface, MS_GLYF_TAG))
2220 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
2222 if (opentype_has_font_table(fontface, MS_CFF__TAG) ||
2223 opentype_has_font_table(fontface, MS_CFF2_TAG))
2224 ret |= DWRITE_GLYPH_IMAGE_FORMATS_CFF;
2226 if (opentype_has_font_table(fontface, MS_COLR_TAG))
2227 ret |= DWRITE_GLYPH_IMAGE_FORMATS_COLR;
2229 if (opentype_has_font_table(fontface, MS_SVG__TAG))
2230 ret |= DWRITE_GLYPH_IMAGE_FORMATS_SVG;
2232 if (opentype_has_font_table(fontface, MS_SBIX_TAG))
2233 ret |= opentype_get_sbix_formats(fontface);
2235 if (opentype_has_font_table(fontface, MS_CBLC_TAG))
2236 ret |= opentype_get_cblc_formats(fontface);
2238 return ret;
2241 DWRITE_CONTAINER_TYPE opentype_analyze_container_type(void const *data, UINT32 data_size)
2243 DWORD signature;
2245 if (data_size < sizeof(DWORD))
2246 return DWRITE_CONTAINER_TYPE_UNKNOWN;
2248 /* Both WOFF and WOFF2 start with 4 bytes signature. */
2249 signature = *(DWORD *)data;
2251 switch (signature)
2253 case MS_WOFF_TAG:
2254 return DWRITE_CONTAINER_TYPE_WOFF;
2255 case MS_WOF2_TAG:
2256 return DWRITE_CONTAINER_TYPE_WOFF2;
2257 default:
2258 return DWRITE_CONTAINER_TYPE_UNKNOWN;