kernel32: Do not allow to combine NORM_IGNORENONSPACE and/or NORM_IGNORESYMBOLS with...
[wine.git] / dlls / dwrite / opentype.c
blobb38b5a2b89e566a8369121cc5a31b2bf96b4a50d
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
23 #include "dwrite_private.h"
24 #include "winternl.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
28 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
29 #define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
30 #define MS_OTTO_TAG DWRITE_MAKE_OPENTYPE_TAG('O','T','T','O')
31 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
32 #define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
33 #define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f')
34 #define MS_GPOS_TAG DWRITE_MAKE_OPENTYPE_TAG('G','P','O','S')
35 #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B')
36 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
38 #ifdef WORDS_BIGENDIAN
39 #define GET_BE_WORD(x) (x)
40 #define GET_BE_DWORD(x) (x)
41 #else
42 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
43 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
44 #endif
46 typedef struct {
47 CHAR TTCTag[4];
48 DWORD Version;
49 DWORD numFonts;
50 DWORD OffsetTable[1];
51 } TTC_Header_V1;
53 typedef struct {
54 DWORD version;
55 WORD numTables;
56 WORD searchRange;
57 WORD entrySelector;
58 WORD rangeShift;
59 } TTC_SFNT_V1;
61 typedef struct {
62 CHAR tag[4];
63 DWORD checkSum;
64 DWORD offset;
65 DWORD length;
66 } TT_TableRecord;
68 typedef struct {
69 WORD platformID;
70 WORD encodingID;
71 DWORD offset;
72 } CMAP_EncodingRecord;
74 typedef struct {
75 WORD version;
76 WORD numTables;
77 CMAP_EncodingRecord tables[1];
78 } CMAP_Header;
80 typedef struct {
81 DWORD startCharCode;
82 DWORD endCharCode;
83 DWORD startGlyphID;
84 } CMAP_SegmentedCoverage_group;
86 typedef struct {
87 WORD format;
88 WORD reserved;
89 DWORD length;
90 DWORD language;
91 DWORD nGroups;
92 CMAP_SegmentedCoverage_group groups[1];
93 } CMAP_SegmentedCoverage;
95 typedef struct {
96 WORD format;
97 WORD length;
98 WORD language;
99 WORD segCountX2;
100 WORD searchRange;
101 WORD entrySelector;
102 WORD rangeShift;
103 WORD endCode[1];
104 } CMAP_SegmentMapping_0;
106 enum OPENTYPE_CMAP_TABLE_FORMAT
108 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING = 4,
109 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE = 12
112 /* PANOSE is 10 bytes in size, need to pack the structure properly */
113 #include "pshpack2.h"
114 typedef struct
116 ULONG version;
117 ULONG revision;
118 ULONG checksumadj;
119 ULONG magic;
120 USHORT flags;
121 USHORT unitsPerEm;
122 ULONGLONG created;
123 ULONGLONG modified;
124 SHORT xMin;
125 SHORT yMin;
126 SHORT xMax;
127 SHORT yMax;
128 USHORT macStyle;
129 USHORT lowestRecPPEM;
130 SHORT direction_hint;
131 SHORT index_format;
132 SHORT glyphdata_format;
133 } TT_HEAD;
135 enum TT_HEAD_MACSTYLE
137 TT_HEAD_MACSTYLE_BOLD = 1 << 0,
138 TT_HEAD_MACSTYLE_ITALIC = 1 << 1,
139 TT_HEAD_MACSTYLE_UNDERLINE = 1 << 2,
140 TT_HEAD_MACSTYLE_OUTLINE = 1 << 3,
141 TT_HEAD_MACSTYLE_SHADOW = 1 << 4,
142 TT_HEAD_MACSTYLE_CONDENSED = 1 << 5,
143 TT_HEAD_MACSTYLE_EXTENDED = 1 << 6,
146 typedef struct
148 ULONG Version;
149 ULONG italicAngle;
150 SHORT underlinePosition;
151 SHORT underlineThickness;
152 ULONG fixed_pitch;
153 ULONG minmemType42;
154 ULONG maxmemType42;
155 ULONG minmemType1;
156 ULONG maxmemType1;
157 } TT_POST;
159 typedef struct
161 USHORT version;
162 SHORT xAvgCharWidth;
163 USHORT usWeightClass;
164 USHORT usWidthClass;
165 SHORT fsType;
166 SHORT ySubscriptXSize;
167 SHORT ySubscriptYSize;
168 SHORT ySubscriptXOffset;
169 SHORT ySubscriptYOffset;
170 SHORT ySuperscriptXSize;
171 SHORT ySuperscriptYSize;
172 SHORT ySuperscriptXOffset;
173 SHORT ySuperscriptYOffset;
174 SHORT yStrikeoutSize;
175 SHORT yStrikeoutPosition;
176 SHORT sFamilyClass;
177 PANOSE panose;
178 ULONG ulUnicodeRange1;
179 ULONG ulUnicodeRange2;
180 ULONG ulUnicodeRange3;
181 ULONG ulUnicodeRange4;
182 CHAR achVendID[4];
183 USHORT fsSelection;
184 USHORT usFirstCharIndex;
185 USHORT usLastCharIndex;
186 /* According to the Apple spec, original version didn't have the below fields,
187 * version numbers were taken from the OpenType spec.
189 /* version 0 (TrueType 1.5) */
190 USHORT sTypoAscender;
191 USHORT sTypoDescender;
192 USHORT sTypoLineGap;
193 USHORT usWinAscent;
194 USHORT usWinDescent;
195 /* version 1 (TrueType 1.66) */
196 ULONG ulCodePageRange1;
197 ULONG ulCodePageRange2;
198 /* version 2 (OpenType 1.2) */
199 SHORT sxHeight;
200 SHORT sCapHeight;
201 USHORT usDefaultChar;
202 USHORT usBreakChar;
203 USHORT usMaxContext;
204 } TT_OS2_V2;
206 typedef struct {
207 ULONG version;
208 SHORT ascender;
209 SHORT descender;
210 SHORT linegap;
211 USHORT advanceWidthMax;
212 SHORT minLeftSideBearing;
213 SHORT minRightSideBearing;
214 SHORT xMaxExtent;
215 SHORT caretSlopeRise;
216 SHORT caretSlopeRun;
217 SHORT caretOffset;
218 SHORT reserved[4];
219 SHORT metricDataFormat;
220 USHORT numberOfHMetrics;
221 } TT_HHEA;
223 #include "poppack.h"
225 enum OS2_FSSELECTION {
226 OS2_FSSELECTION_ITALIC = 1 << 0,
227 OS2_FSSELECTION_UNDERSCORE = 1 << 1,
228 OS2_FSSELECTION_NEGATIVE = 1 << 2,
229 OS2_FSSELECTION_OUTLINED = 1 << 3,
230 OS2_FSSELECTION_STRIKEOUT = 1 << 4,
231 OS2_FSSELECTION_BOLD = 1 << 5,
232 OS2_FSSELECTION_REGULAR = 1 << 6,
233 OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7,
234 OS2_FSSELECTION_WWS = 1 << 8,
235 OS2_FSSELECTION_OBLIQUE = 1 << 9
238 typedef struct {
239 WORD platformID;
240 WORD encodingID;
241 WORD languageID;
242 WORD nameID;
243 WORD length;
244 WORD offset;
245 } TT_NameRecord;
247 typedef struct {
248 WORD format;
249 WORD count;
250 WORD stringOffset;
251 TT_NameRecord nameRecord[1];
252 } TT_NAME_V0;
254 struct VDMX_Header
256 WORD version;
257 WORD numRecs;
258 WORD numRatios;
261 struct VDMX_Ratio
263 BYTE bCharSet;
264 BYTE xRatio;
265 BYTE yStartRatio;
266 BYTE yEndRatio;
269 struct VDMX_group
271 WORD recs;
272 BYTE startsz;
273 BYTE endsz;
276 struct VDMX_vTable
278 WORD yPelHeight;
279 SHORT yMax;
280 SHORT yMin;
283 typedef struct {
284 CHAR FeatureTag[4];
285 WORD Feature;
286 } OT_FeatureRecord;
288 typedef struct {
289 WORD FeatureCount;
290 OT_FeatureRecord FeatureRecord[1];
291 } OT_FeatureList;
293 typedef struct {
294 WORD LookupOrder; /* Reserved */
295 WORD ReqFeatureIndex;
296 WORD FeatureCount;
297 WORD FeatureIndex[1];
298 } OT_LangSys;
300 typedef struct {
301 CHAR LangSysTag[4];
302 WORD LangSys;
303 } OT_LangSysRecord;
305 typedef struct {
306 WORD DefaultLangSys;
307 WORD LangSysCount;
308 OT_LangSysRecord LangSysRecord[1];
309 } OT_Script;
311 typedef struct {
312 CHAR ScriptTag[4];
313 WORD Script;
314 } OT_ScriptRecord;
316 typedef struct {
317 WORD ScriptCount;
318 OT_ScriptRecord ScriptRecord[1];
319 } OT_ScriptList;
321 typedef struct {
322 DWORD version;
323 WORD ScriptList;
324 WORD FeatureList;
325 WORD LookupList;
326 } GPOS_GSUB_Header;
328 enum OPENTYPE_PLATFORM_ID
330 OPENTYPE_PLATFORM_UNICODE = 0,
331 OPENTYPE_PLATFORM_MAC,
332 OPENTYPE_PLATFORM_ISO,
333 OPENTYPE_PLATFORM_WIN,
334 OPENTYPE_PLATFORM_CUSTOM
337 typedef struct {
338 WORD FeatureParams;
339 WORD LookupCount;
340 WORD LookupListIndex[1];
341 } OT_Feature;
343 typedef struct {
344 WORD LookupCount;
345 WORD Lookup[1];
346 } OT_LookupList;
348 typedef struct {
349 WORD LookupType;
350 WORD LookupFlag;
351 WORD SubTableCount;
352 WORD SubTable[1];
353 } OT_LookupTable;
355 typedef struct {
356 WORD SubstFormat;
357 WORD Coverage;
358 WORD DeltaGlyphID;
359 } GSUB_SingleSubstFormat1;
361 typedef struct {
362 WORD SubstFormat;
363 WORD Coverage;
364 WORD GlyphCount;
365 WORD Substitute[1];
366 } GSUB_SingleSubstFormat2;
368 typedef struct {
369 WORD SubstFormat;
370 WORD ExtensionLookupType;
371 DWORD ExtensionOffset;
372 } GSUB_ExtensionPosFormat1;
374 enum OPENTYPE_GPOS_LOOKUPS
376 OPENTYPE_GPOS_SINGLE_SUBST = 1,
377 OPENTYPE_GPOS_EXTENSION_SUBST = 7
380 enum TT_NAME_WINDOWS_ENCODING_ID
382 TT_NAME_WINDOWS_ENCODING_SYMBOL = 0,
383 TT_NAME_WINDOWS_ENCODING_UCS2,
384 TT_NAME_WINDOWS_ENCODING_SJIS,
385 TT_NAME_WINDOWS_ENCODING_PRC,
386 TT_NAME_WINDOWS_ENCODING_BIG5,
387 TT_NAME_WINDOWS_ENCODING_WANSUNG,
388 TT_NAME_WINDOWS_ENCODING_JOHAB,
389 TT_NAME_WINDOWS_ENCODING_RESERVED1,
390 TT_NAME_WINDOWS_ENCODING_RESERVED2,
391 TT_NAME_WINDOWS_ENCODING_RESERVED3,
392 TT_NAME_WINDOWS_ENCODING_UCS4
395 enum TT_NAME_MAC_ENCODING_ID
397 TT_NAME_MAC_ENCODING_ROMAN = 0,
398 TT_NAME_MAC_ENCODING_JAPANESE,
399 TT_NAME_MAC_ENCODING_TRAD_CHINESE,
400 TT_NAME_MAC_ENCODING_KOREAN,
401 TT_NAME_MAC_ENCODING_ARABIC,
402 TT_NAME_MAC_ENCODING_HEBREW,
403 TT_NAME_MAC_ENCODING_GREEK,
404 TT_NAME_MAC_ENCODING_RUSSIAN,
405 TT_NAME_MAC_ENCODING_RSYMBOL,
406 TT_NAME_MAC_ENCODING_DEVANAGARI,
407 TT_NAME_MAC_ENCODING_GURMUKHI,
408 TT_NAME_MAC_ENCODING_GUJARATI,
409 TT_NAME_MAC_ENCODING_ORIYA,
410 TT_NAME_MAC_ENCODING_BENGALI,
411 TT_NAME_MAC_ENCODING_TAMIL,
412 TT_NAME_MAC_ENCODING_TELUGU,
413 TT_NAME_MAC_ENCODING_KANNADA,
414 TT_NAME_MAC_ENCODING_MALAYALAM,
415 TT_NAME_MAC_ENCODING_SINHALESE,
416 TT_NAME_MAC_ENCODING_BURMESE,
417 TT_NAME_MAC_ENCODING_KHMER,
418 TT_NAME_MAC_ENCODING_THAI,
419 TT_NAME_MAC_ENCODING_LAOTIAN,
420 TT_NAME_MAC_ENCODING_GEORGIAN,
421 TT_NAME_MAC_ENCODING_ARMENIAN,
422 TT_NAME_MAC_ENCODING_SIMPL_CHINESE,
423 TT_NAME_MAC_ENCODING_TIBETAN,
424 TT_NAME_MAC_ENCODING_MONGOLIAN,
425 TT_NAME_MAC_ENCODING_GEEZ,
426 TT_NAME_MAC_ENCODING_SLAVIC,
427 TT_NAME_MAC_ENCODING_VIETNAMESE,
428 TT_NAME_MAC_ENCODING_SINDHI,
429 TT_NAME_MAC_ENCODING_UNINTERPRETED
432 enum TT_NAME_MAC_LANGUAGE_ID
434 TT_NAME_MAC_LANGID_ENGLISH = 0,
435 TT_NAME_MAC_LANGID_FRENCH,
436 TT_NAME_MAC_LANGID_GERMAN,
437 TT_NAME_MAC_LANGID_ITALIAN,
438 TT_NAME_MAC_LANGID_DUTCH,
439 TT_NAME_MAC_LANGID_SWEDISH,
440 TT_NAME_MAC_LANGID_SPANISH,
441 TT_NAME_MAC_LANGID_DANISH,
442 TT_NAME_MAC_LANGID_PORTUGUESE,
443 TT_NAME_MAC_LANGID_NORWEGIAN,
444 TT_NAME_MAC_LANGID_HEBREW,
445 TT_NAME_MAC_LANGID_JAPANESE,
446 TT_NAME_MAC_LANGID_ARABIC,
447 TT_NAME_MAC_LANGID_FINNISH,
448 TT_NAME_MAC_LANGID_GREEK,
449 TT_NAME_MAC_LANGID_ICELANDIC,
450 TT_NAME_MAC_LANGID_MALTESE,
451 TT_NAME_MAC_LANGID_TURKISH,
452 TT_NAME_MAC_LANGID_CROATIAN,
453 TT_NAME_MAC_LANGID_TRAD_CHINESE,
454 TT_NAME_MAC_LANGID_URDU,
455 TT_NAME_MAC_LANGID_HINDI,
456 TT_NAME_MAC_LANGID_THAI,
457 TT_NAME_MAC_LANGID_KOREAN,
458 TT_NAME_MAC_LANGID_LITHUANIAN,
459 TT_NAME_MAC_LANGID_POLISH,
460 TT_NAME_MAC_LANGID_HUNGARIAN,
461 TT_NAME_MAC_LANGID_ESTONIAN,
462 TT_NAME_MAC_LANGID_LATVIAN,
463 TT_NAME_MAC_LANGID_SAMI,
464 TT_NAME_MAC_LANGID_FAROESE,
465 TT_NAME_MAC_LANGID_FARSI,
466 TT_NAME_MAC_LANGID_RUSSIAN,
467 TT_NAME_MAC_LANGID_SIMPL_CHINESE,
468 TT_NAME_MAC_LANGID_FLEMISH,
469 TT_NAME_MAC_LANGID_GAELIC,
470 TT_NAME_MAC_LANGID_ALBANIAN,
471 TT_NAME_MAC_LANGID_ROMANIAN,
472 TT_NAME_MAC_LANGID_CZECH,
473 TT_NAME_MAC_LANGID_SLOVAK,
474 TT_NAME_MAC_LANGID_SLOVENIAN,
475 TT_NAME_MAC_LANGID_YIDDISH,
476 TT_NAME_MAC_LANGID_SERBIAN,
477 TT_NAME_MAC_LANGID_MACEDONIAN,
478 TT_NAME_MAC_LANGID_BULGARIAN,
479 TT_NAME_MAC_LANGID_UKRAINIAN,
480 TT_NAME_MAC_LANGID_BYELORUSSIAN,
481 TT_NAME_MAC_LANGID_UZBEK,
482 TT_NAME_MAC_LANGID_KAZAKH,
483 TT_NAME_MAC_LANGID_AZERB_CYR,
484 TT_NAME_MAC_LANGID_AZERB_ARABIC,
485 TT_NAME_MAC_LANGID_ARMENIAN,
486 TT_NAME_MAC_LANGID_GEORGIAN,
487 TT_NAME_MAC_LANGID_MOLDAVIAN,
488 TT_NAME_MAC_LANGID_KIRGHIZ,
489 TT_NAME_MAC_LANGID_TAJIKI,
490 TT_NAME_MAC_LANGID_TURKMEN,
491 TT_NAME_MAC_LANGID_MONGOLIAN,
492 TT_NAME_MAC_LANGID_MONGOLIAN_CYR,
493 TT_NAME_MAC_LANGID_PASHTO,
494 TT_NAME_MAC_LANGID_KURDISH,
495 TT_NAME_MAC_LANGID_KASHMIRI,
496 TT_NAME_MAC_LANGID_SINDHI,
497 TT_NAME_MAC_LANGID_TIBETAN,
498 TT_NAME_MAC_LANGID_NEPALI,
499 TT_NAME_MAC_LANGID_SANSKRIT,
500 TT_NAME_MAC_LANGID_MARATHI,
501 TT_NAME_MAC_LANGID_BENGALI,
502 TT_NAME_MAC_LANGID_ASSAMESE,
503 TT_NAME_MAC_LANGID_GUJARATI,
504 TT_NAME_MAC_LANGID_PUNJABI,
505 TT_NAME_MAC_LANGID_ORIYA,
506 TT_NAME_MAC_LANGID_MALAYALAM,
507 TT_NAME_MAC_LANGID_KANNADA,
508 TT_NAME_MAC_LANGID_TAMIL,
509 TT_NAME_MAC_LANGID_TELUGU,
510 TT_NAME_MAC_LANGID_SINHALESE,
511 TT_NAME_MAC_LANGID_BURMESE,
512 TT_NAME_MAC_LANGID_KHMER,
513 TT_NAME_MAC_LANGID_LAO,
514 TT_NAME_MAC_LANGID_VIETNAMESE,
515 TT_NAME_MAC_LANGID_INDONESIAN,
516 TT_NAME_MAC_LANGID_TAGALOG,
517 TT_NAME_MAC_LANGID_MALAY_ROMAN,
518 TT_NAME_MAC_LANGID_MALAY_ARABIC,
519 TT_NAME_MAC_LANGID_AMHARIC,
520 TT_NAME_MAC_LANGID_TIGRINYA,
521 TT_NAME_MAC_LANGID_GALLA,
522 TT_NAME_MAC_LANGID_SOMALI,
523 TT_NAME_MAC_LANGID_SWAHILI,
524 TT_NAME_MAC_LANGID_KINYARWANDA,
525 TT_NAME_MAC_LANGID_RUNDI,
526 TT_NAME_MAC_LANGID_NYANJA,
527 TT_NAME_MAC_LANGID_MALAGASY,
528 TT_NAME_MAC_LANGID_ESPERANTO,
529 TT_NAME_MAC_LANGID_WELSH = 128,
530 TT_NAME_MAC_LANGID_BASQUE,
531 TT_NAME_MAC_LANGID_CATALAN,
532 TT_NAME_MAC_LANGID_LATIN,
533 TT_NAME_MAC_LANGID_QUECHUA,
534 TT_NAME_MAC_LANGID_GUARANI,
535 TT_NAME_MAC_LANGID_AYMARA,
536 TT_NAME_MAC_LANGID_TATAR,
537 TT_NAME_MAC_LANGID_UIGHUR,
538 TT_NAME_MAC_LANGID_DZONGKHA,
539 TT_NAME_MAC_LANGID_JAVANESE,
540 TT_NAME_MAC_LANGID_SUNDANESE,
541 TT_NAME_MAC_LANGID_GALICIAN,
542 TT_NAME_MAC_LANGID_AFRIKAANS,
543 TT_NAME_MAC_LANGID_BRETON,
544 TT_NAME_MAC_LANGID_INUKTITUT,
545 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC,
546 TT_NAME_MAC_LANGID_MANX_GAELIC,
547 TT_NAME_MAC_LANGID_IRISH_GAELIC,
548 TT_NAME_MAC_LANGID_TONGAN,
549 TT_NAME_MAC_LANGID_GREEK_POLYTONIC,
550 TT_NAME_MAC_LANGID_GREENLANDIC,
551 TT_NAME_MAC_LANGID_AZER_ROMAN
554 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
555 static const char name_mac_langid_to_locale[][10] = {
556 "en-US",
557 "fr-FR",
558 "de-DE",
559 "it-IT",
560 "nl-NL",
561 "sv-SE",
562 "es-ES",
563 "da-DA",
564 "pt-PT",
565 "no-NO",
566 "he-IL",
567 "ja-JP",
568 "ar-AR",
569 "fi-FI",
570 "el-GR",
571 "is-IS",
572 "mt-MT",
573 "tr-TR",
574 "hr-HR",
575 "zh-HK",
576 "ur-PK",
577 "hi-IN",
578 "th-TH",
579 "ko-KR",
580 "lt-LT",
581 "pl-PL",
582 "hu-HU",
583 "et-EE",
584 "lv-LV",
585 "se-NO",
586 "fo-FO",
587 "fa-IR",
588 "ru-RU",
589 "zh-CN",
590 "nl-BE",
591 "gd-GB",
592 "sq-AL",
593 "ro-RO",
594 "cs-CZ",
595 "sk-SK",
596 "sl-SI",
598 "sr-Latn",
599 "mk-MK",
600 "bg-BG",
601 "uk-UA",
602 "be-BY",
603 "uz-Latn",
604 "kk-KZ",
605 "az-Cyrl-AZ",
606 "az-AZ",
607 "hy-AM",
608 "ka-GE",
611 "tg-TJ",
612 "tk-TM",
613 "mn-Mong",
614 "mn-MN",
615 "ps-AF",
616 "ku-Arab",
618 "sd-Arab",
619 "bo-CN",
620 "ne-NP",
621 "sa-IN",
622 "mr-IN",
623 "bn-IN",
624 "as-IN",
625 "gu-IN",
626 "pa-Arab",
627 "or-IN",
628 "ml-IN",
629 "kn-IN",
630 "ta-LK",
631 "te-IN",
632 "si-LK",
634 "km-KH",
635 "lo-LA",
636 "vi-VN",
637 "id-ID",
639 "ms-MY",
640 "ms-Arab",
641 "am-ET",
642 "ti-ET",
645 "sw-KE",
646 "rw-RW",
684 "cy-GB",
685 "eu-ES",
686 "ca-ES",
691 "tt-RU",
692 "ug-CN",
696 "gl-ES",
697 "af-ZA",
698 "br-FR",
699 "iu-Latn-CA",
700 "gd-GB",
702 "ga-IE",
705 "kl-GL",
706 "az-Latn"
709 enum OPENTYPE_STRING_ID
711 OPENTYPE_STRING_COPYRIGHT_NOTICE = 0,
712 OPENTYPE_STRING_FAMILY_NAME,
713 OPENTYPE_STRING_SUBFAMILY_NAME,
714 OPENTYPE_STRING_UNIQUE_IDENTIFIER,
715 OPENTYPE_STRING_FULL_FONTNAME,
716 OPENTYPE_STRING_VERSION_STRING,
717 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
718 OPENTYPE_STRING_TRADEMARK,
719 OPENTYPE_STRING_MANUFACTURER,
720 OPENTYPE_STRING_DESIGNER,
721 OPENTYPE_STRING_DESCRIPTION,
722 OPENTYPE_STRING_VENDOR_URL,
723 OPENTYPE_STRING_DESIGNER_URL,
724 OPENTYPE_STRING_LICENSE_DESCRIPTION,
725 OPENTYPE_STRING_LICENSE_INFO_URL,
726 OPENTYPE_STRING_RESERVED_ID15,
727 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
728 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
729 OPENTYPE_STRING_COMPATIBLE_FULLNAME,
730 OPENTYPE_STRING_SAMPLE_TEXT,
731 OPENTYPE_STRING_POSTSCRIPT_CID_NAME,
732 OPENTYPE_STRING_WWS_FAMILY_NAME,
733 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
736 static const UINT16 dwriteid_to_opentypeid[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1] =
738 (UINT16)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
739 OPENTYPE_STRING_COPYRIGHT_NOTICE,
740 OPENTYPE_STRING_VERSION_STRING,
741 OPENTYPE_STRING_TRADEMARK,
742 OPENTYPE_STRING_MANUFACTURER,
743 OPENTYPE_STRING_DESIGNER,
744 OPENTYPE_STRING_DESIGNER_URL,
745 OPENTYPE_STRING_DESCRIPTION,
746 OPENTYPE_STRING_VENDOR_URL,
747 OPENTYPE_STRING_LICENSE_DESCRIPTION,
748 OPENTYPE_STRING_LICENSE_INFO_URL,
749 OPENTYPE_STRING_FAMILY_NAME,
750 OPENTYPE_STRING_SUBFAMILY_NAME,
751 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
752 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
753 OPENTYPE_STRING_SAMPLE_TEXT,
754 OPENTYPE_STRING_FULL_FONTNAME,
755 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
756 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
759 /* CPAL table */
760 struct CPAL_Header_0
762 USHORT version;
763 USHORT numPaletteEntries;
764 USHORT numPalette;
765 USHORT numColorRecords;
766 ULONG offsetFirstColorRecord;
767 USHORT colorRecordIndices[1];
770 /* for version == 1, this comes after full CPAL_Header_0 */
771 struct CPAL_SubHeader_1
773 ULONG offsetPaletteTypeArray;
774 ULONG offsetPaletteLabelArray;
775 ULONG offsetPaletteEntryLabelArray;
778 struct CPAL_ColorRecord
780 BYTE blue;
781 BYTE green;
782 BYTE red;
783 BYTE alpha;
786 /* COLR table */
787 struct COLR_Header
789 USHORT version;
790 USHORT numBaseGlyphRecords;
791 ULONG offsetBaseGlyphRecord;
792 ULONG offsetLayerRecord;
793 USHORT numLayerRecords;
796 struct COLR_BaseGlyphRecord
798 USHORT GID;
799 USHORT firstLayerIndex;
800 USHORT numLayers;
803 struct COLR_LayerRecord
805 USHORT GID;
806 USHORT paletteIndex;
809 BOOL is_face_type_supported(DWRITE_FONT_FACE_TYPE type)
811 return (type == DWRITE_FONT_FACE_TYPE_CFF) ||
812 (type == DWRITE_FONT_FACE_TYPE_TRUETYPE) ||
813 (type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) ||
814 (type == DWRITE_FONT_FACE_TYPE_RAW_CFF);
817 typedef HRESULT (*dwrite_fontfile_analyzer)(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
818 DWRITE_FONT_FACE_TYPE *face_type);
820 static HRESULT opentype_ttc_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
821 DWRITE_FONT_FACE_TYPE *face_type)
823 static const DWORD ttctag = MS_TTCF_TAG;
824 const TTC_Header_V1 *header;
825 void *context;
826 HRESULT hr;
828 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(header), &context);
829 if (FAILED(hr))
830 return hr;
832 if (!memcmp(header->TTCTag, &ttctag, sizeof(ttctag))) {
833 *font_count = GET_BE_DWORD(header->numFonts);
834 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION;
835 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION;
838 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
840 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
843 static HRESULT opentype_ttf_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
844 DWRITE_FONT_FACE_TYPE *face_type)
846 const DWORD *header;
847 void *context;
848 HRESULT hr;
850 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(*header), &context);
851 if (FAILED(hr))
852 return hr;
854 if (GET_BE_DWORD(*header) == 0x10000) {
855 *font_count = 1;
856 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
857 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
860 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
862 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
865 static HRESULT opentype_otf_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
866 DWRITE_FONT_FACE_TYPE *face_type)
868 const DWORD *header;
869 void *context;
870 HRESULT hr;
872 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(*header), &context);
873 if (FAILED(hr))
874 return hr;
876 if (GET_BE_DWORD(*header) == MS_OTTO_TAG) {
877 *font_count = 1;
878 *file_type = DWRITE_FONT_FILE_TYPE_CFF;
879 *face_type = DWRITE_FONT_FACE_TYPE_CFF;
882 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
884 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
887 static HRESULT opentype_type1_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
888 DWRITE_FONT_FACE_TYPE *face_type)
890 #include "pshpack1.h"
891 /* Specified in Adobe TechNote #5178 */
892 struct pfm_header {
893 WORD dfVersion;
894 DWORD dfSize;
895 char data0[95];
896 DWORD dfDevice;
897 char data1[12];
899 #include "poppack.h"
900 struct type1_header {
901 WORD tag;
902 char data[14];
904 const struct type1_header *header;
905 void *context;
906 HRESULT hr;
908 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(*header), &context);
909 if (FAILED(hr))
910 return hr;
912 /* tag is followed by plain text section */
913 if (header->tag == 0x8001 &&
914 (!memcmp(header->data, "%!PS-AdobeFont", 14) ||
915 !memcmp(header->data, "%!FontType", 10))) {
916 *font_count = 1;
917 *file_type = DWRITE_FONT_FILE_TYPE_TYPE1_PFB;
918 *face_type = DWRITE_FONT_FACE_TYPE_TYPE1;
921 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
923 /* let's see if it's a .pfm metrics file */
924 if (*file_type == DWRITE_FONT_FILE_TYPE_UNKNOWN) {
925 const struct pfm_header *pfm_header;
926 UINT64 filesize;
927 DWORD offset;
928 BOOL header_checked;
930 hr = IDWriteFontFileStream_GetFileSize(stream, &filesize);
931 if (FAILED(hr))
932 return hr;
934 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&pfm_header, 0, sizeof(*pfm_header), &context);
935 if (FAILED(hr))
936 return hr;
938 offset = pfm_header->dfDevice;
939 header_checked = pfm_header->dfVersion == 0x100 && pfm_header->dfSize == filesize;
940 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
942 /* as a last test check static string in PostScript information section */
943 if (header_checked) {
944 static const char postscript[] = "PostScript";
945 char *devtype_name;
947 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&devtype_name, offset, sizeof(postscript), &context);
948 if (FAILED(hr))
949 return hr;
951 if (!memcmp(devtype_name, postscript, sizeof(postscript))) {
952 *font_count = 1;
953 *file_type = DWRITE_FONT_FILE_TYPE_TYPE1_PFM;
954 *face_type = DWRITE_FONT_FACE_TYPE_TYPE1;
957 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
961 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
964 HRESULT opentype_analyze_font(IDWriteFontFileStream *stream, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported)
966 static dwrite_fontfile_analyzer fontfile_analyzers[] = {
967 opentype_ttf_analyzer,
968 opentype_otf_analyzer,
969 opentype_ttc_analyzer,
970 opentype_type1_analyzer,
971 NULL
973 dwrite_fontfile_analyzer *analyzer = fontfile_analyzers;
974 DWRITE_FONT_FACE_TYPE face;
975 HRESULT hr;
977 if (!face_type)
978 face_type = &face;
980 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
981 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
982 *font_count = 0;
984 while (*analyzer) {
985 hr = (*analyzer)(stream, font_count, file_type, face_type);
986 if (FAILED(hr))
987 return hr;
989 if (hr == S_OK)
990 break;
992 analyzer++;
995 *supported = is_face_type_supported(*face_type);
996 return S_OK;
999 HRESULT opentype_get_font_table(struct file_stream_desc *stream_desc, UINT32 tag, const void **table_data,
1000 void **table_context, UINT32 *table_size, BOOL *found)
1002 HRESULT hr;
1003 TTC_SFNT_V1 *font_header = NULL;
1004 void *sfnt_context;
1005 TT_TableRecord *table_record = NULL;
1006 void *table_record_context;
1007 int table_count, table_offset = 0;
1008 int i;
1010 if (found) *found = FALSE;
1011 if (table_size) *table_size = 0;
1013 *table_data = NULL;
1014 *table_context = NULL;
1016 if (stream_desc->face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) {
1017 const TTC_Header_V1 *ttc_header;
1018 void * ttc_context;
1019 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context);
1020 if (SUCCEEDED(hr)) {
1021 if (stream_desc->face_index >= GET_BE_DWORD(ttc_header->numFonts))
1022 hr = E_INVALIDARG;
1023 else {
1024 table_offset = GET_BE_DWORD(ttc_header->OffsetTable[stream_desc->face_index]);
1025 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context);
1027 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, ttc_context);
1030 else
1031 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context);
1033 if (FAILED(hr))
1034 return hr;
1036 table_count = GET_BE_WORD(font_header->numTables);
1037 table_offset += sizeof(*font_header);
1038 for (i = 0; i < table_count; i++)
1040 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&table_record, table_offset, sizeof(*table_record), &table_record_context);
1041 if (FAILED(hr))
1042 break;
1043 if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag)
1044 break;
1045 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, table_record_context);
1046 table_offset += sizeof(*table_record);
1049 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, sfnt_context);
1050 if (SUCCEEDED(hr) && i < table_count)
1052 int offset = GET_BE_DWORD(table_record->offset);
1053 int length = GET_BE_DWORD(table_record->length);
1054 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, table_record_context);
1056 if (found) *found = TRUE;
1057 if (table_size) *table_size = length;
1058 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, table_data, offset, length, table_context);
1061 return hr;
1064 /**********
1065 * CMAP
1066 **********/
1068 static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table)
1070 UINT32 count = 0;
1071 int i;
1073 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) {
1074 WORD type;
1075 WORD *table;
1077 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
1078 continue;
1080 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
1081 type = GET_BE_WORD(*table);
1082 TRACE("table type %i\n", type);
1084 switch (type)
1086 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
1088 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
1089 count += GET_BE_WORD(format->segCountX2)/2;
1090 break;
1092 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
1094 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
1095 count += GET_BE_DWORD(format->nGroups);
1096 break;
1098 default:
1099 FIXME("table type %i unhandled.\n", type);
1103 return count;
1106 HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1108 CMAP_Header *CMAP_Table = data;
1109 int i, k = 0;
1111 if (!CMAP_Table)
1112 return E_FAIL;
1114 *count = opentype_cmap_get_unicode_ranges_count(CMAP_Table);
1116 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables) && k < max_count; i++)
1118 WORD type;
1119 WORD *table;
1120 int j;
1122 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
1123 continue;
1125 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
1126 type = GET_BE_WORD(*table);
1127 TRACE("table type %i\n", type);
1129 switch (type)
1131 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
1133 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
1134 UINT16 segment_count = GET_BE_WORD(format->segCountX2)/2;
1135 UINT16 *startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
1137 for (j = 0; j < segment_count && GET_BE_WORD(format->endCode[j]) < 0xffff && k < max_count; j++, k++) {
1138 ranges[k].first = GET_BE_WORD(startCode[j]);
1139 ranges[k].last = GET_BE_WORD(format->endCode[j]);
1141 break;
1143 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
1145 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
1146 for (j = 0; j < GET_BE_DWORD(format->nGroups) && k < max_count; j++, k++) {
1147 ranges[k].first = GET_BE_DWORD(format->groups[j].startCharCode);
1148 ranges[k].last = GET_BE_DWORD(format->groups[j].endCharCode);
1150 break;
1152 default:
1153 FIXME("table type %i unhandled.\n", type);
1157 return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK;
1160 void opentype_get_font_metrics(struct file_stream_desc *stream_desc, DWRITE_FONT_METRICS1 *metrics, DWRITE_CARET_METRICS *caret)
1162 void *os2_context, *head_context, *post_context, *hhea_context;
1163 const TT_OS2_V2 *tt_os2;
1164 const TT_HEAD *tt_head;
1165 const TT_POST *tt_post;
1166 const TT_HHEA *tt_hhea;
1168 memset(metrics, 0, sizeof(*metrics));
1170 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1171 opentype_get_font_table(stream_desc, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
1172 opentype_get_font_table(stream_desc, MS_POST_TAG, (const void**)&tt_post, &post_context, NULL, NULL);
1173 opentype_get_font_table(stream_desc, MS_HHEA_TAG, (const void**)&tt_hhea, &hhea_context, NULL, NULL);
1175 if (tt_head) {
1176 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
1177 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
1178 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
1179 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
1180 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
1183 if (caret) {
1184 if (tt_hhea) {
1185 caret->slopeRise = GET_BE_WORD(tt_hhea->caretSlopeRise);
1186 caret->slopeRun = GET_BE_WORD(tt_hhea->caretSlopeRun);
1187 caret->offset = GET_BE_WORD(tt_hhea->caretOffset);
1189 else {
1190 caret->slopeRise = 0;
1191 caret->slopeRun = 0;
1192 caret->offset = 0;
1196 if (tt_os2) {
1197 USHORT version = GET_BE_WORD(tt_os2->version);
1199 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
1200 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
1201 interpreted as large unsigned value. */
1202 metrics->descent = abs((SHORT)GET_BE_WORD(tt_os2->usWinDescent));
1204 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
1205 if (tt_hhea) {
1206 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
1207 INT32 linegap;
1209 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
1210 metrics->ascent - metrics->descent;
1211 metrics->lineGap = linegap > 0 ? linegap : 0;
1214 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
1215 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
1216 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
1217 /* Y offset is stored as positive offset below baseline */
1218 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
1219 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
1220 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
1221 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
1222 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
1223 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
1224 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
1226 /* version 2 fields */
1227 if (version >= 2) {
1228 metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight);
1229 metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight);
1232 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
1233 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
1234 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
1235 metrics->descent = descent < 0 ? -descent : 0;
1236 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
1237 metrics->hasTypographicMetrics = TRUE;
1241 if (tt_post) {
1242 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
1243 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
1246 /* use any of thickness values if another one is zero, if both are zero use estimate */
1247 if (metrics->strikethroughThickness || metrics->underlineThickness) {
1248 if (!metrics->strikethroughThickness)
1249 metrics->strikethroughThickness = metrics->underlineThickness;
1250 if (!metrics->underlineThickness)
1251 metrics->underlineThickness = metrics->strikethroughThickness;
1253 else {
1254 metrics->strikethroughThickness = metrics->designUnitsPerEm / 14;
1255 metrics->underlineThickness = metrics->designUnitsPerEm / 14;
1258 /* estimate missing metrics */
1259 if (metrics->xHeight == 0)
1260 metrics->xHeight = metrics->designUnitsPerEm / 2;
1261 if (metrics->capHeight == 0)
1262 metrics->capHeight = metrics->designUnitsPerEm * 7 / 10;
1264 if (tt_os2)
1265 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1266 if (tt_head)
1267 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, head_context);
1268 if (tt_post)
1269 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, post_context);
1270 if (tt_hhea)
1271 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, hhea_context);
1274 void opentype_get_font_properties(struct file_stream_desc *stream_desc, struct dwrite_font_props *props)
1276 void *os2_context, *head_context;
1277 const TT_OS2_V2 *tt_os2;
1278 const TT_HEAD *tt_head;
1280 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1281 opentype_get_font_table(stream_desc, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
1283 /* default stretch, weight and style to normal */
1284 props->stretch = DWRITE_FONT_STRETCH_NORMAL;
1285 props->weight = DWRITE_FONT_WEIGHT_NORMAL;
1286 props->style = DWRITE_FONT_STYLE_NORMAL;
1287 memset(&props->panose, 0, sizeof(props->panose));
1289 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1290 if (tt_os2) {
1291 USHORT version = GET_BE_WORD(tt_os2->version);
1292 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
1293 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
1294 USHORT usWidthClass = GET_BE_WORD(tt_os2->usWidthClass);
1296 if (usWidthClass > DWRITE_FONT_STRETCH_UNDEFINED && usWidthClass <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
1297 props->stretch = usWidthClass;
1299 if (usWeightClass >= 1 && usWeightClass <= 9)
1300 usWeightClass *= 100;
1302 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
1303 props->weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
1304 else if (usWeightClass > 0)
1305 props->weight = usWeightClass;
1307 if (version >= 4 && (fsSelection & OS2_FSSELECTION_OBLIQUE))
1308 props->style = DWRITE_FONT_STYLE_OBLIQUE;
1309 else if (fsSelection & OS2_FSSELECTION_ITALIC)
1310 props->style = DWRITE_FONT_STYLE_ITALIC;
1311 memcpy(&props->panose, &tt_os2->panose, sizeof(props->panose));
1313 else if (tt_head) {
1314 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
1316 if (macStyle & TT_HEAD_MACSTYLE_CONDENSED)
1317 props->stretch = DWRITE_FONT_STRETCH_CONDENSED;
1318 else if (macStyle & TT_HEAD_MACSTYLE_EXTENDED)
1319 props->stretch = DWRITE_FONT_STRETCH_EXPANDED;
1321 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
1322 props->weight = DWRITE_FONT_WEIGHT_BOLD;
1324 if (macStyle & TT_HEAD_MACSTYLE_ITALIC)
1325 props->style = DWRITE_FONT_STYLE_ITALIC;
1328 TRACE("stretch=%d, weight=%d, style %d\n", props->stretch, props->weight, props->style);
1330 if (tt_os2)
1331 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1332 if (tt_head)
1333 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, head_context);
1336 static UINT get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform, USHORT encoding)
1338 UINT codepage = 0;
1340 switch (platform) {
1341 case OPENTYPE_PLATFORM_UNICODE:
1342 break;
1343 case OPENTYPE_PLATFORM_MAC:
1344 switch (encoding)
1346 case TT_NAME_MAC_ENCODING_ROMAN:
1347 codepage = 10000;
1348 break;
1349 case TT_NAME_MAC_ENCODING_JAPANESE:
1350 codepage = 10001;
1351 break;
1352 case TT_NAME_MAC_ENCODING_TRAD_CHINESE:
1353 codepage = 10002;
1354 break;
1355 case TT_NAME_MAC_ENCODING_KOREAN:
1356 codepage = 10003;
1357 break;
1358 case TT_NAME_MAC_ENCODING_ARABIC:
1359 codepage = 10004;
1360 break;
1361 case TT_NAME_MAC_ENCODING_HEBREW:
1362 codepage = 10005;
1363 break;
1364 case TT_NAME_MAC_ENCODING_GREEK:
1365 codepage = 10006;
1366 break;
1367 case TT_NAME_MAC_ENCODING_RUSSIAN:
1368 codepage = 10007;
1369 break;
1370 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE:
1371 codepage = 10008;
1372 break;
1373 case TT_NAME_MAC_ENCODING_THAI:
1374 codepage = 10021;
1375 break;
1376 default:
1377 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1378 break;
1380 break;
1381 case OPENTYPE_PLATFORM_WIN:
1382 switch (encoding)
1384 case TT_NAME_WINDOWS_ENCODING_SYMBOL:
1385 case TT_NAME_WINDOWS_ENCODING_UCS2:
1386 break;
1387 case TT_NAME_WINDOWS_ENCODING_SJIS:
1388 codepage = 932;
1389 break;
1390 case TT_NAME_WINDOWS_ENCODING_PRC:
1391 codepage = 936;
1392 break;
1393 case TT_NAME_WINDOWS_ENCODING_BIG5:
1394 codepage = 950;
1395 break;
1396 case TT_NAME_WINDOWS_ENCODING_WANSUNG:
1397 codepage = 20949;
1398 break;
1399 case TT_NAME_WINDOWS_ENCODING_JOHAB:
1400 codepage = 1361;
1401 break;
1402 default:
1403 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1404 break;
1406 break;
1407 default:
1408 FIXME("unknown platform %d\n", platform);
1411 return codepage;
1414 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform, USHORT lang_id, WCHAR *locale, USHORT locale_len)
1416 static const WCHAR enusW[] = {'e','n','-','U','S',0};
1418 switch (platform) {
1419 case OPENTYPE_PLATFORM_MAC:
1421 const char *locale_name = NULL;
1423 if (lang_id > TT_NAME_MAC_LANGID_AZER_ROMAN)
1424 WARN("invalid mac lang id %d\n", lang_id);
1425 else if (!name_mac_langid_to_locale[lang_id][0])
1426 FIXME("failed to map mac lang id %d to locale name\n", lang_id);
1427 else
1428 locale_name = name_mac_langid_to_locale[lang_id];
1430 if (locale_name)
1431 MultiByteToWideChar(CP_ACP, 0, name_mac_langid_to_locale[lang_id], -1, locale, locale_len);
1432 else
1433 strcpyW(locale, enusW);
1434 break;
1436 case OPENTYPE_PLATFORM_WIN:
1437 if (!LCIDToLocaleName(MAKELCID(lang_id, SORT_DEFAULT), locale, locale_len, 0)) {
1438 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id, SORT_DEFAULT));
1439 strcpyW(locale, enusW);
1441 break;
1442 case OPENTYPE_PLATFORM_UNICODE:
1443 strcpyW(locale, enusW);
1444 break;
1445 default:
1446 FIXME("unknown platform %d\n", platform);
1450 static BOOL opentype_decode_namerecord(const TT_NAME_V0 *header, BYTE *storage_area, USHORT recid, IDWriteLocalizedStrings *strings)
1452 const TT_NameRecord *record = &header->nameRecord[recid];
1453 USHORT lang_id, length, offset, encoding, platform;
1454 BOOL ret = FALSE;
1456 platform = GET_BE_WORD(record->platformID);
1457 lang_id = GET_BE_WORD(record->languageID);
1458 length = GET_BE_WORD(record->length);
1459 offset = GET_BE_WORD(record->offset);
1460 encoding = GET_BE_WORD(record->encodingID);
1462 if (lang_id < 0x8000) {
1463 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
1464 WCHAR *name_string;
1465 UINT codepage;
1467 codepage = get_name_record_codepage(platform, encoding);
1468 get_name_record_locale(platform, lang_id, locale, sizeof(locale)/sizeof(WCHAR));
1470 if (codepage) {
1471 DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0);
1472 name_string = heap_alloc(sizeof(WCHAR) * (len+1));
1473 MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len);
1474 name_string[len] = 0;
1476 else {
1477 int i;
1479 length /= sizeof(WCHAR);
1480 name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length);
1481 for (i = 0; i < length; i++)
1482 name_string[i] = GET_BE_WORD(name_string[i]);
1485 TRACE("string %s for locale %s found\n", debugstr_w(name_string), debugstr_w(locale));
1486 add_localizedstring(strings, locale, name_string);
1487 heap_free(name_string);
1488 ret = TRUE;
1490 else
1491 FIXME("handle NAME format 1\n");
1493 return ret;
1496 static HRESULT opentype_get_font_strings_from_id(const void *table_data, enum OPENTYPE_STRING_ID id, IDWriteLocalizedStrings **strings)
1498 const TT_NAME_V0 *header;
1499 BYTE *storage_area = 0;
1500 USHORT count = 0;
1501 int i, candidate;
1502 WORD format;
1503 BOOL exists;
1504 HRESULT hr;
1506 if (!table_data)
1507 return E_FAIL;
1509 hr = create_localizedstrings(strings);
1510 if (FAILED(hr)) return hr;
1512 header = table_data;
1513 format = GET_BE_WORD(header->format);
1515 switch (format) {
1516 case 0:
1517 case 1:
1518 break;
1519 default:
1520 FIXME("unsupported NAME format %d\n", format);
1523 storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset);
1524 count = GET_BE_WORD(header->count);
1526 exists = FALSE;
1527 candidate = -1;
1528 for (i = 0; i < count; i++) {
1529 const TT_NameRecord *record = &header->nameRecord[i];
1530 USHORT platform;
1532 if (GET_BE_WORD(record->nameID) != id)
1533 continue;
1535 /* Right now only accept unicode and windows encoded fonts */
1536 platform = GET_BE_WORD(record->platformID);
1537 if (platform != OPENTYPE_PLATFORM_UNICODE &&
1538 platform != OPENTYPE_PLATFORM_MAC &&
1539 platform != OPENTYPE_PLATFORM_WIN)
1541 FIXME("platform %i not supported\n", platform);
1542 continue;
1545 /* Skip such entries for now, fonts tend to duplicate those strings as
1546 WIN platform entries. If font does not have WIN or MAC entry for this id, we will
1547 use this Unicode platform entry while assuming en-US locale. */
1548 if (platform == OPENTYPE_PLATFORM_UNICODE) {
1549 candidate = i;
1550 continue;
1553 if (!(exists = opentype_decode_namerecord(header, storage_area, i, *strings)))
1554 continue;
1557 if (!exists) {
1558 if (candidate != -1)
1559 exists = opentype_decode_namerecord(header, storage_area, candidate, *strings);
1560 else {
1561 IDWriteLocalizedStrings_Release(*strings);
1562 *strings = NULL;
1566 return exists ? S_OK : E_FAIL;
1569 /* Provides a conversion from DWRITE to OpenType name ids, input id should be valid, it's not checked. */
1570 HRESULT opentype_get_font_info_strings(const void *table_data, DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings)
1572 return opentype_get_font_strings_from_id(table_data, dwriteid_to_opentypeid[id], strings);
1575 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
1576 have 'Preferred Family Name' in WWS format, then WWS name is not used. */
1577 HRESULT opentype_get_font_familyname(struct file_stream_desc *stream_desc, IDWriteLocalizedStrings **names)
1579 const TT_OS2_V2 *tt_os2;
1580 void *os2_context, *name_context;
1581 const void *name_table;
1582 HRESULT hr;
1584 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1585 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1587 *names = NULL;
1589 /* if Preferred Family doesn't conform to WWS model try WWS name */
1590 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1591 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_FAMILY_NAME, names);
1592 else
1593 hr = E_FAIL;
1595 if (FAILED(hr))
1596 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_FAMILY_NAME, names);
1597 if (FAILED(hr))
1598 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, names);
1600 if (tt_os2)
1601 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1602 if (name_context)
1603 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1605 return hr;
1608 /* FaceName locating order is WWS Face Name -> Preferred Face Name -> Face Name. If font claims to
1609 have 'Preferred Face Name' in WWS format, then WWS name is not used. */
1610 HRESULT opentype_get_font_facename(struct file_stream_desc *stream_desc, IDWriteLocalizedStrings **names)
1612 const TT_OS2_V2 *tt_os2;
1613 void *os2_context, *name_context;
1614 const void *name_table;
1615 HRESULT hr;
1617 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1618 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1620 *names = NULL;
1622 /* if Preferred Family doesn't conform to WWS model try WWS name */
1623 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1624 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_SUBFAMILY_NAME, names);
1625 else
1626 hr = E_FAIL;
1628 if (FAILED(hr))
1629 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME, names);
1630 if (FAILED(hr))
1631 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_SUBFAMILY_NAME, names);
1633 if (tt_os2)
1634 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1635 if (name_context)
1636 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1638 return hr;
1641 static inline const OT_Script *opentype_get_script(const OT_ScriptList *scriptlist, UINT32 scripttag)
1643 UINT16 j;
1645 for (j = 0; j < GET_BE_WORD(scriptlist->ScriptCount); j++) {
1646 const char *tag = scriptlist->ScriptRecord[j].ScriptTag;
1647 if (scripttag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1648 return (OT_Script*)((BYTE*)scriptlist + GET_BE_WORD(scriptlist->ScriptRecord[j].Script));
1651 return NULL;
1654 static inline const OT_LangSys *opentype_get_langsys(const OT_Script *script, UINT32 languagetag)
1656 UINT16 j;
1658 for (j = 0; j < GET_BE_WORD(script->LangSysCount); j++) {
1659 const char *tag = script->LangSysRecord[j].LangSysTag;
1660 if (languagetag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1661 return (OT_LangSys*)((BYTE*)script + GET_BE_WORD(script->LangSysRecord[j].LangSys));
1664 return NULL;
1667 static void opentype_add_font_features(const GPOS_GSUB_Header *header, const OT_LangSys *langsys,
1668 UINT32 max_tagcount, UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1670 const OT_FeatureList *features = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
1671 UINT16 j;
1673 for (j = 0; j < GET_BE_WORD(langsys->FeatureCount); j++) {
1674 const OT_FeatureRecord *feature = &features->FeatureRecord[langsys->FeatureIndex[j]];
1675 const char *tag = feature->FeatureTag;
1677 if (*count < max_tagcount)
1678 tags[*count] = DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]);
1680 (*count)++;
1684 HRESULT opentype_get_typographic_features(IDWriteFontFace *fontface, UINT32 scripttag, UINT32 languagetag, UINT32 max_tagcount,
1685 UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1687 UINT32 tables[2] = { MS_GSUB_TAG, MS_GPOS_TAG };
1688 HRESULT hr;
1689 UINT8 i;
1691 *count = 0;
1692 for (i = 0; i < sizeof(tables)/sizeof(tables[0]); i++) {
1693 const OT_ScriptList *scriptlist;
1694 const GPOS_GSUB_Header *header;
1695 const OT_Script *script;
1696 const void *ptr;
1697 void *context;
1698 UINT32 size;
1699 BOOL exists;
1701 exists = FALSE;
1702 hr = IDWriteFontFace_TryGetFontTable(fontface, tables[i], &ptr, &size, &context, &exists);
1703 if (FAILED(hr))
1704 return hr;
1706 if (!exists)
1707 continue;
1709 header = (const GPOS_GSUB_Header*)ptr;
1710 scriptlist = (const OT_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
1712 script = opentype_get_script(scriptlist, scripttag);
1713 if (script) {
1714 const OT_LangSys *langsys = opentype_get_langsys(script, languagetag);
1715 if (langsys)
1716 opentype_add_font_features(header, langsys, max_tagcount, count, tags);
1719 IDWriteFontFace_ReleaseFontTable(fontface, context);
1722 return *count > max_tagcount ? E_NOT_SUFFICIENT_BUFFER : S_OK;
1725 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
1727 WORD num_ratios, i, group_offset = 0;
1728 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
1729 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
1731 num_ratios = GET_BE_WORD(hdr->numRatios);
1733 for (i = 0; i < num_ratios; i++) {
1735 if (!ratios[i].bCharSet) continue;
1737 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
1738 ratios[i].yEndRatio == 0) ||
1739 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
1740 ratios[i].yEndRatio >= dev_y_ratio))
1742 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
1743 break;
1746 if (group_offset)
1747 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
1748 return NULL;
1751 BOOL opentype_get_vdmx_size(const void *data, INT emsize, UINT16 *ascent, UINT16 *descent)
1753 const struct VDMX_Header *hdr = (const struct VDMX_Header*)data;
1754 const struct VDMX_group *group;
1755 const struct VDMX_vTable *tables;
1756 WORD recs, i;
1758 if (!data)
1759 return FALSE;
1761 group = find_vdmx_group(hdr);
1762 if (!group)
1763 return FALSE;
1765 recs = GET_BE_WORD(group->recs);
1766 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
1768 tables = (const struct VDMX_vTable *)(group + 1);
1769 for (i = 0; i < recs; i++) {
1770 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
1771 if (ppem > emsize) {
1772 FIXME("interpolate %d\n", emsize);
1773 return FALSE;
1776 if (ppem == emsize) {
1777 *ascent = (SHORT)GET_BE_WORD(tables[i].yMax);
1778 *descent = -(SHORT)GET_BE_WORD(tables[i].yMin);
1779 return TRUE;
1782 return FALSE;
1785 WORD opentype_get_gasp_flags(const WORD *ptr, UINT32 size, INT emsize)
1787 WORD num_recs, version;
1788 WORD flags = 0;
1790 if (!ptr)
1791 return 0;
1793 version = GET_BE_WORD( *ptr++ );
1794 num_recs = GET_BE_WORD( *ptr++ );
1795 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
1796 ERR("unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
1797 goto done;
1800 while (num_recs--) {
1801 flags = GET_BE_WORD( *(ptr + 1) );
1802 if (emsize <= GET_BE_WORD( *ptr )) break;
1803 ptr += 2;
1806 done:
1807 return flags;
1810 UINT32 opentype_get_cpal_palettecount(const void *cpal)
1812 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1813 return header ? GET_BE_WORD(header->numPalette) : 0;
1816 UINT32 opentype_get_cpal_paletteentrycount(const void *cpal)
1818 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1819 return header ? GET_BE_WORD(header->numPaletteEntries) : 0;
1822 HRESULT opentype_get_cpal_entries(const void *cpal, UINT32 palette, UINT32 first_entry_index, UINT32 entry_count,
1823 DWRITE_COLOR_F *entries)
1825 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1826 const struct CPAL_ColorRecord *records;
1827 UINT32 palettecount, entrycount, i;
1829 if (!header) return DWRITE_E_NOCOLOR;
1831 palettecount = GET_BE_WORD(header->numPalette);
1832 if (palette >= palettecount)
1833 return DWRITE_E_NOCOLOR;
1835 entrycount = GET_BE_WORD(header->numPaletteEntries);
1836 if (first_entry_index + entry_count > entrycount)
1837 return E_INVALIDARG;
1839 records = (const struct CPAL_ColorRecord*)((BYTE*)cpal + GET_BE_DWORD(header->offsetFirstColorRecord));
1840 first_entry_index += GET_BE_WORD(header->colorRecordIndices[palette]);
1842 for (i = 0; i < entry_count; i++) {
1843 entries[i].r = records[first_entry_index + i].red / 255.0f;
1844 entries[i].g = records[first_entry_index + i].green / 255.0f;
1845 entries[i].b = records[first_entry_index + i].blue / 255.0f;
1846 entries[i].a = records[first_entry_index + i].alpha / 255.0f;
1849 return S_OK;
1852 static int colr_compare_gid(const void *g, const void *r)
1854 const struct COLR_BaseGlyphRecord *record = r;
1855 UINT16 glyph = *(UINT16*)g, GID = GET_BE_WORD(record->GID);
1856 int ret = 0;
1858 if (glyph > GID)
1859 ret = 1;
1860 else if (glyph < GID)
1861 ret = -1;
1863 return ret;
1866 HRESULT opentype_get_colr_glyph(const void *colr, UINT16 glyph, struct dwrite_colorglyph *ret)
1868 const struct COLR_BaseGlyphRecord *record;
1869 const struct COLR_Header *header = colr;
1870 const struct COLR_LayerRecord *layer;
1871 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
1872 DWORD baserecordoffset = GET_BE_DWORD(header->offsetBaseGlyphRecord);
1873 WORD numbaserecords = GET_BE_WORD(header->numBaseGlyphRecords);
1875 record = bsearch(&glyph, (BYTE*)colr + baserecordoffset, numbaserecords, sizeof(struct COLR_BaseGlyphRecord),
1876 colr_compare_gid);
1877 if (!record) {
1878 ret->layer = 0;
1879 ret->first_layer = 0;
1880 ret->num_layers = 0;
1881 ret->glyph = glyph;
1882 ret->palette_index = 0xffff;
1883 return S_FALSE;
1886 ret->layer = 0;
1887 ret->first_layer = GET_BE_WORD(record->firstLayerIndex);
1888 ret->num_layers = GET_BE_WORD(record->numLayers);
1890 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + ret->first_layer + ret->layer;
1891 ret->glyph = GET_BE_WORD(layer->GID);
1892 ret->palette_index = GET_BE_WORD(layer->paletteIndex);
1894 return S_OK;
1897 void opentype_colr_next_glyph(const void *colr, struct dwrite_colorglyph *glyph)
1899 const struct COLR_Header *header = colr;
1900 const struct COLR_LayerRecord *layer;
1901 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
1903 /* iterated all the way through */
1904 if (glyph->layer == glyph->num_layers)
1905 return;
1907 glyph->layer++;
1908 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + glyph->first_layer + glyph->layer;
1909 glyph->glyph = GET_BE_WORD(layer->GID);
1910 glyph->palette_index = GET_BE_WORD(layer->paletteIndex);
1913 HRESULT opentype_get_font_signature(struct file_stream_desc *stream_desc, FONTSIGNATURE *fontsig)
1915 const TT_OS2_V2 *tt_os2;
1916 void *os2_context;
1917 HRESULT hr;
1919 hr = opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1920 if (tt_os2) {
1921 fontsig->fsUsb[0] = GET_BE_DWORD(tt_os2->ulUnicodeRange1);
1922 fontsig->fsUsb[1] = GET_BE_DWORD(tt_os2->ulUnicodeRange2);
1923 fontsig->fsUsb[2] = GET_BE_DWORD(tt_os2->ulUnicodeRange3);
1924 fontsig->fsUsb[3] = GET_BE_DWORD(tt_os2->ulUnicodeRange4);
1926 fontsig->fsCsb[0] = GET_BE_DWORD(tt_os2->ulCodePageRange1);
1927 fontsig->fsCsb[1] = GET_BE_DWORD(tt_os2->ulCodePageRange2);
1929 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1932 return hr;
1935 BOOL opentype_has_vertical_variants(IDWriteFontFace3 *fontface)
1937 const OT_FeatureList *featurelist;
1938 const OT_LookupList *lookup_list;
1939 BOOL exists = FALSE, ret = FALSE;
1940 const GPOS_GSUB_Header *header;
1941 const void *data;
1942 void *context;
1943 UINT32 size;
1944 HRESULT hr;
1945 UINT16 i;
1947 hr = IDWriteFontFace3_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
1948 if (FAILED(hr) || !exists)
1949 return FALSE;
1951 header = data;
1952 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
1953 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
1955 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
1956 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
1957 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
1958 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
1959 const GSUB_SingleSubstFormat2 *subst2;
1960 const OT_LookupTable *lookup_table;
1961 UINT32 offset;
1963 if (lookup_count == 0)
1964 continue;
1966 for (i = 0; i < lookup_count; i++) {
1967 /* check if lookup is empty */
1968 index = GET_BE_WORD(feature->LookupListIndex[i]);
1969 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
1971 type = GET_BE_WORD(lookup_table->LookupType);
1972 if (type != OPENTYPE_GPOS_SINGLE_SUBST && type != OPENTYPE_GPOS_EXTENSION_SUBST)
1973 continue;
1975 count = GET_BE_WORD(lookup_table->SubTableCount);
1976 if (count == 0)
1977 continue;
1979 offset = GET_BE_WORD(lookup_table->SubTable[0]);
1980 if (type == OPENTYPE_GPOS_EXTENSION_SUBST) {
1981 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
1982 if (GET_BE_WORD(ext->SubstFormat) == 1)
1983 offset += GET_BE_DWORD(ext->ExtensionOffset);
1984 else
1985 FIXME("Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
1988 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
1989 index = GET_BE_WORD(subst2->SubstFormat);
1990 if (index == 1)
1991 FIXME("Validate Single Substitution Format 1\n");
1992 else if (index == 2) {
1993 /* SimSun-ExtB has 0 glyph count for this substitution */
1994 if (GET_BE_WORD(subst2->GlyphCount) > 0) {
1995 ret = TRUE;
1996 break;
1999 else
2000 WARN("Unknown Single Substitution Format, %u\n", index);
2005 IDWriteFontFace3_ReleaseFontTable(fontface, context);
2007 return ret;