crypt32: Test CryptStringToBinary with weird Base64.
[wine.git] / dlls / dwrite / opentype.c
blob7a3e641ad4be545d0ce6ba4218f6ecc45b1bd130
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 USHORT majorVersion;
117 USHORT minorVersion;
118 ULONG revision;
119 ULONG checksumadj;
120 ULONG magic;
121 USHORT flags;
122 USHORT unitsPerEm;
123 ULONGLONG created;
124 ULONGLONG modified;
125 SHORT xMin;
126 SHORT yMin;
127 SHORT xMax;
128 SHORT yMax;
129 USHORT macStyle;
130 USHORT lowestRecPPEM;
131 SHORT direction_hint;
132 SHORT index_format;
133 SHORT glyphdata_format;
134 } TT_HEAD;
136 enum TT_HEAD_MACSTYLE
138 TT_HEAD_MACSTYLE_BOLD = 1 << 0,
139 TT_HEAD_MACSTYLE_ITALIC = 1 << 1,
140 TT_HEAD_MACSTYLE_UNDERLINE = 1 << 2,
141 TT_HEAD_MACSTYLE_OUTLINE = 1 << 3,
142 TT_HEAD_MACSTYLE_SHADOW = 1 << 4,
143 TT_HEAD_MACSTYLE_CONDENSED = 1 << 5,
144 TT_HEAD_MACSTYLE_EXTENDED = 1 << 6,
147 typedef struct
149 ULONG Version;
150 ULONG italicAngle;
151 SHORT underlinePosition;
152 SHORT underlineThickness;
153 ULONG fixed_pitch;
154 ULONG minmemType42;
155 ULONG maxmemType42;
156 ULONG minmemType1;
157 ULONG maxmemType1;
158 } TT_POST;
160 typedef struct
162 USHORT version;
163 SHORT xAvgCharWidth;
164 USHORT usWeightClass;
165 USHORT usWidthClass;
166 SHORT fsType;
167 SHORT ySubscriptXSize;
168 SHORT ySubscriptYSize;
169 SHORT ySubscriptXOffset;
170 SHORT ySubscriptYOffset;
171 SHORT ySuperscriptXSize;
172 SHORT ySuperscriptYSize;
173 SHORT ySuperscriptXOffset;
174 SHORT ySuperscriptYOffset;
175 SHORT yStrikeoutSize;
176 SHORT yStrikeoutPosition;
177 SHORT sFamilyClass;
178 PANOSE panose;
179 ULONG ulUnicodeRange1;
180 ULONG ulUnicodeRange2;
181 ULONG ulUnicodeRange3;
182 ULONG ulUnicodeRange4;
183 CHAR achVendID[4];
184 USHORT fsSelection;
185 USHORT usFirstCharIndex;
186 USHORT usLastCharIndex;
187 /* According to the Apple spec, original version didn't have the below fields,
188 * version numbers were taken from the OpenType spec.
190 /* version 0 (TrueType 1.5) */
191 USHORT sTypoAscender;
192 USHORT sTypoDescender;
193 USHORT sTypoLineGap;
194 USHORT usWinAscent;
195 USHORT usWinDescent;
196 /* version 1 (TrueType 1.66) */
197 ULONG ulCodePageRange1;
198 ULONG ulCodePageRange2;
199 /* version 2 (OpenType 1.2) */
200 SHORT sxHeight;
201 SHORT sCapHeight;
202 USHORT usDefaultChar;
203 USHORT usBreakChar;
204 USHORT usMaxContext;
205 } TT_OS2_V2;
207 typedef struct {
208 USHORT majorVersion;
209 USHORT minorVersion;
210 SHORT ascender;
211 SHORT descender;
212 SHORT linegap;
213 USHORT advanceWidthMax;
214 SHORT minLeftSideBearing;
215 SHORT minRightSideBearing;
216 SHORT xMaxExtent;
217 SHORT caretSlopeRise;
218 SHORT caretSlopeRun;
219 SHORT caretOffset;
220 SHORT reserved[4];
221 SHORT metricDataFormat;
222 USHORT numberOfHMetrics;
223 } TT_HHEA;
225 #include "poppack.h"
227 enum OS2_FSSELECTION {
228 OS2_FSSELECTION_ITALIC = 1 << 0,
229 OS2_FSSELECTION_UNDERSCORE = 1 << 1,
230 OS2_FSSELECTION_NEGATIVE = 1 << 2,
231 OS2_FSSELECTION_OUTLINED = 1 << 3,
232 OS2_FSSELECTION_STRIKEOUT = 1 << 4,
233 OS2_FSSELECTION_BOLD = 1 << 5,
234 OS2_FSSELECTION_REGULAR = 1 << 6,
235 OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7,
236 OS2_FSSELECTION_WWS = 1 << 8,
237 OS2_FSSELECTION_OBLIQUE = 1 << 9
240 typedef struct {
241 WORD platformID;
242 WORD encodingID;
243 WORD languageID;
244 WORD nameID;
245 WORD length;
246 WORD offset;
247 } TT_NameRecord;
249 typedef struct {
250 WORD format;
251 WORD count;
252 WORD stringOffset;
253 TT_NameRecord nameRecord[1];
254 } TT_NAME_V0;
256 struct VDMX_Header
258 WORD version;
259 WORD numRecs;
260 WORD numRatios;
263 struct VDMX_Ratio
265 BYTE bCharSet;
266 BYTE xRatio;
267 BYTE yStartRatio;
268 BYTE yEndRatio;
271 struct VDMX_group
273 WORD recs;
274 BYTE startsz;
275 BYTE endsz;
278 struct VDMX_vTable
280 WORD yPelHeight;
281 SHORT yMax;
282 SHORT yMin;
285 typedef struct {
286 CHAR FeatureTag[4];
287 WORD Feature;
288 } OT_FeatureRecord;
290 typedef struct {
291 WORD FeatureCount;
292 OT_FeatureRecord FeatureRecord[1];
293 } OT_FeatureList;
295 typedef struct {
296 WORD LookupOrder; /* Reserved */
297 WORD ReqFeatureIndex;
298 WORD FeatureCount;
299 WORD FeatureIndex[1];
300 } OT_LangSys;
302 typedef struct {
303 CHAR LangSysTag[4];
304 WORD LangSys;
305 } OT_LangSysRecord;
307 typedef struct {
308 WORD DefaultLangSys;
309 WORD LangSysCount;
310 OT_LangSysRecord LangSysRecord[1];
311 } OT_Script;
313 typedef struct {
314 CHAR ScriptTag[4];
315 WORD Script;
316 } OT_ScriptRecord;
318 typedef struct {
319 WORD ScriptCount;
320 OT_ScriptRecord ScriptRecord[1];
321 } OT_ScriptList;
323 typedef struct {
324 DWORD version;
325 WORD ScriptList;
326 WORD FeatureList;
327 WORD LookupList;
328 } GPOS_GSUB_Header;
330 enum OPENTYPE_PLATFORM_ID
332 OPENTYPE_PLATFORM_UNICODE = 0,
333 OPENTYPE_PLATFORM_MAC,
334 OPENTYPE_PLATFORM_ISO,
335 OPENTYPE_PLATFORM_WIN,
336 OPENTYPE_PLATFORM_CUSTOM
339 typedef struct {
340 WORD FeatureParams;
341 WORD LookupCount;
342 WORD LookupListIndex[1];
343 } OT_Feature;
345 typedef struct {
346 WORD LookupCount;
347 WORD Lookup[1];
348 } OT_LookupList;
350 typedef struct {
351 WORD LookupType;
352 WORD LookupFlag;
353 WORD SubTableCount;
354 WORD SubTable[1];
355 } OT_LookupTable;
357 typedef struct {
358 WORD SubstFormat;
359 WORD Coverage;
360 WORD DeltaGlyphID;
361 } GSUB_SingleSubstFormat1;
363 typedef struct {
364 WORD SubstFormat;
365 WORD Coverage;
366 WORD GlyphCount;
367 WORD Substitute[1];
368 } GSUB_SingleSubstFormat2;
370 typedef struct {
371 WORD SubstFormat;
372 WORD ExtensionLookupType;
373 DWORD ExtensionOffset;
374 } GSUB_ExtensionPosFormat1;
376 enum OPENTYPE_GPOS_LOOKUPS
378 OPENTYPE_GPOS_SINGLE_SUBST = 1,
379 OPENTYPE_GPOS_EXTENSION_SUBST = 7
382 enum TT_NAME_WINDOWS_ENCODING_ID
384 TT_NAME_WINDOWS_ENCODING_SYMBOL = 0,
385 TT_NAME_WINDOWS_ENCODING_UCS2,
386 TT_NAME_WINDOWS_ENCODING_SJIS,
387 TT_NAME_WINDOWS_ENCODING_PRC,
388 TT_NAME_WINDOWS_ENCODING_BIG5,
389 TT_NAME_WINDOWS_ENCODING_WANSUNG,
390 TT_NAME_WINDOWS_ENCODING_JOHAB,
391 TT_NAME_WINDOWS_ENCODING_RESERVED1,
392 TT_NAME_WINDOWS_ENCODING_RESERVED2,
393 TT_NAME_WINDOWS_ENCODING_RESERVED3,
394 TT_NAME_WINDOWS_ENCODING_UCS4
397 enum TT_NAME_MAC_ENCODING_ID
399 TT_NAME_MAC_ENCODING_ROMAN = 0,
400 TT_NAME_MAC_ENCODING_JAPANESE,
401 TT_NAME_MAC_ENCODING_TRAD_CHINESE,
402 TT_NAME_MAC_ENCODING_KOREAN,
403 TT_NAME_MAC_ENCODING_ARABIC,
404 TT_NAME_MAC_ENCODING_HEBREW,
405 TT_NAME_MAC_ENCODING_GREEK,
406 TT_NAME_MAC_ENCODING_RUSSIAN,
407 TT_NAME_MAC_ENCODING_RSYMBOL,
408 TT_NAME_MAC_ENCODING_DEVANAGARI,
409 TT_NAME_MAC_ENCODING_GURMUKHI,
410 TT_NAME_MAC_ENCODING_GUJARATI,
411 TT_NAME_MAC_ENCODING_ORIYA,
412 TT_NAME_MAC_ENCODING_BENGALI,
413 TT_NAME_MAC_ENCODING_TAMIL,
414 TT_NAME_MAC_ENCODING_TELUGU,
415 TT_NAME_MAC_ENCODING_KANNADA,
416 TT_NAME_MAC_ENCODING_MALAYALAM,
417 TT_NAME_MAC_ENCODING_SINHALESE,
418 TT_NAME_MAC_ENCODING_BURMESE,
419 TT_NAME_MAC_ENCODING_KHMER,
420 TT_NAME_MAC_ENCODING_THAI,
421 TT_NAME_MAC_ENCODING_LAOTIAN,
422 TT_NAME_MAC_ENCODING_GEORGIAN,
423 TT_NAME_MAC_ENCODING_ARMENIAN,
424 TT_NAME_MAC_ENCODING_SIMPL_CHINESE,
425 TT_NAME_MAC_ENCODING_TIBETAN,
426 TT_NAME_MAC_ENCODING_MONGOLIAN,
427 TT_NAME_MAC_ENCODING_GEEZ,
428 TT_NAME_MAC_ENCODING_SLAVIC,
429 TT_NAME_MAC_ENCODING_VIETNAMESE,
430 TT_NAME_MAC_ENCODING_SINDHI,
431 TT_NAME_MAC_ENCODING_UNINTERPRETED
434 enum TT_NAME_MAC_LANGUAGE_ID
436 TT_NAME_MAC_LANGID_ENGLISH = 0,
437 TT_NAME_MAC_LANGID_FRENCH,
438 TT_NAME_MAC_LANGID_GERMAN,
439 TT_NAME_MAC_LANGID_ITALIAN,
440 TT_NAME_MAC_LANGID_DUTCH,
441 TT_NAME_MAC_LANGID_SWEDISH,
442 TT_NAME_MAC_LANGID_SPANISH,
443 TT_NAME_MAC_LANGID_DANISH,
444 TT_NAME_MAC_LANGID_PORTUGUESE,
445 TT_NAME_MAC_LANGID_NORWEGIAN,
446 TT_NAME_MAC_LANGID_HEBREW,
447 TT_NAME_MAC_LANGID_JAPANESE,
448 TT_NAME_MAC_LANGID_ARABIC,
449 TT_NAME_MAC_LANGID_FINNISH,
450 TT_NAME_MAC_LANGID_GREEK,
451 TT_NAME_MAC_LANGID_ICELANDIC,
452 TT_NAME_MAC_LANGID_MALTESE,
453 TT_NAME_MAC_LANGID_TURKISH,
454 TT_NAME_MAC_LANGID_CROATIAN,
455 TT_NAME_MAC_LANGID_TRAD_CHINESE,
456 TT_NAME_MAC_LANGID_URDU,
457 TT_NAME_MAC_LANGID_HINDI,
458 TT_NAME_MAC_LANGID_THAI,
459 TT_NAME_MAC_LANGID_KOREAN,
460 TT_NAME_MAC_LANGID_LITHUANIAN,
461 TT_NAME_MAC_LANGID_POLISH,
462 TT_NAME_MAC_LANGID_HUNGARIAN,
463 TT_NAME_MAC_LANGID_ESTONIAN,
464 TT_NAME_MAC_LANGID_LATVIAN,
465 TT_NAME_MAC_LANGID_SAMI,
466 TT_NAME_MAC_LANGID_FAROESE,
467 TT_NAME_MAC_LANGID_FARSI,
468 TT_NAME_MAC_LANGID_RUSSIAN,
469 TT_NAME_MAC_LANGID_SIMPL_CHINESE,
470 TT_NAME_MAC_LANGID_FLEMISH,
471 TT_NAME_MAC_LANGID_GAELIC,
472 TT_NAME_MAC_LANGID_ALBANIAN,
473 TT_NAME_MAC_LANGID_ROMANIAN,
474 TT_NAME_MAC_LANGID_CZECH,
475 TT_NAME_MAC_LANGID_SLOVAK,
476 TT_NAME_MAC_LANGID_SLOVENIAN,
477 TT_NAME_MAC_LANGID_YIDDISH,
478 TT_NAME_MAC_LANGID_SERBIAN,
479 TT_NAME_MAC_LANGID_MACEDONIAN,
480 TT_NAME_MAC_LANGID_BULGARIAN,
481 TT_NAME_MAC_LANGID_UKRAINIAN,
482 TT_NAME_MAC_LANGID_BYELORUSSIAN,
483 TT_NAME_MAC_LANGID_UZBEK,
484 TT_NAME_MAC_LANGID_KAZAKH,
485 TT_NAME_MAC_LANGID_AZERB_CYR,
486 TT_NAME_MAC_LANGID_AZERB_ARABIC,
487 TT_NAME_MAC_LANGID_ARMENIAN,
488 TT_NAME_MAC_LANGID_GEORGIAN,
489 TT_NAME_MAC_LANGID_MOLDAVIAN,
490 TT_NAME_MAC_LANGID_KIRGHIZ,
491 TT_NAME_MAC_LANGID_TAJIKI,
492 TT_NAME_MAC_LANGID_TURKMEN,
493 TT_NAME_MAC_LANGID_MONGOLIAN,
494 TT_NAME_MAC_LANGID_MONGOLIAN_CYR,
495 TT_NAME_MAC_LANGID_PASHTO,
496 TT_NAME_MAC_LANGID_KURDISH,
497 TT_NAME_MAC_LANGID_KASHMIRI,
498 TT_NAME_MAC_LANGID_SINDHI,
499 TT_NAME_MAC_LANGID_TIBETAN,
500 TT_NAME_MAC_LANGID_NEPALI,
501 TT_NAME_MAC_LANGID_SANSKRIT,
502 TT_NAME_MAC_LANGID_MARATHI,
503 TT_NAME_MAC_LANGID_BENGALI,
504 TT_NAME_MAC_LANGID_ASSAMESE,
505 TT_NAME_MAC_LANGID_GUJARATI,
506 TT_NAME_MAC_LANGID_PUNJABI,
507 TT_NAME_MAC_LANGID_ORIYA,
508 TT_NAME_MAC_LANGID_MALAYALAM,
509 TT_NAME_MAC_LANGID_KANNADA,
510 TT_NAME_MAC_LANGID_TAMIL,
511 TT_NAME_MAC_LANGID_TELUGU,
512 TT_NAME_MAC_LANGID_SINHALESE,
513 TT_NAME_MAC_LANGID_BURMESE,
514 TT_NAME_MAC_LANGID_KHMER,
515 TT_NAME_MAC_LANGID_LAO,
516 TT_NAME_MAC_LANGID_VIETNAMESE,
517 TT_NAME_MAC_LANGID_INDONESIAN,
518 TT_NAME_MAC_LANGID_TAGALOG,
519 TT_NAME_MAC_LANGID_MALAY_ROMAN,
520 TT_NAME_MAC_LANGID_MALAY_ARABIC,
521 TT_NAME_MAC_LANGID_AMHARIC,
522 TT_NAME_MAC_LANGID_TIGRINYA,
523 TT_NAME_MAC_LANGID_GALLA,
524 TT_NAME_MAC_LANGID_SOMALI,
525 TT_NAME_MAC_LANGID_SWAHILI,
526 TT_NAME_MAC_LANGID_KINYARWANDA,
527 TT_NAME_MAC_LANGID_RUNDI,
528 TT_NAME_MAC_LANGID_NYANJA,
529 TT_NAME_MAC_LANGID_MALAGASY,
530 TT_NAME_MAC_LANGID_ESPERANTO,
531 TT_NAME_MAC_LANGID_WELSH = 128,
532 TT_NAME_MAC_LANGID_BASQUE,
533 TT_NAME_MAC_LANGID_CATALAN,
534 TT_NAME_MAC_LANGID_LATIN,
535 TT_NAME_MAC_LANGID_QUECHUA,
536 TT_NAME_MAC_LANGID_GUARANI,
537 TT_NAME_MAC_LANGID_AYMARA,
538 TT_NAME_MAC_LANGID_TATAR,
539 TT_NAME_MAC_LANGID_UIGHUR,
540 TT_NAME_MAC_LANGID_DZONGKHA,
541 TT_NAME_MAC_LANGID_JAVANESE,
542 TT_NAME_MAC_LANGID_SUNDANESE,
543 TT_NAME_MAC_LANGID_GALICIAN,
544 TT_NAME_MAC_LANGID_AFRIKAANS,
545 TT_NAME_MAC_LANGID_BRETON,
546 TT_NAME_MAC_LANGID_INUKTITUT,
547 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC,
548 TT_NAME_MAC_LANGID_MANX_GAELIC,
549 TT_NAME_MAC_LANGID_IRISH_GAELIC,
550 TT_NAME_MAC_LANGID_TONGAN,
551 TT_NAME_MAC_LANGID_GREEK_POLYTONIC,
552 TT_NAME_MAC_LANGID_GREENLANDIC,
553 TT_NAME_MAC_LANGID_AZER_ROMAN
556 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
557 static const char name_mac_langid_to_locale[][10] = {
558 "en-US",
559 "fr-FR",
560 "de-DE",
561 "it-IT",
562 "nl-NL",
563 "sv-SE",
564 "es-ES",
565 "da-DA",
566 "pt-PT",
567 "no-NO",
568 "he-IL",
569 "ja-JP",
570 "ar-AR",
571 "fi-FI",
572 "el-GR",
573 "is-IS",
574 "mt-MT",
575 "tr-TR",
576 "hr-HR",
577 "zh-HK",
578 "ur-PK",
579 "hi-IN",
580 "th-TH",
581 "ko-KR",
582 "lt-LT",
583 "pl-PL",
584 "hu-HU",
585 "et-EE",
586 "lv-LV",
587 "se-NO",
588 "fo-FO",
589 "fa-IR",
590 "ru-RU",
591 "zh-CN",
592 "nl-BE",
593 "gd-GB",
594 "sq-AL",
595 "ro-RO",
596 "cs-CZ",
597 "sk-SK",
598 "sl-SI",
600 "sr-Latn",
601 "mk-MK",
602 "bg-BG",
603 "uk-UA",
604 "be-BY",
605 "uz-Latn",
606 "kk-KZ",
607 "az-Cyrl-AZ",
608 "az-AZ",
609 "hy-AM",
610 "ka-GE",
613 "tg-TJ",
614 "tk-TM",
615 "mn-Mong",
616 "mn-MN",
617 "ps-AF",
618 "ku-Arab",
620 "sd-Arab",
621 "bo-CN",
622 "ne-NP",
623 "sa-IN",
624 "mr-IN",
625 "bn-IN",
626 "as-IN",
627 "gu-IN",
628 "pa-Arab",
629 "or-IN",
630 "ml-IN",
631 "kn-IN",
632 "ta-LK",
633 "te-IN",
634 "si-LK",
636 "km-KH",
637 "lo-LA",
638 "vi-VN",
639 "id-ID",
641 "ms-MY",
642 "ms-Arab",
643 "am-ET",
644 "ti-ET",
647 "sw-KE",
648 "rw-RW",
686 "cy-GB",
687 "eu-ES",
688 "ca-ES",
693 "tt-RU",
694 "ug-CN",
698 "gl-ES",
699 "af-ZA",
700 "br-FR",
701 "iu-Latn-CA",
702 "gd-GB",
704 "ga-IE",
707 "kl-GL",
708 "az-Latn"
711 enum OPENTYPE_STRING_ID
713 OPENTYPE_STRING_COPYRIGHT_NOTICE = 0,
714 OPENTYPE_STRING_FAMILY_NAME,
715 OPENTYPE_STRING_SUBFAMILY_NAME,
716 OPENTYPE_STRING_UNIQUE_IDENTIFIER,
717 OPENTYPE_STRING_FULL_FONTNAME,
718 OPENTYPE_STRING_VERSION_STRING,
719 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
720 OPENTYPE_STRING_TRADEMARK,
721 OPENTYPE_STRING_MANUFACTURER,
722 OPENTYPE_STRING_DESIGNER,
723 OPENTYPE_STRING_DESCRIPTION,
724 OPENTYPE_STRING_VENDOR_URL,
725 OPENTYPE_STRING_DESIGNER_URL,
726 OPENTYPE_STRING_LICENSE_DESCRIPTION,
727 OPENTYPE_STRING_LICENSE_INFO_URL,
728 OPENTYPE_STRING_RESERVED_ID15,
729 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
730 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
731 OPENTYPE_STRING_COMPATIBLE_FULLNAME,
732 OPENTYPE_STRING_SAMPLE_TEXT,
733 OPENTYPE_STRING_POSTSCRIPT_CID_NAME,
734 OPENTYPE_STRING_WWS_FAMILY_NAME,
735 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
738 static const UINT16 dwriteid_to_opentypeid[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1] =
740 (UINT16)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
741 OPENTYPE_STRING_COPYRIGHT_NOTICE,
742 OPENTYPE_STRING_VERSION_STRING,
743 OPENTYPE_STRING_TRADEMARK,
744 OPENTYPE_STRING_MANUFACTURER,
745 OPENTYPE_STRING_DESIGNER,
746 OPENTYPE_STRING_DESIGNER_URL,
747 OPENTYPE_STRING_DESCRIPTION,
748 OPENTYPE_STRING_VENDOR_URL,
749 OPENTYPE_STRING_LICENSE_DESCRIPTION,
750 OPENTYPE_STRING_LICENSE_INFO_URL,
751 OPENTYPE_STRING_FAMILY_NAME,
752 OPENTYPE_STRING_SUBFAMILY_NAME,
753 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
754 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
755 OPENTYPE_STRING_SAMPLE_TEXT,
756 OPENTYPE_STRING_FULL_FONTNAME,
757 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
758 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
761 /* CPAL table */
762 struct CPAL_Header_0
764 USHORT version;
765 USHORT numPaletteEntries;
766 USHORT numPalette;
767 USHORT numColorRecords;
768 ULONG offsetFirstColorRecord;
769 USHORT colorRecordIndices[1];
772 /* for version == 1, this comes after full CPAL_Header_0 */
773 struct CPAL_SubHeader_1
775 ULONG offsetPaletteTypeArray;
776 ULONG offsetPaletteLabelArray;
777 ULONG offsetPaletteEntryLabelArray;
780 struct CPAL_ColorRecord
782 BYTE blue;
783 BYTE green;
784 BYTE red;
785 BYTE alpha;
788 /* COLR table */
789 struct COLR_Header
791 USHORT version;
792 USHORT numBaseGlyphRecords;
793 ULONG offsetBaseGlyphRecord;
794 ULONG offsetLayerRecord;
795 USHORT numLayerRecords;
798 struct COLR_BaseGlyphRecord
800 USHORT GID;
801 USHORT firstLayerIndex;
802 USHORT numLayers;
805 struct COLR_LayerRecord
807 USHORT GID;
808 USHORT paletteIndex;
811 BOOL is_face_type_supported(DWRITE_FONT_FACE_TYPE type)
813 return (type == DWRITE_FONT_FACE_TYPE_CFF) ||
814 (type == DWRITE_FONT_FACE_TYPE_TRUETYPE) ||
815 (type == DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION) ||
816 (type == DWRITE_FONT_FACE_TYPE_RAW_CFF);
819 typedef HRESULT (*dwrite_fontfile_analyzer)(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
820 DWRITE_FONT_FACE_TYPE *face_type);
822 static HRESULT opentype_ttc_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
823 DWRITE_FONT_FACE_TYPE *face_type)
825 static const DWORD ttctag = MS_TTCF_TAG;
826 const TTC_Header_V1 *header;
827 void *context;
828 HRESULT hr;
830 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(header), &context);
831 if (FAILED(hr))
832 return hr;
834 if (!memcmp(header->TTCTag, &ttctag, sizeof(ttctag))) {
835 *font_count = GET_BE_DWORD(header->numFonts);
836 *file_type = DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION;
837 *face_type = DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION;
840 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
842 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
845 static HRESULT opentype_ttf_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
846 DWRITE_FONT_FACE_TYPE *face_type)
848 const DWORD *header;
849 void *context;
850 HRESULT hr;
852 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(*header), &context);
853 if (FAILED(hr))
854 return hr;
856 if (GET_BE_DWORD(*header) == 0x10000) {
857 *font_count = 1;
858 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
859 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
862 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
864 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
867 static HRESULT opentype_otf_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
868 DWRITE_FONT_FACE_TYPE *face_type)
870 const DWORD *header;
871 void *context;
872 HRESULT hr;
874 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(*header), &context);
875 if (FAILED(hr))
876 return hr;
878 if (GET_BE_DWORD(*header) == MS_OTTO_TAG) {
879 *font_count = 1;
880 *file_type = DWRITE_FONT_FILE_TYPE_CFF;
881 *face_type = DWRITE_FONT_FACE_TYPE_CFF;
884 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
886 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
889 static HRESULT opentype_type1_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
890 DWRITE_FONT_FACE_TYPE *face_type)
892 #include "pshpack1.h"
893 /* Specified in Adobe TechNote #5178 */
894 struct pfm_header {
895 WORD dfVersion;
896 DWORD dfSize;
897 char data0[95];
898 DWORD dfDevice;
899 char data1[12];
901 #include "poppack.h"
902 struct type1_header {
903 WORD tag;
904 char data[14];
906 const struct type1_header *header;
907 void *context;
908 HRESULT hr;
910 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&header, 0, sizeof(*header), &context);
911 if (FAILED(hr))
912 return hr;
914 /* tag is followed by plain text section */
915 if (header->tag == 0x8001 &&
916 (!memcmp(header->data, "%!PS-AdobeFont", 14) ||
917 !memcmp(header->data, "%!FontType", 10))) {
918 *font_count = 1;
919 *file_type = DWRITE_FONT_FILE_TYPE_TYPE1_PFB;
920 *face_type = DWRITE_FONT_FACE_TYPE_TYPE1;
923 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
925 /* let's see if it's a .pfm metrics file */
926 if (*file_type == DWRITE_FONT_FILE_TYPE_UNKNOWN) {
927 const struct pfm_header *pfm_header;
928 UINT64 filesize;
929 DWORD offset;
930 BOOL header_checked;
932 hr = IDWriteFontFileStream_GetFileSize(stream, &filesize);
933 if (FAILED(hr))
934 return hr;
936 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&pfm_header, 0, sizeof(*pfm_header), &context);
937 if (FAILED(hr))
938 return hr;
940 offset = pfm_header->dfDevice;
941 header_checked = pfm_header->dfVersion == 0x100 && pfm_header->dfSize == filesize;
942 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
944 /* as a last test check static string in PostScript information section */
945 if (header_checked) {
946 static const char postscript[] = "PostScript";
947 char *devtype_name;
949 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&devtype_name, offset, sizeof(postscript), &context);
950 if (FAILED(hr))
951 return hr;
953 if (!memcmp(devtype_name, postscript, sizeof(postscript))) {
954 *font_count = 1;
955 *file_type = DWRITE_FONT_FILE_TYPE_TYPE1_PFM;
956 *face_type = DWRITE_FONT_FACE_TYPE_TYPE1;
959 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
963 return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
966 HRESULT opentype_analyze_font(IDWriteFontFileStream *stream, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported)
968 static dwrite_fontfile_analyzer fontfile_analyzers[] = {
969 opentype_ttf_analyzer,
970 opentype_otf_analyzer,
971 opentype_ttc_analyzer,
972 opentype_type1_analyzer,
973 NULL
975 dwrite_fontfile_analyzer *analyzer = fontfile_analyzers;
976 DWRITE_FONT_FACE_TYPE face;
977 HRESULT hr;
979 if (!face_type)
980 face_type = &face;
982 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
983 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
984 *font_count = 0;
986 while (*analyzer) {
987 hr = (*analyzer)(stream, font_count, file_type, face_type);
988 if (FAILED(hr))
989 return hr;
991 if (hr == S_OK)
992 break;
994 analyzer++;
997 *supported = is_face_type_supported(*face_type);
998 return S_OK;
1001 HRESULT opentype_get_font_table(struct file_stream_desc *stream_desc, UINT32 tag, const void **table_data,
1002 void **table_context, UINT32 *table_size, BOOL *found)
1004 HRESULT hr;
1005 TTC_SFNT_V1 *font_header = NULL;
1006 void *sfnt_context;
1007 TT_TableRecord *table_record = NULL;
1008 void *table_record_context;
1009 int table_count, table_offset = 0;
1010 int i;
1012 if (found) *found = FALSE;
1013 if (table_size) *table_size = 0;
1015 *table_data = NULL;
1016 *table_context = NULL;
1018 if (stream_desc->face_type == DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION) {
1019 const TTC_Header_V1 *ttc_header;
1020 void * ttc_context;
1021 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context);
1022 if (SUCCEEDED(hr)) {
1023 if (stream_desc->face_index >= GET_BE_DWORD(ttc_header->numFonts))
1024 hr = E_INVALIDARG;
1025 else {
1026 table_offset = GET_BE_DWORD(ttc_header->OffsetTable[stream_desc->face_index]);
1027 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context);
1029 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, ttc_context);
1032 else
1033 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context);
1035 if (FAILED(hr))
1036 return hr;
1038 table_count = GET_BE_WORD(font_header->numTables);
1039 table_offset += sizeof(*font_header);
1040 for (i = 0; i < table_count; i++)
1042 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void**)&table_record, table_offset, sizeof(*table_record), &table_record_context);
1043 if (FAILED(hr))
1044 break;
1045 if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag)
1046 break;
1047 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, table_record_context);
1048 table_offset += sizeof(*table_record);
1051 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, sfnt_context);
1052 if (SUCCEEDED(hr) && i < table_count)
1054 int offset = GET_BE_DWORD(table_record->offset);
1055 int length = GET_BE_DWORD(table_record->length);
1056 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, table_record_context);
1058 if (found) *found = TRUE;
1059 if (table_size) *table_size = length;
1060 hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, table_data, offset, length, table_context);
1063 return hr;
1066 /**********
1067 * CMAP
1068 **********/
1070 static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table)
1072 UINT32 count = 0;
1073 int i;
1075 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) {
1076 WORD type;
1077 WORD *table;
1079 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
1080 continue;
1082 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
1083 type = GET_BE_WORD(*table);
1084 TRACE("table type %i\n", type);
1086 switch (type)
1088 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
1090 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
1091 count += GET_BE_WORD(format->segCountX2)/2;
1092 break;
1094 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
1096 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
1097 count += GET_BE_DWORD(format->nGroups);
1098 break;
1100 default:
1101 FIXME("table type %i unhandled.\n", type);
1105 return count;
1108 HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1110 CMAP_Header *CMAP_Table = data;
1111 int i, k = 0;
1113 if (!CMAP_Table)
1114 return E_FAIL;
1116 *count = opentype_cmap_get_unicode_ranges_count(CMAP_Table);
1118 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables) && k < max_count; i++)
1120 WORD type;
1121 WORD *table;
1122 int j;
1124 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
1125 continue;
1127 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
1128 type = GET_BE_WORD(*table);
1129 TRACE("table type %i\n", type);
1131 switch (type)
1133 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
1135 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
1136 UINT16 segment_count = GET_BE_WORD(format->segCountX2)/2;
1137 UINT16 *startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
1139 for (j = 0; j < segment_count && GET_BE_WORD(format->endCode[j]) < 0xffff && k < max_count; j++, k++) {
1140 ranges[k].first = GET_BE_WORD(startCode[j]);
1141 ranges[k].last = GET_BE_WORD(format->endCode[j]);
1143 break;
1145 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
1147 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
1148 for (j = 0; j < GET_BE_DWORD(format->nGroups) && k < max_count; j++, k++) {
1149 ranges[k].first = GET_BE_DWORD(format->groups[j].startCharCode);
1150 ranges[k].last = GET_BE_DWORD(format->groups[j].endCharCode);
1152 break;
1154 default:
1155 FIXME("table type %i unhandled.\n", type);
1159 return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK;
1162 void opentype_get_font_metrics(struct file_stream_desc *stream_desc, DWRITE_FONT_METRICS1 *metrics, DWRITE_CARET_METRICS *caret)
1164 void *os2_context, *head_context, *post_context, *hhea_context;
1165 const TT_OS2_V2 *tt_os2;
1166 const TT_HEAD *tt_head;
1167 const TT_POST *tt_post;
1168 const TT_HHEA *tt_hhea;
1170 memset(metrics, 0, sizeof(*metrics));
1172 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1173 opentype_get_font_table(stream_desc, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
1174 opentype_get_font_table(stream_desc, MS_POST_TAG, (const void**)&tt_post, &post_context, NULL, NULL);
1175 opentype_get_font_table(stream_desc, MS_HHEA_TAG, (const void**)&tt_hhea, &hhea_context, NULL, NULL);
1177 if (tt_head) {
1178 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
1179 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
1180 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
1181 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
1182 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
1185 if (caret) {
1186 if (tt_hhea) {
1187 caret->slopeRise = GET_BE_WORD(tt_hhea->caretSlopeRise);
1188 caret->slopeRun = GET_BE_WORD(tt_hhea->caretSlopeRun);
1189 caret->offset = GET_BE_WORD(tt_hhea->caretOffset);
1191 else {
1192 caret->slopeRise = 0;
1193 caret->slopeRun = 0;
1194 caret->offset = 0;
1198 if (tt_os2) {
1199 USHORT version = GET_BE_WORD(tt_os2->version);
1201 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
1202 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
1203 interpreted as large unsigned value. */
1204 metrics->descent = abs((SHORT)GET_BE_WORD(tt_os2->usWinDescent));
1206 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
1207 if (tt_hhea) {
1208 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
1209 INT32 linegap;
1211 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
1212 metrics->ascent - metrics->descent;
1213 metrics->lineGap = linegap > 0 ? linegap : 0;
1216 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
1217 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
1218 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
1219 /* Y offset is stored as positive offset below baseline */
1220 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
1221 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
1222 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
1223 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
1224 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
1225 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
1226 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
1228 /* version 2 fields */
1229 if (version >= 2) {
1230 metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight);
1231 metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight);
1234 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
1235 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
1236 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
1237 metrics->descent = descent < 0 ? -descent : 0;
1238 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
1239 metrics->hasTypographicMetrics = TRUE;
1243 if (tt_post) {
1244 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
1245 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
1248 if (metrics->underlineThickness == 0)
1249 metrics->underlineThickness = metrics->designUnitsPerEm / 14;
1250 if (metrics->strikethroughThickness == 0)
1251 metrics->strikethroughThickness = metrics->underlineThickness;
1253 /* estimate missing metrics */
1254 if (metrics->xHeight == 0)
1255 metrics->xHeight = metrics->designUnitsPerEm / 2;
1256 if (metrics->capHeight == 0)
1257 metrics->capHeight = metrics->designUnitsPerEm * 7 / 10;
1259 if (tt_os2)
1260 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1261 if (tt_head)
1262 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, head_context);
1263 if (tt_post)
1264 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, post_context);
1265 if (tt_hhea)
1266 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, hhea_context);
1269 void opentype_get_font_properties(struct file_stream_desc *stream_desc, struct dwrite_font_props *props)
1271 void *os2_context, *head_context;
1272 const TT_OS2_V2 *tt_os2;
1273 const TT_HEAD *tt_head;
1275 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1276 opentype_get_font_table(stream_desc, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
1278 /* default stretch, weight and style to normal */
1279 props->stretch = DWRITE_FONT_STRETCH_NORMAL;
1280 props->weight = DWRITE_FONT_WEIGHT_NORMAL;
1281 props->style = DWRITE_FONT_STYLE_NORMAL;
1282 memset(&props->panose, 0, sizeof(props->panose));
1283 memset(&props->lf, 0, sizeof(props->lf));
1285 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1286 if (tt_os2) {
1287 USHORT version = GET_BE_WORD(tt_os2->version);
1288 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
1289 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
1290 USHORT usWidthClass = GET_BE_WORD(tt_os2->usWidthClass);
1292 if (usWidthClass > DWRITE_FONT_STRETCH_UNDEFINED && usWidthClass <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
1293 props->stretch = usWidthClass;
1295 if (usWeightClass >= 1 && usWeightClass <= 9)
1296 usWeightClass *= 100;
1298 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
1299 props->weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
1300 else if (usWeightClass > 0)
1301 props->weight = usWeightClass;
1303 if (version >= 4 && (fsSelection & OS2_FSSELECTION_OBLIQUE))
1304 props->style = DWRITE_FONT_STYLE_OBLIQUE;
1305 else if (fsSelection & OS2_FSSELECTION_ITALIC)
1306 props->style = DWRITE_FONT_STYLE_ITALIC;
1308 memcpy(&props->panose, &tt_os2->panose, sizeof(props->panose));
1310 else if (tt_head) {
1311 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
1313 if (macStyle & TT_HEAD_MACSTYLE_CONDENSED)
1314 props->stretch = DWRITE_FONT_STRETCH_CONDENSED;
1315 else if (macStyle & TT_HEAD_MACSTYLE_EXTENDED)
1316 props->stretch = DWRITE_FONT_STRETCH_EXPANDED;
1318 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
1319 props->weight = DWRITE_FONT_WEIGHT_BOLD;
1321 if (macStyle & TT_HEAD_MACSTYLE_ITALIC)
1322 props->style = DWRITE_FONT_STYLE_ITALIC;
1325 props->lf.lfWeight = props->weight;
1326 props->lf.lfItalic = 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, WCHAR *lfname, IDWriteLocalizedStrings **names)
1612 IDWriteLocalizedStrings *lfnames;
1613 void *os2_context, *name_context;
1614 const TT_OS2_V2 *tt_os2;
1615 const void *name_table;
1616 HRESULT hr;
1618 opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1619 opentype_get_font_table(stream_desc, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1621 *names = NULL;
1623 /* if Preferred Family doesn't conform to WWS model try WWS name */
1624 if (tt_os2 && !(GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_WWS))
1625 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_SUBFAMILY_NAME, names);
1626 else
1627 hr = E_FAIL;
1629 if (FAILED(hr))
1630 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME, names);
1631 if (FAILED(hr))
1632 hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_SUBFAMILY_NAME, names);
1634 /* User locale is preferred, with fallback to en-us. */
1635 *lfname = 0;
1636 if (SUCCEEDED(opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, &lfnames))) {
1637 static const WCHAR enusW[] = {'e','n','-','u','s',0};
1638 WCHAR localeW[LOCALE_NAME_MAX_LENGTH];
1639 UINT32 index;
1640 BOOL exists;
1642 exists = FALSE;
1643 if (GetSystemDefaultLocaleName(localeW, sizeof(localeW)/sizeof(WCHAR)))
1644 IDWriteLocalizedStrings_FindLocaleName(lfnames, localeW, &index, &exists);
1646 if (!exists)
1647 IDWriteLocalizedStrings_FindLocaleName(lfnames, enusW, &index, &exists);
1649 if (exists)
1650 IDWriteLocalizedStrings_GetString(lfnames, index, lfname, LF_FACESIZE);
1652 IDWriteLocalizedStrings_Release(lfnames);
1655 if (tt_os2)
1656 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1657 if (name_context)
1658 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name_context);
1660 return hr;
1663 static inline const OT_Script *opentype_get_script(const OT_ScriptList *scriptlist, UINT32 scripttag)
1665 UINT16 j;
1667 for (j = 0; j < GET_BE_WORD(scriptlist->ScriptCount); j++) {
1668 const char *tag = scriptlist->ScriptRecord[j].ScriptTag;
1669 if (scripttag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1670 return (OT_Script*)((BYTE*)scriptlist + GET_BE_WORD(scriptlist->ScriptRecord[j].Script));
1673 return NULL;
1676 static inline const OT_LangSys *opentype_get_langsys(const OT_Script *script, UINT32 languagetag)
1678 UINT16 j;
1680 for (j = 0; j < GET_BE_WORD(script->LangSysCount); j++) {
1681 const char *tag = script->LangSysRecord[j].LangSysTag;
1682 if (languagetag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
1683 return (OT_LangSys*)((BYTE*)script + GET_BE_WORD(script->LangSysRecord[j].LangSys));
1686 return NULL;
1689 static void opentype_add_font_features(const GPOS_GSUB_Header *header, const OT_LangSys *langsys,
1690 UINT32 max_tagcount, UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1692 const OT_FeatureList *features = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
1693 UINT16 j;
1695 for (j = 0; j < GET_BE_WORD(langsys->FeatureCount); j++) {
1696 const OT_FeatureRecord *feature = &features->FeatureRecord[langsys->FeatureIndex[j]];
1697 const char *tag = feature->FeatureTag;
1699 if (*count < max_tagcount)
1700 tags[*count] = DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]);
1702 (*count)++;
1706 HRESULT opentype_get_typographic_features(IDWriteFontFace *fontface, UINT32 scripttag, UINT32 languagetag, UINT32 max_tagcount,
1707 UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
1709 UINT32 tables[2] = { MS_GSUB_TAG, MS_GPOS_TAG };
1710 HRESULT hr;
1711 UINT8 i;
1713 *count = 0;
1714 for (i = 0; i < sizeof(tables)/sizeof(tables[0]); i++) {
1715 const OT_ScriptList *scriptlist;
1716 const GPOS_GSUB_Header *header;
1717 const OT_Script *script;
1718 const void *ptr;
1719 void *context;
1720 UINT32 size;
1721 BOOL exists;
1723 exists = FALSE;
1724 hr = IDWriteFontFace_TryGetFontTable(fontface, tables[i], &ptr, &size, &context, &exists);
1725 if (FAILED(hr))
1726 return hr;
1728 if (!exists)
1729 continue;
1731 header = (const GPOS_GSUB_Header*)ptr;
1732 scriptlist = (const OT_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
1734 script = opentype_get_script(scriptlist, scripttag);
1735 if (script) {
1736 const OT_LangSys *langsys = opentype_get_langsys(script, languagetag);
1737 if (langsys)
1738 opentype_add_font_features(header, langsys, max_tagcount, count, tags);
1741 IDWriteFontFace_ReleaseFontTable(fontface, context);
1744 return *count > max_tagcount ? E_NOT_SUFFICIENT_BUFFER : S_OK;
1747 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
1749 WORD num_ratios, i, group_offset = 0;
1750 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
1751 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
1753 num_ratios = GET_BE_WORD(hdr->numRatios);
1755 for (i = 0; i < num_ratios; i++) {
1757 if (!ratios[i].bCharSet) continue;
1759 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
1760 ratios[i].yEndRatio == 0) ||
1761 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
1762 ratios[i].yEndRatio >= dev_y_ratio))
1764 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
1765 break;
1768 if (group_offset)
1769 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
1770 return NULL;
1773 BOOL opentype_get_vdmx_size(const void *data, INT emsize, UINT16 *ascent, UINT16 *descent)
1775 const struct VDMX_Header *hdr = (const struct VDMX_Header*)data;
1776 const struct VDMX_group *group;
1777 const struct VDMX_vTable *tables;
1778 WORD recs, i;
1780 if (!data)
1781 return FALSE;
1783 group = find_vdmx_group(hdr);
1784 if (!group)
1785 return FALSE;
1787 recs = GET_BE_WORD(group->recs);
1788 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
1790 tables = (const struct VDMX_vTable *)(group + 1);
1791 for (i = 0; i < recs; i++) {
1792 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
1793 if (ppem > emsize) {
1794 FIXME("interpolate %d\n", emsize);
1795 return FALSE;
1798 if (ppem == emsize) {
1799 *ascent = (SHORT)GET_BE_WORD(tables[i].yMax);
1800 *descent = -(SHORT)GET_BE_WORD(tables[i].yMin);
1801 return TRUE;
1804 return FALSE;
1807 WORD opentype_get_gasp_flags(const WORD *ptr, UINT32 size, INT emsize)
1809 WORD num_recs, version;
1810 WORD flags = 0;
1812 if (!ptr)
1813 return 0;
1815 version = GET_BE_WORD( *ptr++ );
1816 num_recs = GET_BE_WORD( *ptr++ );
1817 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
1818 ERR("unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
1819 goto done;
1822 while (num_recs--) {
1823 flags = GET_BE_WORD( *(ptr + 1) );
1824 if (emsize <= GET_BE_WORD( *ptr )) break;
1825 ptr += 2;
1828 done:
1829 return flags;
1832 UINT32 opentype_get_cpal_palettecount(const void *cpal)
1834 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1835 return header ? GET_BE_WORD(header->numPalette) : 0;
1838 UINT32 opentype_get_cpal_paletteentrycount(const void *cpal)
1840 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1841 return header ? GET_BE_WORD(header->numPaletteEntries) : 0;
1844 HRESULT opentype_get_cpal_entries(const void *cpal, UINT32 palette, UINT32 first_entry_index, UINT32 entry_count,
1845 DWRITE_COLOR_F *entries)
1847 const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal;
1848 const struct CPAL_ColorRecord *records;
1849 UINT32 palettecount, entrycount, i;
1851 if (!header) return DWRITE_E_NOCOLOR;
1853 palettecount = GET_BE_WORD(header->numPalette);
1854 if (palette >= palettecount)
1855 return DWRITE_E_NOCOLOR;
1857 entrycount = GET_BE_WORD(header->numPaletteEntries);
1858 if (first_entry_index + entry_count > entrycount)
1859 return E_INVALIDARG;
1861 records = (const struct CPAL_ColorRecord*)((BYTE*)cpal + GET_BE_DWORD(header->offsetFirstColorRecord));
1862 first_entry_index += GET_BE_WORD(header->colorRecordIndices[palette]);
1864 for (i = 0; i < entry_count; i++) {
1865 entries[i].r = records[first_entry_index + i].red / 255.0f;
1866 entries[i].g = records[first_entry_index + i].green / 255.0f;
1867 entries[i].b = records[first_entry_index + i].blue / 255.0f;
1868 entries[i].a = records[first_entry_index + i].alpha / 255.0f;
1871 return S_OK;
1874 static int colr_compare_gid(const void *g, const void *r)
1876 const struct COLR_BaseGlyphRecord *record = r;
1877 UINT16 glyph = *(UINT16*)g, GID = GET_BE_WORD(record->GID);
1878 int ret = 0;
1880 if (glyph > GID)
1881 ret = 1;
1882 else if (glyph < GID)
1883 ret = -1;
1885 return ret;
1888 HRESULT opentype_get_colr_glyph(const void *colr, UINT16 glyph, struct dwrite_colorglyph *ret)
1890 const struct COLR_BaseGlyphRecord *record;
1891 const struct COLR_Header *header = colr;
1892 const struct COLR_LayerRecord *layer;
1893 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
1894 DWORD baserecordoffset = GET_BE_DWORD(header->offsetBaseGlyphRecord);
1895 WORD numbaserecords = GET_BE_WORD(header->numBaseGlyphRecords);
1897 record = bsearch(&glyph, (BYTE*)colr + baserecordoffset, numbaserecords, sizeof(struct COLR_BaseGlyphRecord),
1898 colr_compare_gid);
1899 if (!record) {
1900 ret->layer = 0;
1901 ret->first_layer = 0;
1902 ret->num_layers = 0;
1903 ret->glyph = glyph;
1904 ret->palette_index = 0xffff;
1905 return S_FALSE;
1908 ret->layer = 0;
1909 ret->first_layer = GET_BE_WORD(record->firstLayerIndex);
1910 ret->num_layers = GET_BE_WORD(record->numLayers);
1912 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + ret->first_layer + ret->layer;
1913 ret->glyph = GET_BE_WORD(layer->GID);
1914 ret->palette_index = GET_BE_WORD(layer->paletteIndex);
1916 return S_OK;
1919 void opentype_colr_next_glyph(const void *colr, struct dwrite_colorglyph *glyph)
1921 const struct COLR_Header *header = colr;
1922 const struct COLR_LayerRecord *layer;
1923 DWORD layerrecordoffset = GET_BE_DWORD(header->offsetLayerRecord);
1925 /* iterated all the way through */
1926 if (glyph->layer == glyph->num_layers)
1927 return;
1929 glyph->layer++;
1930 layer = (struct COLR_LayerRecord*)((BYTE*)colr + layerrecordoffset) + glyph->first_layer + glyph->layer;
1931 glyph->glyph = GET_BE_WORD(layer->GID);
1932 glyph->palette_index = GET_BE_WORD(layer->paletteIndex);
1935 HRESULT opentype_get_font_signature(struct file_stream_desc *stream_desc, FONTSIGNATURE *fontsig)
1937 const TT_OS2_V2 *tt_os2;
1938 void *os2_context;
1939 HRESULT hr;
1941 hr = opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
1942 if (tt_os2) {
1943 fontsig->fsUsb[0] = GET_BE_DWORD(tt_os2->ulUnicodeRange1);
1944 fontsig->fsUsb[1] = GET_BE_DWORD(tt_os2->ulUnicodeRange2);
1945 fontsig->fsUsb[2] = GET_BE_DWORD(tt_os2->ulUnicodeRange3);
1946 fontsig->fsUsb[3] = GET_BE_DWORD(tt_os2->ulUnicodeRange4);
1948 if (GET_BE_WORD(tt_os2->version) == 0) {
1949 fontsig->fsCsb[0] = 0;
1950 fontsig->fsCsb[1] = 0;
1952 else {
1953 fontsig->fsCsb[0] = GET_BE_DWORD(tt_os2->ulCodePageRange1);
1954 fontsig->fsCsb[1] = GET_BE_DWORD(tt_os2->ulCodePageRange2);
1957 IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2_context);
1960 return hr;
1963 BOOL opentype_has_vertical_variants(IDWriteFontFace4 *fontface)
1965 const OT_FeatureList *featurelist;
1966 const OT_LookupList *lookup_list;
1967 BOOL exists = FALSE, ret = FALSE;
1968 const GPOS_GSUB_Header *header;
1969 const void *data;
1970 void *context;
1971 UINT32 size;
1972 HRESULT hr;
1973 UINT16 i;
1975 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
1976 if (FAILED(hr) || !exists)
1977 return FALSE;
1979 header = data;
1980 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
1981 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
1983 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
1984 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
1985 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
1986 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
1987 const GSUB_SingleSubstFormat2 *subst2;
1988 const OT_LookupTable *lookup_table;
1989 UINT32 offset;
1991 if (lookup_count == 0)
1992 continue;
1994 for (i = 0; i < lookup_count; i++) {
1995 /* check if lookup is empty */
1996 index = GET_BE_WORD(feature->LookupListIndex[i]);
1997 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
1999 type = GET_BE_WORD(lookup_table->LookupType);
2000 if (type != OPENTYPE_GPOS_SINGLE_SUBST && type != OPENTYPE_GPOS_EXTENSION_SUBST)
2001 continue;
2003 count = GET_BE_WORD(lookup_table->SubTableCount);
2004 if (count == 0)
2005 continue;
2007 offset = GET_BE_WORD(lookup_table->SubTable[0]);
2008 if (type == OPENTYPE_GPOS_EXTENSION_SUBST) {
2009 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
2010 if (GET_BE_WORD(ext->SubstFormat) == 1)
2011 offset += GET_BE_DWORD(ext->ExtensionOffset);
2012 else
2013 FIXME("Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
2016 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
2017 index = GET_BE_WORD(subst2->SubstFormat);
2018 if (index == 1)
2019 FIXME("Validate Single Substitution Format 1\n");
2020 else if (index == 2) {
2021 /* SimSun-ExtB has 0 glyph count for this substitution */
2022 if (GET_BE_WORD(subst2->GlyphCount) > 0) {
2023 ret = TRUE;
2024 break;
2027 else
2028 WARN("Unknown Single Substitution Format, %u\n", index);
2033 IDWriteFontFace4_ReleaseFontTable(fontface, context);
2035 return ret;