comctl32/edit: Force update on focus change.
[wine.git] / dlls / dwrite / opentype.c
blob18fb00be09ad85770b00edc1e34dad243f580560
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;
1378 props->lf.lfItalic = !!(fsSelection & OS2_FSSELECTION_ITALIC);
1380 memcpy(&props->panose, &tt_os2->panose, sizeof(props->panose));
1382 /* FONTSIGNATURE */
1383 props->fontsig.fsUsb[0] = GET_BE_DWORD(tt_os2->ulUnicodeRange1);
1384 props->fontsig.fsUsb[1] = GET_BE_DWORD(tt_os2->ulUnicodeRange2);
1385 props->fontsig.fsUsb[2] = GET_BE_DWORD(tt_os2->ulUnicodeRange3);
1386 props->fontsig.fsUsb[3] = GET_BE_DWORD(tt_os2->ulUnicodeRange4);
1388 if (GET_BE_WORD(tt_os2->version) == 0) {
1389 props->fontsig.fsCsb[0] = 0;
1390 props->fontsig.fsCsb[1] = 0;
1392 else {
1393 props->fontsig.fsCsb[0] = GET_BE_DWORD(tt_os2->ulCodePageRange1);
1394 props->fontsig.fsCsb[1] = GET_BE_DWORD(tt_os2->ulCodePageRange2);
1397 else if (tt_head) {
1398 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
1400 if (macStyle & TT_HEAD_MACSTYLE_CONDENSED)
1401 props->stretch = DWRITE_FONT_STRETCH_CONDENSED;
1402 else if (macStyle & TT_HEAD_MACSTYLE_EXTENDED)
1403 props->stretch = DWRITE_FONT_STRETCH_EXPANDED;
1405 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
1406 props->weight = DWRITE_FONT_WEIGHT_BOLD;
1408 if (macStyle & TT_HEAD_MACSTYLE_ITALIC) {
1409 props->style = DWRITE_FONT_STYLE_ITALIC;
1410 props->lf.lfItalic = 1;
1414 props->lf.lfWeight = props->weight;
1416 TRACE("stretch=%d, weight=%d, style %d\n", props->stretch, props->weight, props->style);
1418 if (tt_os2)
1419 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1420 if (tt_head)
1421 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, head_context);
1424 static UINT get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform, USHORT encoding)
1426 UINT codepage = 0;
1428 switch (platform) {
1429 case OPENTYPE_PLATFORM_UNICODE:
1430 break;
1431 case OPENTYPE_PLATFORM_MAC:
1432 switch (encoding)
1434 case TT_NAME_MAC_ENCODING_ROMAN:
1435 codepage = 10000;
1436 break;
1437 case TT_NAME_MAC_ENCODING_JAPANESE:
1438 codepage = 10001;
1439 break;
1440 case TT_NAME_MAC_ENCODING_TRAD_CHINESE:
1441 codepage = 10002;
1442 break;
1443 case TT_NAME_MAC_ENCODING_KOREAN:
1444 codepage = 10003;
1445 break;
1446 case TT_NAME_MAC_ENCODING_ARABIC:
1447 codepage = 10004;
1448 break;
1449 case TT_NAME_MAC_ENCODING_HEBREW:
1450 codepage = 10005;
1451 break;
1452 case TT_NAME_MAC_ENCODING_GREEK:
1453 codepage = 10006;
1454 break;
1455 case TT_NAME_MAC_ENCODING_RUSSIAN:
1456 codepage = 10007;
1457 break;
1458 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE:
1459 codepage = 10008;
1460 break;
1461 case TT_NAME_MAC_ENCODING_THAI:
1462 codepage = 10021;
1463 break;
1464 default:
1465 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1466 break;
1468 break;
1469 case OPENTYPE_PLATFORM_WIN:
1470 switch (encoding)
1472 case TT_NAME_WINDOWS_ENCODING_SYMBOL:
1473 case TT_NAME_WINDOWS_ENCODING_UCS2:
1474 break;
1475 case TT_NAME_WINDOWS_ENCODING_SJIS:
1476 codepage = 932;
1477 break;
1478 case TT_NAME_WINDOWS_ENCODING_PRC:
1479 codepage = 936;
1480 break;
1481 case TT_NAME_WINDOWS_ENCODING_BIG5:
1482 codepage = 950;
1483 break;
1484 case TT_NAME_WINDOWS_ENCODING_WANSUNG:
1485 codepage = 20949;
1486 break;
1487 case TT_NAME_WINDOWS_ENCODING_JOHAB:
1488 codepage = 1361;
1489 break;
1490 default:
1491 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1492 break;
1494 break;
1495 default:
1496 FIXME("unknown platform %d\n", platform);
1499 return codepage;
1502 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform, USHORT lang_id, WCHAR *locale, USHORT locale_len)
1504 static const WCHAR enusW[] = {'e','n','-','U','S',0};
1506 switch (platform) {
1507 case OPENTYPE_PLATFORM_MAC:
1509 const char *locale_name = NULL;
1511 if (lang_id > TT_NAME_MAC_LANGID_AZER_ROMAN)
1512 WARN("invalid mac lang id %d\n", lang_id);
1513 else if (!name_mac_langid_to_locale[lang_id][0])
1514 FIXME("failed to map mac lang id %d to locale name\n", lang_id);
1515 else
1516 locale_name = name_mac_langid_to_locale[lang_id];
1518 if (locale_name)
1519 MultiByteToWideChar(CP_ACP, 0, name_mac_langid_to_locale[lang_id], -1, locale, locale_len);
1520 else
1521 strcpyW(locale, enusW);
1522 break;
1524 case OPENTYPE_PLATFORM_WIN:
1525 if (!LCIDToLocaleName(MAKELCID(lang_id, SORT_DEFAULT), locale, locale_len, 0)) {
1526 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id, SORT_DEFAULT));
1527 strcpyW(locale, enusW);
1529 break;
1530 case OPENTYPE_PLATFORM_UNICODE:
1531 strcpyW(locale, enusW);
1532 break;
1533 default:
1534 FIXME("unknown platform %d\n", platform);
1538 static BOOL opentype_decode_namerecord(const TT_NAME_V0 *header, BYTE *storage_area, USHORT recid, IDWriteLocalizedStrings *strings)
1540 const TT_NameRecord *record = &header->nameRecord[recid];
1541 USHORT lang_id, length, offset, encoding, platform;
1542 BOOL ret = FALSE;
1544 platform = GET_BE_WORD(record->platformID);
1545 lang_id = GET_BE_WORD(record->languageID);
1546 length = GET_BE_WORD(record->length);
1547 offset = GET_BE_WORD(record->offset);
1548 encoding = GET_BE_WORD(record->encodingID);
1550 if (lang_id < 0x8000) {
1551 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
1552 WCHAR *name_string;
1553 UINT codepage;
1555 codepage = get_name_record_codepage(platform, encoding);
1556 get_name_record_locale(platform, lang_id, locale, sizeof(locale)/sizeof(WCHAR));
1558 if (codepage) {
1559 DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0);
1560 name_string = heap_alloc(sizeof(WCHAR) * (len+1));
1561 MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len);
1562 name_string[len] = 0;
1564 else {
1565 int i;
1567 length /= sizeof(WCHAR);
1568 name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length);
1569 for (i = 0; i < length; i++)
1570 name_string[i] = GET_BE_WORD(name_string[i]);
1573 TRACE("string %s for locale %s found\n", debugstr_w(name_string), debugstr_w(locale));
1574 add_localizedstring(strings, locale, name_string);
1575 heap_free(name_string);
1576 ret = TRUE;
1578 else
1579 FIXME("handle NAME format 1\n");
1581 return ret;
1584 static HRESULT opentype_get_font_strings_from_id(const void *table_data, enum OPENTYPE_STRING_ID id, IDWriteLocalizedStrings **strings)
1586 const TT_NAME_V0 *header;
1587 BYTE *storage_area = 0;
1588 USHORT count = 0;
1589 int i, candidate;
1590 WORD format;
1591 BOOL exists;
1592 HRESULT hr;
1594 if (!table_data)
1595 return E_FAIL;
1597 hr = create_localizedstrings(strings);
1598 if (FAILED(hr)) return hr;
1600 header = table_data;
1601 format = GET_BE_WORD(header->format);
1603 switch (format) {
1604 case 0:
1605 case 1:
1606 break;
1607 default:
1608 FIXME("unsupported NAME format %d\n", format);
1611 storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset);
1612 count = GET_BE_WORD(header->count);
1614 exists = FALSE;
1615 candidate = -1;
1616 for (i = 0; i < count; i++) {
1617 const TT_NameRecord *record = &header->nameRecord[i];
1618 USHORT platform;
1620 if (GET_BE_WORD(record->nameID) != id)
1621 continue;
1623 /* Right now only accept unicode and windows encoded fonts */
1624 platform = GET_BE_WORD(record->platformID);
1625 if (platform != OPENTYPE_PLATFORM_UNICODE &&
1626 platform != OPENTYPE_PLATFORM_MAC &&
1627 platform != OPENTYPE_PLATFORM_WIN)
1629 FIXME("platform %i not supported\n", platform);
1630 continue;
1633 /* Skip such entries for now, fonts tend to duplicate those strings as
1634 WIN platform entries. If font does not have WIN or MAC entry for this id, we will
1635 use this Unicode platform entry while assuming en-US locale. */
1636 if (platform == OPENTYPE_PLATFORM_UNICODE) {
1637 candidate = i;
1638 continue;
1641 if (!opentype_decode_namerecord(header, storage_area, i, *strings))
1642 continue;
1644 exists = TRUE;
1647 if (!exists) {
1648 if (candidate != -1)
1649 exists = opentype_decode_namerecord(header, storage_area, candidate, *strings);
1650 else {
1651 IDWriteLocalizedStrings_Release(*strings);
1652 *strings = NULL;
1656 return exists ? S_OK : E_FAIL;
1659 /* Provides a conversion from DWRITE to OpenType name ids, input id should be valid, it's not checked. */
1660 HRESULT opentype_get_font_info_strings(const void *table_data, DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings)
1662 return opentype_get_font_strings_from_id(table_data, dwriteid_to_opentypeid[id], strings);
1665 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
1666 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
1667 HRESULT opentype_get_font_familyname(struct file_stream_desc *stream_desc, IDWriteLocalizedStrings **names)
1669 const TT_OS2_V2 *tt_os2;
1670 void *os2_context, *name_context;
1671 const void *name_table;
1672 HRESULT hr;
1674 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1675 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1677 *names = NULL;
1679 /* if Preferred Family doesn't conform to WWS model try WWS name */
1680 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1681 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_FAMILY_NAME, names);
1682 else
1683 hr = E_FAIL;
1685 if (FAILED(hr))
1686 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_FAMILY_NAME, names);
1687 if (FAILED(hr))
1688 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, names);
1690 if (tt_os2)
1691 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1692 if (name_context)
1693 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1695 return hr;
1698 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
1699 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
1700 HRESULT opentype_get_font_facename(struct file_stream_desc *stream_desc, WCHAR *lfname, IDWriteLocalizedStrings **names)
1702 IDWriteLocalizedStrings *lfnames;
1703 void *os2_context, *name_context;
1704 const TT_OS2_V2 *tt_os2;
1705 const void *name_table;
1706 HRESULT hr;
1708 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1709 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1711 *names = NULL;
1713 /* if Preferred Family doesn't conform to WWS model try WWS name */
1714 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1715 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_SUBFAMILY_NAME, names);
1716 else
1717 hr = E_FAIL;
1719 if (FAILED(hr))
1720 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME, names);
1721 if (FAILED(hr))
1722 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_SUBFAMILY_NAME, names);
1724 /* User locale is preferred, with fallback to en-us. */
1725 *lfname = 0;
1726 if (SUCCEEDED(opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, &lfnames))) {
1727 static const WCHAR enusW[] = {'e','n','-','u','s',0};
1728 WCHAR localeW[LOCALE_NAME_MAX_LENGTH];
1729 UINT32 index;
1730 BOOL exists;
1732 exists = FALSE;
1733 if (GetSystemDefaultLocaleName(localeW, sizeof(localeW)/sizeof(WCHAR)))
1734 IDWriteLocalizedStrings_FindLocaleName(lfnames, localeW, &index, &exists);
1736 if (!exists)
1737 IDWriteLocalizedStrings_FindLocaleName(lfnames, enusW, &index, &exists);
1739 if (exists)
1740 IDWriteLocalizedStrings_GetString(lfnames, index, lfname, LF_FACESIZE);
1742 IDWriteLocalizedStrings_Release(lfnames);
1745 if (tt_os2)
1746 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1747 if (name_context)
1748 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1750 return hr;
1753 static inline const OT_Script *opentype_get_script(const OT_ScriptList *scriptlist, UINT32 scripttag)
1755 UINT16 j;
1757 for (j = 0; j < GET_BE_WORD(scriptlist->ScriptCount); j++) {
1758 const char *tag = scriptlist->ScriptRecord[j].ScriptTag;
1759 if (scripttag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1760 return (OT_Script*)((BYTE*)scriptlist + GET_BE_WORD(scriptlist->ScriptRecord[j].Script));
1763 return NULL;
1766 static inline const OT_LangSys *opentype_get_langsys(const OT_Script *script, UINT32 languagetag)
1768 UINT16 j;
1770 for (j = 0; j < GET_BE_WORD(script->LangSysCount); j++) {
1771 const char *tag = script->LangSysRecord[j].LangSysTag;
1772 if (languagetag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1773 return (OT_LangSys*)((BYTE*)script + GET_BE_WORD(script->LangSysRecord[j].LangSys));
1776 return NULL;
1779 static void opentype_add_font_features(const GPOS_GSUB_Header *header, const OT_LangSys *langsys,
1780 UINT32 max_tagcount, UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1782 const OT_FeatureList *features = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
1783 UINT16 j;
1785 for (j = 0; j < GET_BE_WORD(langsys->FeatureCount); j++) {
1786 const OT_FeatureRecord *feature = &features->FeatureRecord[langsys->FeatureIndex[j]];
1787 const char *tag = feature->FeatureTag;
1789 if (*count < max_tagcount)
1790 tags[*count] = DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]);
1792 (*count)++;
1796 HRESULT opentype_get_typographic_features(IDWriteFontFace *fontface, UINT32 scripttag, UINT32 languagetag, UINT32 max_tagcount,
1797 UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1799 UINT32 tables[2] = { MS_GSUB_TAG, MS_GPOS_TAG };
1800 HRESULT hr;
1801 UINT8 i;
1803 *count = 0;
1804 for (i = 0; i < sizeof(tables)/sizeof(tables[0]); i++) {
1805 const OT_ScriptList *scriptlist;
1806 const GPOS_GSUB_Header *header;
1807 const OT_Script *script;
1808 const void *ptr;
1809 void *context;
1810 UINT32 size;
1811 BOOL exists;
1813 exists = FALSE;
1814 hr = IDWriteFontFace_TryGetFontTable(fontface, tables[i], &ptr, &size, &context, &exists);
1815 if (FAILED(hr))
1816 return hr;
1818 if (!exists)
1819 continue;
1821 header = (const GPOS_GSUB_Header*)ptr;
1822 scriptlist = (const OT_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
1824 script = opentype_get_script(scriptlist, scripttag);
1825 if (script) {
1826 const OT_LangSys *langsys = opentype_get_langsys(script, languagetag);
1827 if (langsys)
1828 opentype_add_font_features(header, langsys, max_tagcount, count, tags);
1831 IDWriteFontFace_ReleaseFontTable(fontface, context);
1834 return *count > max_tagcount ? E_NOT_SUFFICIENT_BUFFER : S_OK;
1837 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
1839 WORD num_ratios, i, group_offset = 0;
1840 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
1841 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
1843 num_ratios = GET_BE_WORD(hdr->numRatios);
1845 for (i = 0; i < num_ratios; i++) {
1847 if (!ratios[i].bCharSet) continue;
1849 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
1850 ratios[i].yEndRatio == 0) ||
1851 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
1852 ratios[i].yEndRatio >= dev_y_ratio))
1854 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
1855 break;
1858 if (group_offset)
1859 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
1860 return NULL;
1863 BOOL opentype_get_vdmx_size(const void *data, INT emsize, UINT16 *ascent, UINT16 *descent)
1865 const struct VDMX_Header *hdr = (const struct VDMX_Header*)data;
1866 const struct VDMX_group *group;
1867 const struct VDMX_vTable *tables;
1868 WORD recs, i;
1870 if (!data)
1871 return FALSE;
1873 group = find_vdmx_group(hdr);
1874 if (!group)
1875 return FALSE;
1877 recs = GET_BE_WORD(group->recs);
1878 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
1880 tables = (const struct VDMX_vTable *)(group + 1);
1881 for (i = 0; i < recs; i++) {
1882 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
1883 if (ppem > emsize) {
1884 FIXME("interpolate %d\n", emsize);
1885 return FALSE;
1888 if (ppem == emsize) {
1889 *ascent = (SHORT)GET_BE_WORD(tables[i].yMax);
1890 *descent = -(SHORT)GET_BE_WORD(tables[i].yMin);
1891 return TRUE;
1894 return FALSE;
1897 WORD opentype_get_gasp_flags(const WORD *ptr, UINT32 size, INT emsize)
1899 WORD num_recs, version;
1900 WORD flags = 0;
1902 if (!ptr)
1903 return 0;
1905 version = GET_BE_WORD( *ptr++ );
1906 num_recs = GET_BE_WORD( *ptr++ );
1907 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
1908 ERR("unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
1909 goto done;
1912 while (num_recs--) {
1913 flags = GET_BE_WORD( *(ptr + 1) );
1914 if (emsize <= GET_BE_WORD( *ptr )) break;
1915 ptr += 2;
1918 done:
1919 return flags;
1922 UINT32 opentype_get_cpal_palettecount(const void *cpal)
1924 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1925 return header ? GET_BE_WORD(header->numPalette) : 0;
1928 UINT32 opentype_get_cpal_paletteentrycount(const void *cpal)
1930 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1931 return header ? GET_BE_WORD(header->numPaletteEntries) : 0;
1934 HRESULT opentype_get_cpal_entries(const void *cpal, UINT32 palette, UINT32 first_entry_index, UINT32 entry_count,
1935 DWRITE_COLOR_F *entries)
1937 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1938 const struct CPAL_ColorRecord *records;
1939 UINT32 palettecount, entrycount, i;
1941 if (!header) return DWRITE_E_NOCOLOR;
1943 palettecount = GET_BE_WORD(header->numPalette);
1944 if (palette >= palettecount)
1945 return DWRITE_E_NOCOLOR;
1947 entrycount = GET_BE_WORD(header->numPaletteEntries);
1948 if (first_entry_index + entry_count > entrycount)
1949 return E_INVALIDARG;
1951 records = (const struct CPAL_ColorRecord*)((BYTE*)cpal + GET_BE_DWORD(header->offsetFirstColorRecord));
1952 first_entry_index += GET_BE_WORD(header->colorRecordIndices[palette]);
1954 for (i = 0; i < entry_count; i++) {
1955 entries[i].u1.r = records[first_entry_index + i].red / 255.0f;
1956 entries[i].u2.g = records[first_entry_index + i].green / 255.0f;
1957 entries[i].u3.b = records[first_entry_index + i].blue / 255.0f;
1958 entries[i].u4.a = records[first_entry_index + i].alpha / 255.0f;
1961 return S_OK;
1964 static int colr_compare_gid(const void *g, const void *r)
1966 const struct COLR_BaseGlyphRecord *record = r;
1967 UINT16 glyph = *(UINT16*)g, GID = GET_BE_WORD(record->GID);
1968 int ret = 0;
1970 if (glyph > GID)
1971 ret = 1;
1972 else if (glyph < GID)
1973 ret = -1;
1975 return ret;
1978 HRESULT opentype_get_colr_glyph(const void *colr, UINT16 glyph, struct dwrite_colorglyph *ret)
1980 const struct COLR_BaseGlyphRecord *record;
1981 const struct COLR_Header *header = colr;
1982 const struct COLR_LayerRecord *layer;
1983 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
1984 DWORD baserecordoffset = GET_BE_DWORD(header->offsetBaseGlyphRecord);
1985 WORD numbaserecords = GET_BE_WORD(header->numBaseGlyphRecords);
1987 record = bsearch(&glyph, (BYTE*)colr + baserecordoffset, numbaserecords, sizeof(struct COLR_BaseGlyphRecord),
1988 colr_compare_gid);
1989 if (!record) {
1990 ret->layer = 0;
1991 ret->first_layer = 0;
1992 ret->num_layers = 0;
1993 ret->glyph = glyph;
1994 ret->palette_index = 0xffff;
1995 return S_FALSE;
1998 ret->layer = 0;
1999 ret->first_layer = GET_BE_WORD(record->firstLayerIndex);
2000 ret->num_layers = GET_BE_WORD(record->numLayers);
2002 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + ret->first_layer + ret->layer;
2003 ret->glyph = GET_BE_WORD(layer->GID);
2004 ret->palette_index = GET_BE_WORD(layer->paletteIndex);
2006 return S_OK;
2009 void opentype_colr_next_glyph(const void *colr, struct dwrite_colorglyph *glyph)
2011 const struct COLR_Header *header = colr;
2012 const struct COLR_LayerRecord *layer;
2013 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
2015 /* iterated all the way through */
2016 if (glyph->layer == glyph->num_layers)
2017 return;
2019 glyph->layer++;
2020 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + glyph->first_layer + glyph->layer;
2021 glyph->glyph = GET_BE_WORD(layer->GID);
2022 glyph->palette_index = GET_BE_WORD(layer->paletteIndex);
2025 BOOL opentype_has_vertical_variants(IDWriteFontFace4 *fontface)
2027 const OT_FeatureList *featurelist;
2028 const OT_LookupList *lookup_list;
2029 BOOL exists = FALSE, ret = FALSE;
2030 const GPOS_GSUB_Header *header;
2031 const void *data;
2032 void *context;
2033 UINT32 size;
2034 HRESULT hr;
2035 UINT16 i;
2037 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
2038 if (FAILED(hr) || !exists)
2039 return FALSE;
2041 header = data;
2042 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
2043 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
2045 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
2046 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
2047 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
2048 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
2049 const GSUB_SingleSubstFormat2 *subst2;
2050 const OT_LookupTable *lookup_table;
2051 UINT32 offset;
2053 if (lookup_count == 0)
2054 continue;
2056 for (i = 0; i < lookup_count; i++) {
2057 /* check if lookup is empty */
2058 index = GET_BE_WORD(feature->LookupListIndex[i]);
2059 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
2061 type = GET_BE_WORD(lookup_table->LookupType);
2062 if (type != OPENTYPE_GPOS_SINGLE_SUBST && type != OPENTYPE_GPOS_EXTENSION_SUBST)
2063 continue;
2065 count = GET_BE_WORD(lookup_table->SubTableCount);
2066 if (count == 0)
2067 continue;
2069 offset = GET_BE_WORD(lookup_table->SubTable[0]);
2070 if (type == OPENTYPE_GPOS_EXTENSION_SUBST) {
2071 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
2072 if (GET_BE_WORD(ext->SubstFormat) == 1)
2073 offset += GET_BE_DWORD(ext->ExtensionOffset);
2074 else
2075 FIXME("Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
2078 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
2079 index = GET_BE_WORD(subst2->SubstFormat);
2080 if (index == 1)
2081 FIXME("Validate Single Substitution Format 1\n");
2082 else if (index == 2) {
2083 /* SimSun-ExtB has 0 glyph count for this substitution */
2084 if (GET_BE_WORD(subst2->GlyphCount) > 0) {
2085 ret = TRUE;
2086 break;
2089 else
2090 WARN("Unknown Single Substitution Format, %u\n", index);
2095 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2097 return ret;
2100 static BOOL opentype_has_font_table(IDWriteFontFace4 *fontface, UINT32 tag)
2102 BOOL exists = FALSE;
2103 const void *data;
2104 void *context;
2105 UINT32 size;
2106 HRESULT hr;
2108 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, &data, &size, &context, &exists);
2109 if (FAILED(hr))
2110 return FALSE;
2112 if (exists)
2113 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2115 return exists;
2118 static DWORD opentype_get_sbix_formats(IDWriteFontFace4 *fontface)
2120 UINT32 size, s, num_strikes;
2121 const sbix_header *header;
2122 UINT16 g, num_glyphs;
2123 BOOL exists = FALSE;
2124 const maxp *maxp;
2125 const void *data;
2126 DWORD ret = 0;
2127 void *context;
2128 HRESULT hr;
2130 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_MAXP_TAG, &data, &size, &context, &exists);
2131 if (FAILED(hr) || !exists)
2132 return 0;
2134 maxp = data;
2135 num_glyphs = GET_BE_WORD(maxp->numGlyphs);
2137 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2139 if (FAILED(IDWriteFontFace4_TryGetFontTable(fontface, MS_SBIX_TAG, &data, &size, &context, &exists))) {
2140 WARN("Failed to get 'sbix' table, %#x\n", hr);
2141 return 0;
2144 header = data;
2145 num_strikes = GET_BE_DWORD(header->numStrikes);
2147 for (s = 0; s < num_strikes; s++) {
2148 sbix_strike *strike = (sbix_strike *)((BYTE *)header + GET_BE_DWORD(header->strikeOffset[s]));
2150 for (g = 0; g < num_glyphs; g++) {
2151 DWORD offset = GET_BE_DWORD(strike->glyphDataOffsets[g]);
2152 DWORD offset_next = GET_BE_DWORD(strike->glyphDataOffsets[g + 1]);
2153 sbix_glyph_data *glyph_data;
2154 DWORD format;
2156 if (offset == offset_next)
2157 continue;
2159 glyph_data = (sbix_glyph_data *)((BYTE *)strike + offset);
2160 switch (format = glyph_data->graphicType)
2162 case MS_PNG__TAG:
2163 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
2164 break;
2165 case MS_JPG__TAG:
2166 ret |= DWRITE_GLYPH_IMAGE_FORMATS_JPEG;
2167 break;
2168 case MS_TIFF_TAG:
2169 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TIFF;
2170 break;
2171 default:
2172 format = GET_BE_DWORD(format);
2173 FIXME("unexpected bitmap format %s\n", debugstr_an((char *)&format, 4));
2178 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2180 return ret;
2183 static UINT32 opentype_get_cblc_formats(IDWriteFontFace4 *fontface)
2185 CBLCBitmapSizeTable *sizes;
2186 UINT32 num_sizes, size, s;
2187 BOOL exists = FALSE;
2188 CBLCHeader *header;
2189 UINT32 ret = 0;
2190 void *context;
2191 HRESULT hr;
2193 if (FAILED(hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_CBLC_TAG, (const void **)&header, &size,
2194 &context, &exists)))
2195 return 0;
2197 if (!exists)
2198 return 0;
2200 num_sizes = GET_BE_DWORD(header->numSizes);
2201 sizes = (CBLCBitmapSizeTable *)(header + 1);
2203 for (s = 0; s < num_sizes; s++) {
2204 BYTE bpp = sizes->bitDepth;
2206 if (bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8)
2207 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
2208 else if (bpp == 32)
2209 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8;
2212 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2214 return ret;
2217 UINT32 opentype_get_glyph_image_formats(IDWriteFontFace4 *fontface)
2219 UINT32 ret = DWRITE_GLYPH_IMAGE_FORMATS_NONE;
2221 if (opentype_has_font_table(fontface, MS_GLYF_TAG))
2222 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
2224 if (opentype_has_font_table(fontface, MS_CFF__TAG) ||
2225 opentype_has_font_table(fontface, MS_CFF2_TAG))
2226 ret |= DWRITE_GLYPH_IMAGE_FORMATS_CFF;
2228 if (opentype_has_font_table(fontface, MS_COLR_TAG))
2229 ret |= DWRITE_GLYPH_IMAGE_FORMATS_COLR;
2231 if (opentype_has_font_table(fontface, MS_SVG__TAG))
2232 ret |= DWRITE_GLYPH_IMAGE_FORMATS_SVG;
2234 if (opentype_has_font_table(fontface, MS_SBIX_TAG))
2235 ret |= opentype_get_sbix_formats(fontface);
2237 if (opentype_has_font_table(fontface, MS_CBLC_TAG))
2238 ret |= opentype_get_cblc_formats(fontface);
2240 return ret;
2243 DWRITE_CONTAINER_TYPE opentype_analyze_container_type(void const *data, UINT32 data_size)
2245 DWORD signature;
2247 if (data_size < sizeof(DWORD))
2248 return DWRITE_CONTAINER_TYPE_UNKNOWN;
2250 /* Both WOFF and WOFF2 start with 4 bytes signature. */
2251 signature = *(DWORD *)data;
2253 switch (signature)
2255 case MS_WOFF_TAG:
2256 return DWRITE_CONTAINER_TYPE_WOFF;
2257 case MS_WOF2_TAG:
2258 return DWRITE_CONTAINER_TYPE_WOFF2;
2259 default:
2260 return DWRITE_CONTAINER_TYPE_UNKNOWN;