winemac: Ignore Cocoa child windows which aren't instances of WineWindow.
[wine.git] / dlls / dwrite / opentype.c
blob9cee281472eddc52c3fcc3713335c6811e92a62d
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"
25 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
27 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
28 #define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
29 #define MS_OTTO_TAG DWRITE_MAKE_OPENTYPE_TAG('O','T','T','O')
30 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
31 #define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
32 #define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f')
34 #ifdef WORDS_BIGENDIAN
35 #define GET_BE_WORD(x) (x)
36 #define GET_BE_DWORD(x) (x)
37 #else
38 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
39 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)))
40 #endif
42 typedef struct {
43 CHAR TTCTag[4];
44 DWORD Version;
45 DWORD numFonts;
46 DWORD OffsetTable[1];
47 } TTC_Header_V1;
49 typedef struct {
50 DWORD version;
51 WORD numTables;
52 WORD searchRange;
53 WORD entrySelector;
54 WORD rangeShift;
55 } TTC_SFNT_V1;
57 typedef struct {
58 CHAR tag[4];
59 DWORD checkSum;
60 DWORD offset;
61 DWORD length;
62 } TT_TableRecord;
64 typedef struct {
65 WORD platformID;
66 WORD encodingID;
67 DWORD offset;
68 } CMAP_EncodingRecord;
70 typedef struct {
71 WORD version;
72 WORD numTables;
73 CMAP_EncodingRecord tables[1];
74 } CMAP_Header;
76 typedef struct {
77 DWORD startCharCode;
78 DWORD endCharCode;
79 DWORD startGlyphID;
80 } CMAP_SegmentedCoverage_group;
82 typedef struct {
83 WORD format;
84 WORD reserved;
85 DWORD length;
86 DWORD language;
87 DWORD nGroups;
88 CMAP_SegmentedCoverage_group groups[1];
89 } CMAP_SegmentedCoverage;
91 typedef struct {
92 WORD format;
93 WORD length;
94 WORD language;
95 WORD segCountX2;
96 WORD searchRange;
97 WORD entrySelector;
98 WORD rangeShift;
99 WORD endCode[1];
100 } CMAP_SegmentMapping_0;
102 enum OPENTYPE_CMAP_TABLE_FORMAT
104 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING = 4,
105 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE = 12
108 /* PANOSE is 10 bytes in size, need to pack the structure properly */
109 #include "pshpack2.h"
110 typedef struct
112 ULONG version;
113 ULONG revision;
114 ULONG checksumadj;
115 ULONG magic;
116 USHORT flags;
117 USHORT unitsPerEm;
118 ULONGLONG created;
119 ULONGLONG modified;
120 SHORT xMin;
121 SHORT yMin;
122 SHORT xMax;
123 SHORT yMax;
124 USHORT macStyle;
125 USHORT lowestRecPPEM;
126 SHORT direction_hint;
127 SHORT index_format;
128 SHORT glyphdata_format;
129 } TT_HEAD;
131 typedef struct
133 ULONG Version;
134 ULONG italicAngle;
135 SHORT underlinePosition;
136 SHORT underlineThickness;
137 ULONG fixed_pitch;
138 ULONG minmemType42;
139 ULONG maxmemType42;
140 ULONG minmemType1;
141 ULONG maxmemType1;
142 } TT_POST;
144 typedef struct
146 USHORT version;
147 SHORT xAvgCharWidth;
148 USHORT usWeightClass;
149 USHORT usWidthClass;
150 SHORT fsType;
151 SHORT ySubscriptXSize;
152 SHORT ySubscriptYSize;
153 SHORT ySubscriptXOffset;
154 SHORT ySubscriptYOffset;
155 SHORT ySuperscriptXSize;
156 SHORT ySuperscriptYSize;
157 SHORT ySuperscriptXOffset;
158 SHORT ySuperscriptYOffset;
159 SHORT yStrikeoutSize;
160 SHORT yStrikeoutPosition;
161 SHORT sFamilyClass;
162 PANOSE panose;
163 ULONG ulUnicodeRange1;
164 ULONG ulUnicodeRange2;
165 ULONG ulUnicodeRange3;
166 ULONG ulUnicodeRange4;
167 CHAR achVendID[4];
168 USHORT fsSelection;
169 USHORT usFirstCharIndex;
170 USHORT usLastCharIndex;
171 /* According to the Apple spec, original version didn't have the below fields,
172 * version numbers were taken from the OpenType spec.
174 /* version 0 (TrueType 1.5) */
175 USHORT sTypoAscender;
176 USHORT sTypoDescender;
177 USHORT sTypoLineGap;
178 USHORT usWinAscent;
179 USHORT usWinDescent;
180 /* version 1 (TrueType 1.66) */
181 ULONG ulCodePageRange1;
182 ULONG ulCodePageRange2;
183 /* version 2 (OpenType 1.2) */
184 SHORT sxHeight;
185 SHORT sCapHeight;
186 USHORT usDefaultChar;
187 USHORT usBreakChar;
188 USHORT usMaxContext;
189 } TT_OS2_V2;
191 typedef struct {
192 ULONG version;
193 SHORT ascender;
194 SHORT descender;
195 SHORT linegap;
196 USHORT advanceWidthMax;
197 SHORT minLeftSideBearing;
198 SHORT minRightSideBearing;
199 SHORT xMaxExtent;
200 SHORT caretSlopeRise;
201 SHORT caretSlopeRun;
202 SHORT caretOffset;
203 SHORT reserved[4];
204 SHORT metricDataFormat;
205 USHORT numberOfHMetrics;
206 } TT_HHEA;
208 #include "poppack.h"
210 enum OS2_FSSELECTION {
211 OS2_FSSELECTION_ITALIC = 1 << 0,
212 OS2_FSSELECTION_UNDERSCORE = 1 << 1,
213 OS2_FSSELECTION_NEGATIVE = 1 << 2,
214 OS2_FSSELECTION_OUTLINED = 1 << 3,
215 OS2_FSSELECTION_STRIKEOUT = 1 << 4,
216 OS2_FSSELECTION_BOLD = 1 << 5,
217 OS2_FSSELECTION_REGULAR = 1 << 6,
218 OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7,
219 OS2_FSSELECTION_WWS = 1 << 8,
220 OS2_FSSELECTION_OBLIQUE = 1 << 9
223 typedef struct {
224 WORD platformID;
225 WORD encodingID;
226 WORD languageID;
227 WORD nameID;
228 WORD length;
229 WORD offset;
230 } TT_NameRecord;
232 typedef struct {
233 WORD format;
234 WORD count;
235 WORD stringOffset;
236 TT_NameRecord nameRecord[1];
237 } TT_NAME_V0;
239 enum OPENTYPE_PLATFORM_ID
241 OPENTYPE_PLATFORM_UNICODE = 0,
242 OPENTYPE_PLATFORM_MAC,
243 OPENTYPE_PLATFORM_ISO,
244 OPENTYPE_PLATFORM_WIN,
245 OPENTYPE_PLATFORM_CUSTOM
248 enum TT_NAME_WINDOWS_ENCODING_ID
250 TT_NAME_WINDOWS_ENCODING_SYMBOL = 0,
251 TT_NAME_WINDOWS_ENCODING_UCS2,
252 TT_NAME_WINDOWS_ENCODING_SJIS,
253 TT_NAME_WINDOWS_ENCODING_PRC,
254 TT_NAME_WINDOWS_ENCODING_BIG5,
255 TT_NAME_WINDOWS_ENCODING_WANSUNG,
256 TT_NAME_WINDOWS_ENCODING_JOHAB,
257 TT_NAME_WINDOWS_ENCODING_RESERVED1,
258 TT_NAME_WINDOWS_ENCODING_RESERVED2,
259 TT_NAME_WINDOWS_ENCODING_RESERVED3,
260 TT_NAME_WINDOWS_ENCODING_UCS4
263 enum TT_NAME_MAC_ENCODING_ID
265 TT_NAME_MAC_ENCODING_ROMAN = 0,
266 TT_NAME_MAC_ENCODING_JAPANESE,
267 TT_NAME_MAC_ENCODING_TRAD_CHINESE,
268 TT_NAME_MAC_ENCODING_KOREAN,
269 TT_NAME_MAC_ENCODING_ARABIC,
270 TT_NAME_MAC_ENCODING_HEBREW,
271 TT_NAME_MAC_ENCODING_GREEK,
272 TT_NAME_MAC_ENCODING_RUSSIAN,
273 TT_NAME_MAC_ENCODING_RSYMBOL,
274 TT_NAME_MAC_ENCODING_DEVANAGARI,
275 TT_NAME_MAC_ENCODING_GURMUKHI,
276 TT_NAME_MAC_ENCODING_GUJARATI,
277 TT_NAME_MAC_ENCODING_ORIYA,
278 TT_NAME_MAC_ENCODING_BENGALI,
279 TT_NAME_MAC_ENCODING_TAMIL,
280 TT_NAME_MAC_ENCODING_TELUGU,
281 TT_NAME_MAC_ENCODING_KANNADA,
282 TT_NAME_MAC_ENCODING_MALAYALAM,
283 TT_NAME_MAC_ENCODING_SINHALESE,
284 TT_NAME_MAC_ENCODING_BURMESE,
285 TT_NAME_MAC_ENCODING_KHMER,
286 TT_NAME_MAC_ENCODING_THAI,
287 TT_NAME_MAC_ENCODING_LAOTIAN,
288 TT_NAME_MAC_ENCODING_GEORGIAN,
289 TT_NAME_MAC_ENCODING_ARMENIAN,
290 TT_NAME_MAC_ENCODING_SIMPL_CHINESE,
291 TT_NAME_MAC_ENCODING_TIBETAN,
292 TT_NAME_MAC_ENCODING_MONGOLIAN,
293 TT_NAME_MAC_ENCODING_GEEZ,
294 TT_NAME_MAC_ENCODING_SLAVIC,
295 TT_NAME_MAC_ENCODING_VIETNAMESE,
296 TT_NAME_MAC_ENCODING_SINDHI,
297 TT_NAME_MAC_ENCODING_UNINTERPRETED
300 enum TT_NAME_MAC_LANGUAGE_ID
302 TT_NAME_MAC_LANGID_ENGLISH = 0,
303 TT_NAME_MAC_LANGID_FRENCH,
304 TT_NAME_MAC_LANGID_GERMAN,
305 TT_NAME_MAC_LANGID_ITALIAN,
306 TT_NAME_MAC_LANGID_DUTCH,
307 TT_NAME_MAC_LANGID_SWEDISH,
308 TT_NAME_MAC_LANGID_SPANISH,
309 TT_NAME_MAC_LANGID_DANISH,
310 TT_NAME_MAC_LANGID_PORTUGUESE,
311 TT_NAME_MAC_LANGID_NORWEGIAN,
312 TT_NAME_MAC_LANGID_HEBREW,
313 TT_NAME_MAC_LANGID_JAPANESE,
314 TT_NAME_MAC_LANGID_ARABIC,
315 TT_NAME_MAC_LANGID_FINNISH,
316 TT_NAME_MAC_LANGID_GREEK,
317 TT_NAME_MAC_LANGID_ICELANDIC,
318 TT_NAME_MAC_LANGID_MALTESE,
319 TT_NAME_MAC_LANGID_TURKISH,
320 TT_NAME_MAC_LANGID_CROATIAN,
321 TT_NAME_MAC_LANGID_TRAD_CHINESE,
322 TT_NAME_MAC_LANGID_URDU,
323 TT_NAME_MAC_LANGID_HINDI,
324 TT_NAME_MAC_LANGID_THAI,
325 TT_NAME_MAC_LANGID_KOREAN,
326 TT_NAME_MAC_LANGID_LITHUANIAN,
327 TT_NAME_MAC_LANGID_POLISH,
328 TT_NAME_MAC_LANGID_HUNGARIAN,
329 TT_NAME_MAC_LANGID_ESTONIAN,
330 TT_NAME_MAC_LANGID_LATVIAN,
331 TT_NAME_MAC_LANGID_SAMI,
332 TT_NAME_MAC_LANGID_FAROESE,
333 TT_NAME_MAC_LANGID_FARSI,
334 TT_NAME_MAC_LANGID_RUSSIAN,
335 TT_NAME_MAC_LANGID_SIMPL_CHINESE,
336 TT_NAME_MAC_LANGID_FLEMISH,
337 TT_NAME_MAC_LANGID_GAELIC,
338 TT_NAME_MAC_LANGID_ALBANIAN,
339 TT_NAME_MAC_LANGID_ROMANIAN,
340 TT_NAME_MAC_LANGID_CZECH,
341 TT_NAME_MAC_LANGID_SLOVAK,
342 TT_NAME_MAC_LANGID_SLOVENIAN,
343 TT_NAME_MAC_LANGID_YIDDISH,
344 TT_NAME_MAC_LANGID_SERBIAN,
345 TT_NAME_MAC_LANGID_MACEDONIAN,
346 TT_NAME_MAC_LANGID_BULGARIAN,
347 TT_NAME_MAC_LANGID_UKRAINIAN,
348 TT_NAME_MAC_LANGID_BYELORUSSIAN,
349 TT_NAME_MAC_LANGID_UZBEK,
350 TT_NAME_MAC_LANGID_KAZAKH,
351 TT_NAME_MAC_LANGID_AZERB_CYR,
352 TT_NAME_MAC_LANGID_AZERB_ARABIC,
353 TT_NAME_MAC_LANGID_ARMENIAN,
354 TT_NAME_MAC_LANGID_GEORGIAN,
355 TT_NAME_MAC_LANGID_MOLDAVIAN,
356 TT_NAME_MAC_LANGID_KIRGHIZ,
357 TT_NAME_MAC_LANGID_TAJIKI,
358 TT_NAME_MAC_LANGID_TURKMEN,
359 TT_NAME_MAC_LANGID_MONGOLIAN,
360 TT_NAME_MAC_LANGID_MONGOLIAN_CYR,
361 TT_NAME_MAC_LANGID_PASHTO,
362 TT_NAME_MAC_LANGID_KURDISH,
363 TT_NAME_MAC_LANGID_KASHMIRI,
364 TT_NAME_MAC_LANGID_SINDHI,
365 TT_NAME_MAC_LANGID_TIBETAN,
366 TT_NAME_MAC_LANGID_NEPALI,
367 TT_NAME_MAC_LANGID_SANSKRIT,
368 TT_NAME_MAC_LANGID_MARATHI,
369 TT_NAME_MAC_LANGID_BENGALI,
370 TT_NAME_MAC_LANGID_ASSAMESE,
371 TT_NAME_MAC_LANGID_GUJARATI,
372 TT_NAME_MAC_LANGID_PUNJABI,
373 TT_NAME_MAC_LANGID_ORIYA,
374 TT_NAME_MAC_LANGID_MALAYALAM,
375 TT_NAME_MAC_LANGID_KANNADA,
376 TT_NAME_MAC_LANGID_TAMIL,
377 TT_NAME_MAC_LANGID_TELUGU,
378 TT_NAME_MAC_LANGID_SINHALESE,
379 TT_NAME_MAC_LANGID_BURMESE,
380 TT_NAME_MAC_LANGID_KHMER,
381 TT_NAME_MAC_LANGID_LAO,
382 TT_NAME_MAC_LANGID_VIETNAMESE,
383 TT_NAME_MAC_LANGID_INDONESIAN,
384 TT_NAME_MAC_LANGID_TAGALONG,
385 TT_NAME_MAC_LANGID_MALAY_ROMAN,
386 TT_NAME_MAC_LANGID_MALAY_ARABIC,
387 TT_NAME_MAC_LANGID_AMHARIC,
388 TT_NAME_MAC_LANGID_TIGRINYA,
389 TT_NAME_MAC_LANGID_GALLA,
390 TT_NAME_MAC_LANGID_SOMALI,
391 TT_NAME_MAC_LANGID_SWAHILI,
392 TT_NAME_MAC_LANGID_KINYARWANDA,
393 TT_NAME_MAC_LANGID_RUNDI,
394 TT_NAME_MAC_LANGID_NYANJA,
395 TT_NAME_MAC_LANGID_MALAGASY,
396 TT_NAME_MAC_LANGID_ESPERANTO,
397 TT_NAME_MAC_LANGID_WELSH,
398 TT_NAME_MAC_LANGID_BASQUE,
399 TT_NAME_MAC_LANGID_CATALAN,
400 TT_NAME_MAC_LANGID_LATIN,
401 TT_NAME_MAC_LANGID_QUENCHUA,
402 TT_NAME_MAC_LANGID_GUARANI,
403 TT_NAME_MAC_LANGID_AYMARA,
404 TT_NAME_MAC_LANGID_TATAR,
405 TT_NAME_MAC_LANGID_UIGHUR,
406 TT_NAME_MAC_LANGID_DZONGKHA,
407 TT_NAME_MAC_LANGID_JAVANESE,
408 TT_NAME_MAC_LANGID_SUNDANESE,
409 TT_NAME_MAC_LANGID_GALICIAN,
410 TT_NAME_MAC_LANGID_AFRIKAANS,
411 TT_NAME_MAC_LANGID_BRETON,
412 TT_NAME_MAC_LANGID_INUKTITUT,
413 TT_NAME_MAC_LANGID_SCOTTISH_GAELIC,
414 TT_NAME_MAC_LANGID_MANX_GAELIC,
415 TT_NAME_MAC_LANGID_IRISH_GAELIC,
416 TT_NAME_MAC_LANGID_TONGAN,
417 TT_NAME_MAC_LANGID_GREEK_POLYTONIC,
418 TT_NAME_MAC_LANGID_GREENLANDIC,
419 TT_NAME_MAC_LANGID_AZER_ROMAN
422 /* Names are indexed with TT_NAME_MAC_LANGUAGE_ID values */
423 static const char name_mac_langid_to_locale[][10] = {
424 "en-US",
425 "fr-FR",
426 "de-DE",
427 "it-IT",
428 "nl-NL",
429 "sv-SE",
430 "es-ES",
431 "da-DA",
432 "pt-PT",
433 "no-NO",
434 "he-IL",
435 "ja-JP",
436 "ar-AR",
437 "fi-FI",
438 "el-GR",
439 "is-IS",
440 "mt-MT",
441 "tr-TR",
442 "hr-HR",
443 "zh-HK",
444 "ur-PK",
445 "hi-IN",
446 "th-TH",
447 "ko-KR",
448 "lt-LT",
449 "pl-PL",
450 "hu-HU",
451 "et-EE",
452 "lv-LV",
453 "se-NO",
454 "fo-FO",
455 "fa-IR",
456 "ru-RU",
457 "zh-CN",
458 "nl-BE",
459 "gd-GB",
460 "sq-AL",
461 "ro-RO",
462 "cs-CZ",
463 "sk-SK",
464 "sl-SI",
466 "sr-Latn",
467 "mk-MK",
468 "bg-BG",
469 "uk-UA",
470 "be-BY",
471 "uz-Latn",
472 "kk-KZ",
473 "az-Cyrl-AZ",
474 "az-AZ",
475 "hy-AM",
476 "ka-GE",
479 "tg-TJ",
480 "tk-TM",
481 "mn-Mong",
482 "mn-MN",
483 "ps-AF",
484 "ku-Arab",
486 "sd-Arab",
487 "bo-CN",
488 "ne-NP",
489 "sa-IN",
490 "mr-IN",
491 "bn-IN",
492 "as-IN",
493 "gu-IN",
494 "pa-Arab",
495 "or-IN",
496 "ml-IN",
497 "kn-IN",
498 "ta-LK",
499 "te-IN",
500 "si-LK",
502 "km-KH",
503 "lo-LA",
504 "vi-VN",
505 "id-ID",
507 "ms-MY",
508 "ms-Arab",
509 "am-ET",
510 "ti-ET",
513 "sw-KE",
514 "rw-RW",
519 "cy-GB",
520 "eu-ES",
521 "ca-ES",
526 "tt-RU",
527 "ug-CN",
531 "gl-ES",
532 "af-ZA",
533 "br-FR",
534 "iu-Latn-CA",
535 "gd-GB",
537 "ga-IE",
540 "kl-GL",
541 "az-Latn"
544 enum OPENTYPE_STRING_ID
546 OPENTYPE_STRING_COPYRIGHT_NOTICE = 0,
547 OPENTYPE_STRING_FAMILY_NAME,
548 OPENTYPE_STRING_SUBFAMILY_NAME,
549 OPENTYPE_STRING_UNIQUE_IDENTIFIER,
550 OPENTYPE_STRING_FULL_FONTNAME,
551 OPENTYPE_STRING_VERSION_STRING,
552 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
553 OPENTYPE_STRING_TRADEMARK,
554 OPENTYPE_STRING_MANUFACTURER,
555 OPENTYPE_STRING_DESIGNER,
556 OPENTYPE_STRING_DESCRIPTION,
557 OPENTYPE_STRING_VENDOR_URL,
558 OPENTYPE_STRING_DESIGNER_URL,
559 OPENTYPE_STRING_LICENSE_DESCRIPTION,
560 OPENTYPE_STRING_LICENSE_INFO_URL,
561 OPENTYPE_STRING_RESERVED_ID15,
562 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
563 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
564 OPENTYPE_STRING_COMPATIBLE_FULLNAME,
565 OPENTYPE_STRING_SAMPLE_TEXT,
566 OPENTYPE_STRING_POSTSCRIPT_CID_NAME,
567 OPENTYPE_STRING_WWS_FAMILY_NAME,
568 OPENTYPE_STRING_WWS_SUBFAMILY_NAME
571 static const UINT16 dwriteid_to_opentypeid[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1] =
573 (UINT16)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */
574 OPENTYPE_STRING_COPYRIGHT_NOTICE,
575 OPENTYPE_STRING_VERSION_STRING,
576 OPENTYPE_STRING_TRADEMARK,
577 OPENTYPE_STRING_MANUFACTURER,
578 OPENTYPE_STRING_DESIGNER,
579 OPENTYPE_STRING_DESIGNER_URL,
580 OPENTYPE_STRING_DESCRIPTION,
581 OPENTYPE_STRING_VENDOR_URL,
582 OPENTYPE_STRING_LICENSE_DESCRIPTION,
583 OPENTYPE_STRING_LICENSE_INFO_URL,
584 OPENTYPE_STRING_FAMILY_NAME,
585 OPENTYPE_STRING_SUBFAMILY_NAME,
586 OPENTYPE_STRING_PREFERRED_FAMILY_NAME,
587 OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME,
588 OPENTYPE_STRING_SAMPLE_TEXT,
589 OPENTYPE_STRING_FULL_FONTNAME,
590 OPENTYPE_STRING_POSTSCRIPT_FONTNAME,
591 OPENTYPE_STRING_POSTSCRIPT_CID_NAME
594 BOOL is_face_type_supported(DWRITE_FONT_FACE_TYPE type)
596 return (type == DWRITE_FONT_FACE_TYPE_CFF) ||
597 (type == DWRITE_FONT_FACE_TYPE_TRUETYPE) ||
598 (type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) ||
599 (type == DWRITE_FONT_FACE_TYPE_RAW_CFF);
602 HRESULT opentype_analyze_font(IDWriteFontFileStream *stream, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported)
604 /* TODO: Do font validation */
605 DWRITE_FONT_FACE_TYPE face;
606 const void *font_data;
607 const char* tag;
608 void *context;
609 HRESULT hr;
611 hr = IDWriteFontFileStream_ReadFileFragment(stream, &font_data, 0, sizeof(TTC_Header_V1), &context);
612 if (FAILED(hr))
613 return hr;
615 tag = font_data;
616 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
617 face = DWRITE_FONT_FACE_TYPE_UNKNOWN;
618 *font_count = 0;
620 if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_TTCF_TAG)
622 const TTC_Header_V1 *header = font_data;
623 *font_count = GET_BE_DWORD(header->numFonts);
624 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION;
625 face = DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION;
627 else if (GET_BE_DWORD(*(DWORD*)font_data) == 0x10000)
629 *font_count = 1;
630 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
631 face = DWRITE_FONT_FACE_TYPE_TRUETYPE;
633 else if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_OTTO_TAG)
635 *file_type = DWRITE_FONT_FILE_TYPE_CFF;
636 face = DWRITE_FONT_FACE_TYPE_CFF;
639 if (face_type)
640 *face_type = face;
642 *supported = is_face_type_supported(face);
644 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
645 return S_OK;
648 HRESULT opentype_get_font_table(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE type, UINT32 font_index, UINT32 tag,
649 const void **table_data, void **table_context, UINT32 *table_size, BOOL *found)
651 HRESULT hr;
652 TTC_SFNT_V1 *font_header = NULL;
653 void *sfnt_context;
654 TT_TableRecord *table_record = NULL;
655 void *table_record_context;
656 int table_count, table_offset = 0;
657 int i;
659 if (found) *found = FALSE;
660 if (table_size) *table_size = 0;
662 if (type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) {
663 const TTC_Header_V1 *ttc_header;
664 void * ttc_context;
665 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context);
666 if (SUCCEEDED(hr)) {
667 table_offset = GET_BE_DWORD(ttc_header->OffsetTable[0]);
668 if (font_index >= GET_BE_DWORD(ttc_header->numFonts))
669 hr = E_INVALIDARG;
670 else
671 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context);
672 IDWriteFontFileStream_ReleaseFileFragment(stream, ttc_context);
675 else
676 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context);
678 if (FAILED(hr))
679 return hr;
681 table_count = GET_BE_WORD(font_header->numTables);
682 table_offset += sizeof(*font_header);
683 for (i = 0; i < table_count; i++)
685 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&table_record, table_offset, sizeof(*table_record), &table_record_context);
686 if (FAILED(hr))
687 break;
688 if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag)
689 break;
690 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
691 table_offset += sizeof(*table_record);
694 IDWriteFontFileStream_ReleaseFileFragment(stream, sfnt_context);
695 if (SUCCEEDED(hr) && i < table_count)
697 int offset = GET_BE_DWORD(table_record->offset);
698 int length = GET_BE_DWORD(table_record->length);
699 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
701 if (found) *found = TRUE;
702 if (table_size) *table_size = length;
703 hr = IDWriteFontFileStream_ReadFileFragment(stream, table_data, offset, length, table_context);
706 return hr;
709 /**********
710 * CMAP
711 **********/
713 static int compare_group(const void *a, const void* b)
715 const DWORD *chr = a;
716 const CMAP_SegmentedCoverage_group *group = b;
718 if (*chr < GET_BE_DWORD(group->startCharCode))
719 return -1;
720 if (*chr > GET_BE_DWORD(group->endCharCode))
721 return 1;
722 return 0;
725 static void CMAP4_GetGlyphIndex(CMAP_SegmentMapping_0* format, UINT32 utf32c, UINT16 *pgi)
727 WORD *startCode;
728 SHORT *idDelta;
729 WORD *idRangeOffset;
730 int segment;
732 int segment_count = GET_BE_WORD(format->segCountX2)/2;
733 /* This is correct because of the padding before startCode */
734 startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
735 idDelta = (SHORT*)(((BYTE*)startCode) + (sizeof(WORD) * segment_count));
736 idRangeOffset = (WORD*)(((BYTE*)idDelta) + (sizeof(WORD) * segment_count));
738 segment = 0;
739 while(GET_BE_WORD(format->endCode[segment]) < 0xffff)
741 if (utf32c <= GET_BE_WORD(format->endCode[segment]))
742 break;
743 segment++;
745 if (segment >= segment_count)
746 return;
747 TRACE("Segment %i of %i\n",segment, segment_count);
748 if (GET_BE_WORD(startCode[segment]) > utf32c)
749 return;
750 TRACE("In range %i -> %i\n", GET_BE_WORD(startCode[segment]), GET_BE_WORD(format->endCode[segment]));
751 if (GET_BE_WORD(idRangeOffset[segment]) == 0)
753 *pgi = (SHORT)(GET_BE_WORD(idDelta[segment])) + utf32c;
755 else
757 WORD ro = GET_BE_WORD(idRangeOffset[segment])/2;
758 WORD co = (utf32c - GET_BE_WORD(startCode[segment]));
759 WORD *index = (WORD*)((BYTE*)&idRangeOffset[segment] + (ro + co));
760 *pgi = GET_BE_WORD(*index);
764 static void CMAP12_GetGlyphIndex(CMAP_SegmentedCoverage* format, UINT32 utf32c, UINT16 *pgi)
766 CMAP_SegmentedCoverage_group *group;
768 group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
769 sizeof(CMAP_SegmentedCoverage_group), compare_group);
771 if (group)
773 DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
774 *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
778 void opentype_cmap_get_glyphindex(void *data, UINT32 utf32c, UINT16 *pgi)
780 CMAP_Header *CMAP_Table = data;
781 int i;
783 *pgi = 0;
785 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
787 WORD type;
788 WORD *table;
790 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
791 continue;
793 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
794 type = GET_BE_WORD(*table);
795 TRACE("table type %i\n", type);
797 switch (type)
799 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
800 CMAP4_GetGlyphIndex((CMAP_SegmentMapping_0*) table, utf32c, pgi);
801 break;
802 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
803 CMAP12_GetGlyphIndex((CMAP_SegmentedCoverage*) table, utf32c, pgi);
804 break;
805 default:
806 TRACE("table type %i unhandled.\n", type);
809 if (*pgi) return;
813 static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table)
815 UINT32 count = 0;
816 int i;
818 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) {
819 WORD type;
820 WORD *table;
822 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
823 continue;
825 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
826 type = GET_BE_WORD(*table);
827 TRACE("table type %i\n", type);
829 switch (type)
831 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
833 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
834 count += GET_BE_WORD(format->segCountX2)/2;
835 break;
837 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
839 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
840 count += GET_BE_DWORD(format->nGroups);
841 break;
843 default:
844 FIXME("table type %i unhandled.\n", type);
848 return count;
851 HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
853 CMAP_Header *CMAP_Table = data;
854 int i, k = 0;
856 if (!CMAP_Table)
857 return E_FAIL;
859 *count = opentype_cmap_get_unicode_ranges_count(CMAP_Table);
861 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables) && k < max_count; i++)
863 WORD type;
864 WORD *table;
865 int j;
867 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
868 continue;
870 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
871 type = GET_BE_WORD(*table);
872 TRACE("table type %i\n", type);
874 switch (type)
876 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
878 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
879 UINT16 segment_count = GET_BE_WORD(format->segCountX2)/2;
880 UINT16 *startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
882 for (j = 0; j < segment_count && GET_BE_WORD(format->endCode[j]) < 0xffff && k < max_count; j++, k++) {
883 ranges[k].first = GET_BE_WORD(startCode[j]);
884 ranges[k].last = GET_BE_WORD(format->endCode[j]);
886 break;
888 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
890 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
891 for (j = 0; j < GET_BE_DWORD(format->nGroups) && k < max_count; j++, k++) {
892 ranges[k].first = GET_BE_DWORD(format->groups[j].startCharCode);
893 ranges[k].last = GET_BE_DWORD(format->groups[j].endCharCode);
895 break;
897 default:
898 FIXME("table type %i unhandled.\n", type);
902 return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK;
905 void opentype_get_font_metrics(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index,
906 DWRITE_FONT_METRICS1 *metrics)
908 void *os2_context, *head_context, *post_context, *hhea_context;
909 const TT_OS2_V2 *tt_os2;
910 const TT_HEAD *tt_head;
911 const TT_POST *tt_post;
912 const TT_HHEA *tt_hhea;
914 memset(metrics, 0, sizeof(*metrics));
916 opentype_get_font_table(stream, face_type, face_index, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
917 opentype_get_font_table(stream, face_type, face_index, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
918 opentype_get_font_table(stream, face_type, face_index, MS_POST_TAG, (const void**)&tt_post, &post_context, NULL, NULL);
919 opentype_get_font_table(stream, face_type, face_index, MS_HHEA_TAG, (const void**)&tt_hhea, &hhea_context, NULL, NULL);
921 if (tt_head) {
922 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
923 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
924 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
925 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
926 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
929 if (tt_os2) {
930 USHORT version = GET_BE_WORD(tt_os2->version);
932 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
933 metrics->descent = GET_BE_WORD(tt_os2->usWinDescent);
935 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
936 if (tt_hhea) {
937 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
938 INT32 linegap;
940 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
941 metrics->ascent - metrics->descent;
942 metrics->lineGap = linegap > 0 ? linegap : 0;
945 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
946 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
947 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
948 /* Y offset is stored as positive offset below baseline */
949 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
950 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
951 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
952 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
953 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
954 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
955 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
957 /* version 2 fields */
958 if (version >= 2) {
959 metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight);
960 metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight);
963 /* version 4 fields */
964 if (version >= 4) {
965 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
966 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
967 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
968 metrics->descent = descent < 0 ? -descent : 0;
969 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
970 metrics->hasTypographicMetrics = TRUE;
975 if (tt_post) {
976 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
977 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
980 /* estimate missing metrics */
981 if (metrics->xHeight == 0)
982 metrics->xHeight = metrics->designUnitsPerEm / 2;
983 if (metrics->capHeight == 0)
984 metrics->capHeight = metrics->designUnitsPerEm * 7 / 10;
986 if (tt_os2)
987 IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context);
988 if (tt_head)
989 IDWriteFontFileStream_ReleaseFileFragment(stream, head_context);
990 if (tt_post)
991 IDWriteFontFileStream_ReleaseFileFragment(stream, post_context);
992 if (tt_hhea)
993 IDWriteFontFileStream_ReleaseFileFragment(stream, hhea_context);
996 void opentype_get_font_properties(const void *os2, const void *head, DWRITE_FONT_STRETCH *stretch, DWRITE_FONT_WEIGHT *weight, DWRITE_FONT_STYLE *style)
998 TT_OS2_V2 *tt_os2 = (TT_OS2_V2*)os2;
999 TT_HEAD *tt_head = (TT_HEAD*)head;
1001 /* default stretch, weight and style to normal */
1002 *stretch = DWRITE_FONT_STRETCH_NORMAL;
1003 *weight = DWRITE_FONT_WEIGHT_NORMAL;
1004 *style = DWRITE_FONT_STYLE_NORMAL;
1006 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
1007 if (tt_os2) {
1008 if (GET_BE_WORD(tt_os2->usWidthClass) <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
1009 *stretch = GET_BE_WORD(tt_os2->usWidthClass);
1011 *weight = GET_BE_WORD(tt_os2->usWeightClass);
1012 TRACE("stretch=%d, weight=%d\n", *stretch, *weight);
1015 if (tt_head) {
1016 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
1017 if (macStyle & 0x0002)
1018 *style = DWRITE_FONT_STYLE_ITALIC;
1022 static UINT get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform, USHORT encoding)
1024 UINT codepage = 0;
1026 switch (platform) {
1027 case OPENTYPE_PLATFORM_UNICODE:
1028 break;
1029 case OPENTYPE_PLATFORM_MAC:
1030 switch (encoding)
1032 case TT_NAME_MAC_ENCODING_ROMAN:
1033 codepage = 10000;
1034 break;
1035 case TT_NAME_MAC_ENCODING_JAPANESE:
1036 codepage = 10001;
1037 break;
1038 case TT_NAME_MAC_ENCODING_TRAD_CHINESE:
1039 codepage = 10002;
1040 break;
1041 case TT_NAME_MAC_ENCODING_KOREAN:
1042 codepage = 10003;
1043 break;
1044 case TT_NAME_MAC_ENCODING_ARABIC:
1045 codepage = 10004;
1046 break;
1047 case TT_NAME_MAC_ENCODING_HEBREW:
1048 codepage = 10005;
1049 break;
1050 case TT_NAME_MAC_ENCODING_GREEK:
1051 codepage = 10006;
1052 break;
1053 case TT_NAME_MAC_ENCODING_RUSSIAN:
1054 codepage = 10007;
1055 break;
1056 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE:
1057 codepage = 10008;
1058 break;
1059 case TT_NAME_MAC_ENCODING_THAI:
1060 codepage = 10021;
1061 break;
1062 default:
1063 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1064 break;
1066 break;
1067 case OPENTYPE_PLATFORM_WIN:
1068 switch (encoding)
1070 case TT_NAME_WINDOWS_ENCODING_SYMBOL:
1071 case TT_NAME_WINDOWS_ENCODING_UCS2:
1072 break;
1073 case TT_NAME_WINDOWS_ENCODING_SJIS:
1074 codepage = 932;
1075 break;
1076 case TT_NAME_WINDOWS_ENCODING_PRC:
1077 codepage = 936;
1078 break;
1079 case TT_NAME_WINDOWS_ENCODING_BIG5:
1080 codepage = 950;
1081 break;
1082 case TT_NAME_WINDOWS_ENCODING_WANSUNG:
1083 codepage = 20949;
1084 break;
1085 case TT_NAME_WINDOWS_ENCODING_JOHAB:
1086 codepage = 1361;
1087 break;
1088 default:
1089 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1090 break;
1092 break;
1093 default:
1094 FIXME("unknown platform %d\n", platform);
1097 return codepage;
1100 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform, USHORT lang_id, WCHAR *locale, USHORT locale_len)
1102 static const WCHAR enusW[] = {'e','n','-','U','S',0};
1104 switch (platform) {
1105 case OPENTYPE_PLATFORM_MAC:
1107 const char *locale_name = NULL;
1109 if (lang_id > TT_NAME_MAC_LANGID_AZER_ROMAN)
1110 ERR("invalid mac lang id %d\n", lang_id);
1111 else if (!name_mac_langid_to_locale[lang_id][0])
1112 FIXME("failed to map mac lang id %d to locale name\n", lang_id);
1113 else
1114 locale_name = name_mac_langid_to_locale[lang_id];
1116 if (locale_name)
1117 MultiByteToWideChar(CP_ACP, 0, name_mac_langid_to_locale[lang_id], -1, locale, locale_len);
1118 else
1119 strcpyW(locale, enusW);
1120 break;
1122 case OPENTYPE_PLATFORM_WIN:
1123 if (!LCIDToLocaleName(MAKELCID(lang_id, SORT_DEFAULT), locale, locale_len, 0)) {
1124 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id, SORT_DEFAULT));
1125 strcpyW(locale, enusW);
1127 break;
1128 default:
1129 FIXME("unknown platform %d\n", platform);
1133 HRESULT opentype_get_font_strings_from_id(const void *table_data, DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings)
1135 const TT_NAME_V0 *header;
1136 BYTE *storage_area = 0;
1137 USHORT count = 0;
1138 UINT16 name_id;
1139 BOOL exists;
1140 HRESULT hr;
1141 int i;
1143 if (!table_data)
1144 return E_FAIL;
1146 hr = create_localizedstrings(strings);
1147 if (FAILED(hr)) return hr;
1149 header = table_data;
1150 storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset);
1151 count = GET_BE_WORD(header->count);
1153 name_id = dwriteid_to_opentypeid[id];
1155 exists = FALSE;
1156 for (i = 0; i < count; i++) {
1157 const TT_NameRecord *record = &header->nameRecord[i];
1158 USHORT lang_id, length, offset, encoding, platform;
1160 if (GET_BE_WORD(record->nameID) != name_id)
1161 continue;
1163 exists = TRUE;
1165 /* Right now only accept unicode and windows encoded fonts */
1166 platform = GET_BE_WORD(record->platformID);
1167 if (platform != OPENTYPE_PLATFORM_UNICODE &&
1168 platform != OPENTYPE_PLATFORM_MAC &&
1169 platform != OPENTYPE_PLATFORM_WIN)
1171 FIXME("platform %i not supported\n", platform);
1172 continue;
1175 lang_id = GET_BE_WORD(record->languageID);
1176 length = GET_BE_WORD(record->length);
1177 offset = GET_BE_WORD(record->offset);
1178 encoding = GET_BE_WORD(record->encodingID);
1180 if (lang_id < 0x8000) {
1181 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
1182 WCHAR *name_string;
1183 UINT codepage;
1185 codepage = get_name_record_codepage(platform, encoding);
1186 get_name_record_locale(platform, lang_id, locale, sizeof(locale)/sizeof(WCHAR));
1188 if (codepage) {
1189 DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0);
1190 name_string = heap_alloc(sizeof(WCHAR) * (len+1));
1191 MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len);
1192 name_string[len] = 0;
1194 else {
1195 int i;
1197 length /= sizeof(WCHAR);
1198 name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length);
1199 for (i = 0; i < length; i++)
1200 name_string[i] = GET_BE_WORD(name_string[i]);
1203 TRACE("string %s for locale %s found\n", debugstr_w(name_string), debugstr_w(locale));
1204 add_localizedstring(*strings, locale, name_string);
1205 heap_free(name_string);
1207 else {
1208 FIXME("handle NAME format 1\n");
1209 continue;
1213 if (!exists) {
1214 IDWriteLocalizedStrings_Release(*strings);
1215 *strings = NULL;
1218 return hr;