Release 4.0.4.
[wine.git] / dlls / dwrite / opentype.c
blobdb7dabcd56c12c3886565757a01bf3c56ca39316
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;
1312 else {
1313 metrics->strikethroughPosition = metrics->designUnitsPerEm / 3;
1314 if (tt_hhea) {
1315 metrics->ascent = GET_BE_WORD(tt_hhea->ascender);
1316 metrics->descent = abs((SHORT)GET_BE_WORD(tt_hhea->descender));
1320 if (tt_post) {
1321 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
1322 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
1325 if (metrics->underlineThickness == 0)
1326 metrics->underlineThickness = metrics->designUnitsPerEm / 14;
1327 if (metrics->strikethroughThickness == 0)
1328 metrics->strikethroughThickness = metrics->underlineThickness;
1330 /* estimate missing metrics */
1331 if (metrics->xHeight == 0)
1332 metrics->xHeight = metrics->designUnitsPerEm / 2;
1333 if (metrics->capHeight == 0)
1334 metrics->capHeight = metrics->designUnitsPerEm * 7 / 10;
1336 if (tt_os2)
1337 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1338 if (tt_head)
1339 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, head_context);
1340 if (tt_post)
1341 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, post_context);
1342 if (tt_hhea)
1343 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, hhea_context);
1346 void opentype_get_font_properties(struct file_stream_desc *stream_desc, struct dwrite_font_props *props)
1348 void *os2_context, *head_context;
1349 const TT_OS2_V2 *tt_os2;
1350 const TT_HEAD *tt_head;
1352 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1353 opentype_get_font_table(stream_desc, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
1355 /* default stretch, weight and style to normal */
1356 props->stretch = DWRITE_FONT_STRETCH_NORMAL;
1357 props->weight = DWRITE_FONT_WEIGHT_NORMAL;
1358 props->style = DWRITE_FONT_STYLE_NORMAL;
1359 memset(&props->panose, 0, sizeof(props->panose));
1360 memset(&props->fontsig, 0, sizeof(props->fontsig));
1361 memset(&props->lf, 0, sizeof(props->lf));
1363 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1364 if (tt_os2) {
1365 USHORT version = GET_BE_WORD(tt_os2->version);
1366 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
1367 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
1368 USHORT usWidthClass = GET_BE_WORD(tt_os2->usWidthClass);
1370 if (usWidthClass > DWRITE_FONT_STRETCH_UNDEFINED && usWidthClass <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
1371 props->stretch = usWidthClass;
1373 if (usWeightClass >= 1 && usWeightClass <= 9)
1374 usWeightClass *= 100;
1376 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
1377 props->weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
1378 else if (usWeightClass > 0)
1379 props->weight = usWeightClass;
1381 if (version >= 4 && (fsSelection & OS2_FSSELECTION_OBLIQUE))
1382 props->style = DWRITE_FONT_STYLE_OBLIQUE;
1383 else if (fsSelection & OS2_FSSELECTION_ITALIC)
1384 props->style = DWRITE_FONT_STYLE_ITALIC;
1385 props->lf.lfItalic = !!(fsSelection & OS2_FSSELECTION_ITALIC);
1387 memcpy(&props->panose, &tt_os2->panose, sizeof(props->panose));
1389 /* FONTSIGNATURE */
1390 props->fontsig.fsUsb[0] = GET_BE_DWORD(tt_os2->ulUnicodeRange1);
1391 props->fontsig.fsUsb[1] = GET_BE_DWORD(tt_os2->ulUnicodeRange2);
1392 props->fontsig.fsUsb[2] = GET_BE_DWORD(tt_os2->ulUnicodeRange3);
1393 props->fontsig.fsUsb[3] = GET_BE_DWORD(tt_os2->ulUnicodeRange4);
1395 if (GET_BE_WORD(tt_os2->version) == 0) {
1396 props->fontsig.fsCsb[0] = 0;
1397 props->fontsig.fsCsb[1] = 0;
1399 else {
1400 props->fontsig.fsCsb[0] = GET_BE_DWORD(tt_os2->ulCodePageRange1);
1401 props->fontsig.fsCsb[1] = GET_BE_DWORD(tt_os2->ulCodePageRange2);
1404 else if (tt_head) {
1405 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
1407 if (macStyle & TT_HEAD_MACSTYLE_CONDENSED)
1408 props->stretch = DWRITE_FONT_STRETCH_CONDENSED;
1409 else if (macStyle & TT_HEAD_MACSTYLE_EXTENDED)
1410 props->stretch = DWRITE_FONT_STRETCH_EXPANDED;
1412 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
1413 props->weight = DWRITE_FONT_WEIGHT_BOLD;
1415 if (macStyle & TT_HEAD_MACSTYLE_ITALIC) {
1416 props->style = DWRITE_FONT_STYLE_ITALIC;
1417 props->lf.lfItalic = 1;
1421 props->lf.lfWeight = props->weight;
1423 TRACE("stretch=%d, weight=%d, style %d\n", props->stretch, props->weight, props->style);
1425 if (tt_os2)
1426 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1427 if (tt_head)
1428 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, head_context);
1431 static UINT get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform, USHORT encoding)
1433 UINT codepage = 0;
1435 switch (platform) {
1436 case OPENTYPE_PLATFORM_UNICODE:
1437 break;
1438 case OPENTYPE_PLATFORM_MAC:
1439 switch (encoding)
1441 case TT_NAME_MAC_ENCODING_ROMAN:
1442 codepage = 10000;
1443 break;
1444 case TT_NAME_MAC_ENCODING_JAPANESE:
1445 codepage = 10001;
1446 break;
1447 case TT_NAME_MAC_ENCODING_TRAD_CHINESE:
1448 codepage = 10002;
1449 break;
1450 case TT_NAME_MAC_ENCODING_KOREAN:
1451 codepage = 10003;
1452 break;
1453 case TT_NAME_MAC_ENCODING_ARABIC:
1454 codepage = 10004;
1455 break;
1456 case TT_NAME_MAC_ENCODING_HEBREW:
1457 codepage = 10005;
1458 break;
1459 case TT_NAME_MAC_ENCODING_GREEK:
1460 codepage = 10006;
1461 break;
1462 case TT_NAME_MAC_ENCODING_RUSSIAN:
1463 codepage = 10007;
1464 break;
1465 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE:
1466 codepage = 10008;
1467 break;
1468 case TT_NAME_MAC_ENCODING_THAI:
1469 codepage = 10021;
1470 break;
1471 default:
1472 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1473 break;
1475 break;
1476 case OPENTYPE_PLATFORM_WIN:
1477 switch (encoding)
1479 case TT_NAME_WINDOWS_ENCODING_SYMBOL:
1480 case TT_NAME_WINDOWS_ENCODING_UCS2:
1481 break;
1482 case TT_NAME_WINDOWS_ENCODING_SJIS:
1483 codepage = 932;
1484 break;
1485 case TT_NAME_WINDOWS_ENCODING_PRC:
1486 codepage = 936;
1487 break;
1488 case TT_NAME_WINDOWS_ENCODING_BIG5:
1489 codepage = 950;
1490 break;
1491 case TT_NAME_WINDOWS_ENCODING_WANSUNG:
1492 codepage = 20949;
1493 break;
1494 case TT_NAME_WINDOWS_ENCODING_JOHAB:
1495 codepage = 1361;
1496 break;
1497 default:
1498 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1499 break;
1501 break;
1502 default:
1503 FIXME("unknown platform %d\n", platform);
1506 return codepage;
1509 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform, USHORT lang_id, WCHAR *locale, USHORT locale_len)
1511 static const WCHAR enusW[] = {'e','n','-','U','S',0};
1513 switch (platform) {
1514 case OPENTYPE_PLATFORM_MAC:
1516 const char *locale_name = NULL;
1518 if (lang_id > TT_NAME_MAC_LANGID_AZER_ROMAN)
1519 WARN("invalid mac lang id %d\n", lang_id);
1520 else if (!name_mac_langid_to_locale[lang_id][0])
1521 FIXME("failed to map mac lang id %d to locale name\n", lang_id);
1522 else
1523 locale_name = name_mac_langid_to_locale[lang_id];
1525 if (locale_name)
1526 MultiByteToWideChar(CP_ACP, 0, name_mac_langid_to_locale[lang_id], -1, locale, locale_len);
1527 else
1528 strcpyW(locale, enusW);
1529 break;
1531 case OPENTYPE_PLATFORM_WIN:
1532 if (!LCIDToLocaleName(MAKELCID(lang_id, SORT_DEFAULT), locale, locale_len, 0)) {
1533 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id, SORT_DEFAULT));
1534 strcpyW(locale, enusW);
1536 break;
1537 case OPENTYPE_PLATFORM_UNICODE:
1538 strcpyW(locale, enusW);
1539 break;
1540 default:
1541 FIXME("unknown platform %d\n", platform);
1545 static BOOL opentype_decode_namerecord(const TT_NAME_V0 *header, BYTE *storage_area, USHORT recid, IDWriteLocalizedStrings *strings)
1547 const TT_NameRecord *record = &header->nameRecord[recid];
1548 USHORT lang_id, length, offset, encoding, platform;
1549 BOOL ret = FALSE;
1551 platform = GET_BE_WORD(record->platformID);
1552 lang_id = GET_BE_WORD(record->languageID);
1553 length = GET_BE_WORD(record->length);
1554 offset = GET_BE_WORD(record->offset);
1555 encoding = GET_BE_WORD(record->encodingID);
1557 if (lang_id < 0x8000) {
1558 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
1559 WCHAR *name_string;
1560 UINT codepage;
1562 codepage = get_name_record_codepage(platform, encoding);
1563 get_name_record_locale(platform, lang_id, locale, ARRAY_SIZE(locale));
1565 if (codepage) {
1566 DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0);
1567 name_string = heap_alloc(sizeof(WCHAR) * (len+1));
1568 MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len);
1569 name_string[len] = 0;
1571 else {
1572 int i;
1574 length /= sizeof(WCHAR);
1575 name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length);
1576 for (i = 0; i < length; i++)
1577 name_string[i] = GET_BE_WORD(name_string[i]);
1580 TRACE("string %s for locale %s found\n", debugstr_w(name_string), debugstr_w(locale));
1581 add_localizedstring(strings, locale, name_string);
1582 heap_free(name_string);
1583 ret = TRUE;
1585 else
1586 FIXME("handle NAME format 1\n");
1588 return ret;
1591 static HRESULT opentype_get_font_strings_from_id(const void *table_data, enum OPENTYPE_STRING_ID id, IDWriteLocalizedStrings **strings)
1593 const TT_NAME_V0 *header;
1594 BYTE *storage_area = 0;
1595 USHORT count = 0;
1596 int i, candidate;
1597 WORD format;
1598 BOOL exists;
1599 HRESULT hr;
1601 if (!table_data)
1602 return E_FAIL;
1604 hr = create_localizedstrings(strings);
1605 if (FAILED(hr)) return hr;
1607 header = table_data;
1608 format = GET_BE_WORD(header->format);
1610 switch (format) {
1611 case 0:
1612 case 1:
1613 break;
1614 default:
1615 FIXME("unsupported NAME format %d\n", format);
1618 storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset);
1619 count = GET_BE_WORD(header->count);
1621 exists = FALSE;
1622 candidate = -1;
1623 for (i = 0; i < count; i++) {
1624 const TT_NameRecord *record = &header->nameRecord[i];
1625 USHORT platform;
1627 if (GET_BE_WORD(record->nameID) != id)
1628 continue;
1630 /* Right now only accept unicode and windows encoded fonts */
1631 platform = GET_BE_WORD(record->platformID);
1632 if (platform != OPENTYPE_PLATFORM_UNICODE &&
1633 platform != OPENTYPE_PLATFORM_MAC &&
1634 platform != OPENTYPE_PLATFORM_WIN)
1636 FIXME("platform %i not supported\n", platform);
1637 continue;
1640 /* Skip such entries for now, fonts tend to duplicate those strings as
1641 WIN platform entries. If font does not have WIN or MAC entry for this id, we will
1642 use this Unicode platform entry while assuming en-US locale. */
1643 if (platform == OPENTYPE_PLATFORM_UNICODE) {
1644 candidate = i;
1645 continue;
1648 if (!opentype_decode_namerecord(header, storage_area, i, *strings))
1649 continue;
1651 exists = TRUE;
1654 if (!exists) {
1655 if (candidate != -1)
1656 exists = opentype_decode_namerecord(header, storage_area, candidate, *strings);
1657 else {
1658 IDWriteLocalizedStrings_Release(*strings);
1659 *strings = NULL;
1663 return exists ? S_OK : E_FAIL;
1666 /* Provides a conversion from DWRITE to OpenType name ids, input id should be valid, it's not checked. */
1667 HRESULT opentype_get_font_info_strings(const void *table_data, DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings)
1669 return opentype_get_font_strings_from_id(table_data, dwriteid_to_opentypeid[id], strings);
1672 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
1673 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
1674 HRESULT opentype_get_font_familyname(struct file_stream_desc *stream_desc, IDWriteLocalizedStrings **names)
1676 const TT_OS2_V2 *tt_os2;
1677 void *os2_context, *name_context;
1678 const void *name_table;
1679 HRESULT hr;
1681 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1682 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1684 *names = NULL;
1686 /* if Preferred Family doesn't conform to WWS model try WWS name */
1687 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1688 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_FAMILY_NAME, names);
1689 else
1690 hr = E_FAIL;
1692 if (FAILED(hr))
1693 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_FAMILY_NAME, names);
1694 if (FAILED(hr))
1695 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, names);
1697 if (tt_os2)
1698 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1699 if (name_context)
1700 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1702 return hr;
1705 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
1706 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
1707 HRESULT opentype_get_font_facename(struct file_stream_desc *stream_desc, WCHAR *lfname, IDWriteLocalizedStrings **names)
1709 IDWriteLocalizedStrings *lfnames;
1710 void *os2_context, *name_context;
1711 const TT_OS2_V2 *tt_os2;
1712 const void *name_table;
1713 HRESULT hr;
1715 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1716 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1718 *names = NULL;
1720 /* if Preferred Family doesn't conform to WWS model try WWS name */
1721 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1722 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_SUBFAMILY_NAME, names);
1723 else
1724 hr = E_FAIL;
1726 if (FAILED(hr))
1727 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME, names);
1728 if (FAILED(hr))
1729 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_SUBFAMILY_NAME, names);
1731 /* User locale is preferred, with fallback to en-us. */
1732 *lfname = 0;
1733 if (SUCCEEDED(opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, &lfnames))) {
1734 static const WCHAR enusW[] = {'e','n','-','u','s',0};
1735 WCHAR localeW[LOCALE_NAME_MAX_LENGTH];
1736 UINT32 index;
1737 BOOL exists;
1739 exists = FALSE;
1740 if (GetSystemDefaultLocaleName(localeW, ARRAY_SIZE(localeW)))
1741 IDWriteLocalizedStrings_FindLocaleName(lfnames, localeW, &index, &exists);
1743 if (!exists)
1744 IDWriteLocalizedStrings_FindLocaleName(lfnames, enusW, &index, &exists);
1746 if (exists) {
1747 UINT32 length = 0;
1748 WCHAR *nameW;
1750 IDWriteLocalizedStrings_GetStringLength(lfnames, index, &length);
1751 nameW = heap_alloc((length + 1) * sizeof(WCHAR));
1752 if (nameW) {
1753 *nameW = 0;
1754 IDWriteLocalizedStrings_GetString(lfnames, index, nameW, length + 1);
1755 lstrcpynW(lfname, nameW, LF_FACESIZE);
1756 heap_free(nameW);
1760 IDWriteLocalizedStrings_Release(lfnames);
1763 if (tt_os2)
1764 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1765 if (name_context)
1766 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1768 return hr;
1771 static inline const OT_Script *opentype_get_script(const OT_ScriptList *scriptlist, UINT32 scripttag)
1773 UINT16 j;
1775 for (j = 0; j < GET_BE_WORD(scriptlist->ScriptCount); j++) {
1776 const char *tag = scriptlist->ScriptRecord[j].ScriptTag;
1777 if (scripttag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1778 return (OT_Script*)((BYTE*)scriptlist + GET_BE_WORD(scriptlist->ScriptRecord[j].Script));
1781 return NULL;
1784 static inline const OT_LangSys *opentype_get_langsys(const OT_Script *script, UINT32 languagetag)
1786 UINT16 j;
1788 for (j = 0; j < GET_BE_WORD(script->LangSysCount); j++) {
1789 const char *tag = script->LangSysRecord[j].LangSysTag;
1790 if (languagetag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1791 return (OT_LangSys*)((BYTE*)script + GET_BE_WORD(script->LangSysRecord[j].LangSys));
1794 return NULL;
1797 static void opentype_add_font_features(const GPOS_GSUB_Header *header, const OT_LangSys *langsys,
1798 UINT32 max_tagcount, UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1800 const OT_FeatureList *features = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
1801 UINT16 j;
1803 for (j = 0; j < GET_BE_WORD(langsys->FeatureCount); j++) {
1804 const OT_FeatureRecord *feature = &features->FeatureRecord[langsys->FeatureIndex[j]];
1805 const char *tag = feature->FeatureTag;
1807 if (*count < max_tagcount)
1808 tags[*count] = DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]);
1810 (*count)++;
1814 HRESULT opentype_get_typographic_features(IDWriteFontFace *fontface, UINT32 scripttag, UINT32 languagetag, UINT32 max_tagcount,
1815 UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1817 UINT32 tables[2] = { MS_GSUB_TAG, MS_GPOS_TAG };
1818 HRESULT hr;
1819 UINT8 i;
1821 *count = 0;
1822 for (i = 0; i < ARRAY_SIZE(tables); i++) {
1823 const OT_ScriptList *scriptlist;
1824 const GPOS_GSUB_Header *header;
1825 const OT_Script *script;
1826 const void *ptr;
1827 void *context;
1828 UINT32 size;
1829 BOOL exists;
1831 exists = FALSE;
1832 hr = IDWriteFontFace_TryGetFontTable(fontface, tables[i], &ptr, &size, &context, &exists);
1833 if (FAILED(hr))
1834 return hr;
1836 if (!exists)
1837 continue;
1839 header = (const GPOS_GSUB_Header*)ptr;
1840 scriptlist = (const OT_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
1842 script = opentype_get_script(scriptlist, scripttag);
1843 if (script) {
1844 const OT_LangSys *langsys = opentype_get_langsys(script, languagetag);
1845 if (langsys)
1846 opentype_add_font_features(header, langsys, max_tagcount, count, tags);
1849 IDWriteFontFace_ReleaseFontTable(fontface, context);
1852 return *count > max_tagcount ? E_NOT_SUFFICIENT_BUFFER : S_OK;
1855 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
1857 WORD num_ratios, i, group_offset = 0;
1858 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
1859 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
1861 num_ratios = GET_BE_WORD(hdr->numRatios);
1863 for (i = 0; i < num_ratios; i++) {
1865 if (!ratios[i].bCharSet) continue;
1867 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
1868 ratios[i].yEndRatio == 0) ||
1869 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
1870 ratios[i].yEndRatio >= dev_y_ratio))
1872 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
1873 break;
1876 if (group_offset)
1877 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
1878 return NULL;
1881 BOOL opentype_get_vdmx_size(const void *data, INT emsize, UINT16 *ascent, UINT16 *descent)
1883 const struct VDMX_Header *hdr = (const struct VDMX_Header*)data;
1884 const struct VDMX_group *group;
1885 const struct VDMX_vTable *tables;
1886 WORD recs, i;
1888 if (!data)
1889 return FALSE;
1891 group = find_vdmx_group(hdr);
1892 if (!group)
1893 return FALSE;
1895 recs = GET_BE_WORD(group->recs);
1896 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
1898 tables = (const struct VDMX_vTable *)(group + 1);
1899 for (i = 0; i < recs; i++) {
1900 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
1901 if (ppem > emsize) {
1902 FIXME("interpolate %d\n", emsize);
1903 return FALSE;
1906 if (ppem == emsize) {
1907 *ascent = (SHORT)GET_BE_WORD(tables[i].yMax);
1908 *descent = -(SHORT)GET_BE_WORD(tables[i].yMin);
1909 return TRUE;
1912 return FALSE;
1915 WORD opentype_get_gasp_flags(const WORD *ptr, UINT32 size, INT emsize)
1917 WORD num_recs, version;
1918 WORD flags = 0;
1920 if (!ptr)
1921 return 0;
1923 version = GET_BE_WORD( *ptr++ );
1924 num_recs = GET_BE_WORD( *ptr++ );
1925 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
1926 ERR("unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
1927 goto done;
1930 while (num_recs--) {
1931 flags = GET_BE_WORD( *(ptr + 1) );
1932 if (emsize <= GET_BE_WORD( *ptr )) break;
1933 ptr += 2;
1936 done:
1937 return flags;
1940 UINT32 opentype_get_cpal_palettecount(const void *cpal)
1942 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1943 return header ? GET_BE_WORD(header->numPalette) : 0;
1946 UINT32 opentype_get_cpal_paletteentrycount(const void *cpal)
1948 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1949 return header ? GET_BE_WORD(header->numPaletteEntries) : 0;
1952 HRESULT opentype_get_cpal_entries(const void *cpal, UINT32 palette, UINT32 first_entry_index, UINT32 entry_count,
1953 DWRITE_COLOR_F *entries)
1955 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1956 const struct CPAL_ColorRecord *records;
1957 UINT32 palettecount, entrycount, i;
1959 if (!header) return DWRITE_E_NOCOLOR;
1961 palettecount = GET_BE_WORD(header->numPalette);
1962 if (palette >= palettecount)
1963 return DWRITE_E_NOCOLOR;
1965 entrycount = GET_BE_WORD(header->numPaletteEntries);
1966 if (first_entry_index + entry_count > entrycount)
1967 return E_INVALIDARG;
1969 records = (const struct CPAL_ColorRecord*)((BYTE*)cpal + GET_BE_DWORD(header->offsetFirstColorRecord));
1970 first_entry_index += GET_BE_WORD(header->colorRecordIndices[palette]);
1972 for (i = 0; i < entry_count; i++) {
1973 entries[i].u1.r = records[first_entry_index + i].red / 255.0f;
1974 entries[i].u2.g = records[first_entry_index + i].green / 255.0f;
1975 entries[i].u3.b = records[first_entry_index + i].blue / 255.0f;
1976 entries[i].u4.a = records[first_entry_index + i].alpha / 255.0f;
1979 return S_OK;
1982 static int colr_compare_gid(const void *g, const void *r)
1984 const struct COLR_BaseGlyphRecord *record = r;
1985 UINT16 glyph = *(UINT16*)g, GID = GET_BE_WORD(record->GID);
1986 int ret = 0;
1988 if (glyph > GID)
1989 ret = 1;
1990 else if (glyph < GID)
1991 ret = -1;
1993 return ret;
1996 HRESULT opentype_get_colr_glyph(const void *colr, UINT16 glyph, struct dwrite_colorglyph *ret)
1998 const struct COLR_BaseGlyphRecord *record;
1999 const struct COLR_Header *header = colr;
2000 const struct COLR_LayerRecord *layer;
2001 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
2002 DWORD baserecordoffset = GET_BE_DWORD(header->offsetBaseGlyphRecord);
2003 WORD numbaserecords = GET_BE_WORD(header->numBaseGlyphRecords);
2005 record = bsearch(&glyph, (BYTE*)colr + baserecordoffset, numbaserecords, sizeof(struct COLR_BaseGlyphRecord),
2006 colr_compare_gid);
2007 if (!record) {
2008 ret->layer = 0;
2009 ret->first_layer = 0;
2010 ret->num_layers = 0;
2011 ret->glyph = glyph;
2012 ret->palette_index = 0xffff;
2013 return S_FALSE;
2016 ret->layer = 0;
2017 ret->first_layer = GET_BE_WORD(record->firstLayerIndex);
2018 ret->num_layers = GET_BE_WORD(record->numLayers);
2020 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + ret->first_layer + ret->layer;
2021 ret->glyph = GET_BE_WORD(layer->GID);
2022 ret->palette_index = GET_BE_WORD(layer->paletteIndex);
2024 return S_OK;
2027 void opentype_colr_next_glyph(const void *colr, struct dwrite_colorglyph *glyph)
2029 const struct COLR_Header *header = colr;
2030 const struct COLR_LayerRecord *layer;
2031 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
2033 /* iterated all the way through */
2034 if (glyph->layer == glyph->num_layers)
2035 return;
2037 glyph->layer++;
2038 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + glyph->first_layer + glyph->layer;
2039 glyph->glyph = GET_BE_WORD(layer->GID);
2040 glyph->palette_index = GET_BE_WORD(layer->paletteIndex);
2043 BOOL opentype_has_vertical_variants(IDWriteFontFace4 *fontface)
2045 const OT_FeatureList *featurelist;
2046 const OT_LookupList *lookup_list;
2047 BOOL exists = FALSE, ret = FALSE;
2048 const GPOS_GSUB_Header *header;
2049 const void *data;
2050 void *context;
2051 UINT32 size;
2052 HRESULT hr;
2053 UINT16 i;
2055 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
2056 if (FAILED(hr) || !exists)
2057 return FALSE;
2059 header = data;
2060 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
2061 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
2063 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
2064 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
2065 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
2066 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
2067 const GSUB_SingleSubstFormat2 *subst2;
2068 const OT_LookupTable *lookup_table;
2069 UINT32 offset;
2071 if (lookup_count == 0)
2072 continue;
2074 for (i = 0; i < lookup_count; i++) {
2075 /* check if lookup is empty */
2076 index = GET_BE_WORD(feature->LookupListIndex[i]);
2077 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
2079 type = GET_BE_WORD(lookup_table->LookupType);
2080 if (type != OPENTYPE_GPOS_SINGLE_SUBST && type != OPENTYPE_GPOS_EXTENSION_SUBST)
2081 continue;
2083 count = GET_BE_WORD(lookup_table->SubTableCount);
2084 if (count == 0)
2085 continue;
2087 offset = GET_BE_WORD(lookup_table->SubTable[0]);
2088 if (type == OPENTYPE_GPOS_EXTENSION_SUBST) {
2089 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
2090 if (GET_BE_WORD(ext->SubstFormat) == 1)
2091 offset += GET_BE_DWORD(ext->ExtensionOffset);
2092 else
2093 FIXME("Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
2096 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
2097 index = GET_BE_WORD(subst2->SubstFormat);
2098 if (index == 1)
2099 FIXME("Validate Single Substitution Format 1\n");
2100 else if (index == 2) {
2101 /* SimSun-ExtB has 0 glyph count for this substitution */
2102 if (GET_BE_WORD(subst2->GlyphCount) > 0) {
2103 ret = TRUE;
2104 break;
2107 else
2108 WARN("Unknown Single Substitution Format, %u\n", index);
2113 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2115 return ret;
2118 static BOOL opentype_has_font_table(IDWriteFontFace4 *fontface, UINT32 tag)
2120 BOOL exists = FALSE;
2121 const void *data;
2122 void *context;
2123 UINT32 size;
2124 HRESULT hr;
2126 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, &data, &size, &context, &exists);
2127 if (FAILED(hr))
2128 return FALSE;
2130 if (exists)
2131 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2133 return exists;
2136 static DWORD opentype_get_sbix_formats(IDWriteFontFace4 *fontface)
2138 UINT32 size, s, num_strikes;
2139 const sbix_header *header;
2140 UINT16 g, num_glyphs;
2141 BOOL exists = FALSE;
2142 const maxp *maxp;
2143 const void *data;
2144 DWORD ret = 0;
2145 void *context;
2146 HRESULT hr;
2148 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_MAXP_TAG, &data, &size, &context, &exists);
2149 if (FAILED(hr) || !exists)
2150 return 0;
2152 maxp = data;
2153 num_glyphs = GET_BE_WORD(maxp->numGlyphs);
2155 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2157 if (FAILED(IDWriteFontFace4_TryGetFontTable(fontface, MS_SBIX_TAG, &data, &size, &context, &exists))) {
2158 WARN("Failed to get 'sbix' table, %#x\n", hr);
2159 return 0;
2162 header = data;
2163 num_strikes = GET_BE_DWORD(header->numStrikes);
2165 for (s = 0; s < num_strikes; s++) {
2166 sbix_strike *strike = (sbix_strike *)((BYTE *)header + GET_BE_DWORD(header->strikeOffset[s]));
2168 for (g = 0; g < num_glyphs; g++) {
2169 DWORD offset = GET_BE_DWORD(strike->glyphDataOffsets[g]);
2170 DWORD offset_next = GET_BE_DWORD(strike->glyphDataOffsets[g + 1]);
2171 sbix_glyph_data *glyph_data;
2172 DWORD format;
2174 if (offset == offset_next)
2175 continue;
2177 glyph_data = (sbix_glyph_data *)((BYTE *)strike + offset);
2178 switch (format = glyph_data->graphicType)
2180 case MS_PNG__TAG:
2181 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
2182 break;
2183 case MS_JPG__TAG:
2184 ret |= DWRITE_GLYPH_IMAGE_FORMATS_JPEG;
2185 break;
2186 case MS_TIFF_TAG:
2187 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TIFF;
2188 break;
2189 default:
2190 format = GET_BE_DWORD(format);
2191 FIXME("unexpected bitmap format %s\n", debugstr_an((char *)&format, 4));
2196 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2198 return ret;
2201 static UINT32 opentype_get_cblc_formats(IDWriteFontFace4 *fontface)
2203 CBLCBitmapSizeTable *sizes;
2204 UINT32 num_sizes, size, s;
2205 BOOL exists = FALSE;
2206 CBLCHeader *header;
2207 UINT32 ret = 0;
2208 void *context;
2209 HRESULT hr;
2211 if (FAILED(hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_CBLC_TAG, (const void **)&header, &size,
2212 &context, &exists)))
2213 return 0;
2215 if (!exists)
2216 return 0;
2218 num_sizes = GET_BE_DWORD(header->numSizes);
2219 sizes = (CBLCBitmapSizeTable *)(header + 1);
2221 for (s = 0; s < num_sizes; s++) {
2222 BYTE bpp = sizes->bitDepth;
2224 if (bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8)
2225 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
2226 else if (bpp == 32)
2227 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8;
2230 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2232 return ret;
2235 UINT32 opentype_get_glyph_image_formats(IDWriteFontFace4 *fontface)
2237 UINT32 ret = DWRITE_GLYPH_IMAGE_FORMATS_NONE;
2239 if (opentype_has_font_table(fontface, MS_GLYF_TAG))
2240 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
2242 if (opentype_has_font_table(fontface, MS_CFF__TAG) ||
2243 opentype_has_font_table(fontface, MS_CFF2_TAG))
2244 ret |= DWRITE_GLYPH_IMAGE_FORMATS_CFF;
2246 if (opentype_has_font_table(fontface, MS_COLR_TAG))
2247 ret |= DWRITE_GLYPH_IMAGE_FORMATS_COLR;
2249 if (opentype_has_font_table(fontface, MS_SVG__TAG))
2250 ret |= DWRITE_GLYPH_IMAGE_FORMATS_SVG;
2252 if (opentype_has_font_table(fontface, MS_SBIX_TAG))
2253 ret |= opentype_get_sbix_formats(fontface);
2255 if (opentype_has_font_table(fontface, MS_CBLC_TAG))
2256 ret |= opentype_get_cblc_formats(fontface);
2258 return ret;
2261 DWRITE_CONTAINER_TYPE opentype_analyze_container_type(void const *data, UINT32 data_size)
2263 DWORD signature;
2265 if (data_size < sizeof(DWORD))
2266 return DWRITE_CONTAINER_TYPE_UNKNOWN;
2268 /* Both WOFF and WOFF2 start with 4 bytes signature. */
2269 signature = *(DWORD *)data;
2271 switch (signature)
2273 case MS_WOFF_TAG:
2274 return DWRITE_CONTAINER_TYPE_WOFF;
2275 case MS_WOF2_TAG:
2276 return DWRITE_CONTAINER_TYPE_WOFF2;
2277 default:
2278 return DWRITE_CONTAINER_TYPE_UNKNOWN;