dsound: Report buffer notifications in offset order.
[wine.git] / dlls / dwrite / opentype.c
bloba76dd4b212c067872bfcc3d037a9dc63b5ead75c
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 HRESULT opentype_analyze_font(IDWriteFontFileStream *stream, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported)
596 /* TODO: Do font validation */
597 const void *font_data;
598 const char* tag;
599 void *context;
600 HRESULT hr;
602 hr = IDWriteFontFileStream_ReadFileFragment(stream, &font_data, 0, sizeof(TTC_Header_V1), &context);
603 if (FAILED(hr))
604 return hr;
606 tag = font_data;
607 *supported = FALSE;
608 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
609 if (face_type)
610 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
611 *font_count = 0;
613 if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_TTCF_TAG)
615 const TTC_Header_V1 *header = font_data;
616 *font_count = GET_BE_DWORD(header->numFonts);
617 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION;
618 if (face_type)
619 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION;
620 *supported = TRUE;
622 else if (GET_BE_DWORD(*(DWORD*)font_data) == 0x10000)
624 *font_count = 1;
625 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
626 if (face_type)
627 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
628 *supported = TRUE;
630 else if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_OTTO_TAG)
632 *file_type = DWRITE_FONT_FILE_TYPE_CFF;
635 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
636 return S_OK;
639 HRESULT opentype_get_font_table(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE type, UINT32 font_index, UINT32 tag,
640 const void **table_data, void **table_context, UINT32 *table_size, BOOL *found)
642 HRESULT hr;
643 TTC_SFNT_V1 *font_header = NULL;
644 void *sfnt_context;
645 TT_TableRecord *table_record = NULL;
646 void *table_record_context;
647 int table_count, table_offset = 0;
648 int i;
650 if (found) *found = FALSE;
651 if (table_size) *table_size = 0;
653 if (type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) {
654 const TTC_Header_V1 *ttc_header;
655 void * ttc_context;
656 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context);
657 if (SUCCEEDED(hr)) {
658 table_offset = GET_BE_DWORD(ttc_header->OffsetTable[0]);
659 if (font_index >= GET_BE_DWORD(ttc_header->numFonts))
660 hr = E_INVALIDARG;
661 else
662 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context);
663 IDWriteFontFileStream_ReleaseFileFragment(stream, ttc_context);
666 else
667 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context);
669 if (FAILED(hr))
670 return hr;
672 table_count = GET_BE_WORD(font_header->numTables);
673 table_offset += sizeof(*font_header);
674 for (i = 0; i < table_count; i++)
676 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&table_record, table_offset, sizeof(*table_record), &table_record_context);
677 if (FAILED(hr))
678 break;
679 if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag)
680 break;
681 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
682 table_offset += sizeof(*table_record);
685 IDWriteFontFileStream_ReleaseFileFragment(stream, sfnt_context);
686 if (SUCCEEDED(hr) && i < table_count)
688 int offset = GET_BE_DWORD(table_record->offset);
689 int length = GET_BE_DWORD(table_record->length);
690 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
692 if (found) *found = TRUE;
693 if (table_size) *table_size = length;
694 hr = IDWriteFontFileStream_ReadFileFragment(stream, table_data, offset, length, table_context);
697 return hr;
700 /**********
701 * CMAP
702 **********/
704 static int compare_group(const void *a, const void* b)
706 const DWORD *chr = a;
707 const CMAP_SegmentedCoverage_group *group = b;
709 if (*chr < GET_BE_DWORD(group->startCharCode))
710 return -1;
711 if (*chr > GET_BE_DWORD(group->endCharCode))
712 return 1;
713 return 0;
716 static void CMAP4_GetGlyphIndex(CMAP_SegmentMapping_0* format, UINT32 utf32c, UINT16 *pgi)
718 WORD *startCode;
719 SHORT *idDelta;
720 WORD *idRangeOffset;
721 int segment;
723 int segment_count = GET_BE_WORD(format->segCountX2)/2;
724 /* This is correct because of the padding before startCode */
725 startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
726 idDelta = (SHORT*)(((BYTE*)startCode) + (sizeof(WORD) * segment_count));
727 idRangeOffset = (WORD*)(((BYTE*)idDelta) + (sizeof(WORD) * segment_count));
729 segment = 0;
730 while(GET_BE_WORD(format->endCode[segment]) < 0xffff)
732 if (utf32c <= GET_BE_WORD(format->endCode[segment]))
733 break;
734 segment++;
736 if (segment >= segment_count)
737 return;
738 TRACE("Segment %i of %i\n",segment, segment_count);
739 if (GET_BE_WORD(startCode[segment]) > utf32c)
740 return;
741 TRACE("In range %i -> %i\n", GET_BE_WORD(startCode[segment]), GET_BE_WORD(format->endCode[segment]));
742 if (GET_BE_WORD(idRangeOffset[segment]) == 0)
744 *pgi = (SHORT)(GET_BE_WORD(idDelta[segment])) + utf32c;
746 else
748 WORD ro = GET_BE_WORD(idRangeOffset[segment])/2;
749 WORD co = (utf32c - GET_BE_WORD(startCode[segment]));
750 WORD *index = (WORD*)((BYTE*)&idRangeOffset[segment] + (ro + co));
751 *pgi = GET_BE_WORD(*index);
755 static void CMAP12_GetGlyphIndex(CMAP_SegmentedCoverage* format, UINT32 utf32c, UINT16 *pgi)
757 CMAP_SegmentedCoverage_group *group;
759 group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
760 sizeof(CMAP_SegmentedCoverage_group), compare_group);
762 if (group)
764 DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
765 *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
769 void opentype_cmap_get_glyphindex(void *data, UINT32 utf32c, UINT16 *pgi)
771 CMAP_Header *CMAP_Table = data;
772 int i;
774 *pgi = 0;
776 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
778 WORD type;
779 WORD *table;
781 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
782 continue;
784 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
785 type = GET_BE_WORD(*table);
786 TRACE("table type %i\n", type);
788 switch (type)
790 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
791 CMAP4_GetGlyphIndex((CMAP_SegmentMapping_0*) table, utf32c, pgi);
792 break;
793 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
794 CMAP12_GetGlyphIndex((CMAP_SegmentedCoverage*) table, utf32c, pgi);
795 break;
796 default:
797 TRACE("table type %i unhandled.\n", type);
800 if (*pgi) return;
804 static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table)
806 UINT32 count = 0;
807 int i;
809 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) {
810 WORD type;
811 WORD *table;
813 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
814 continue;
816 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
817 type = GET_BE_WORD(*table);
818 TRACE("table type %i\n", type);
820 switch (type)
822 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
824 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
825 count += GET_BE_WORD(format->segCountX2)/2;
826 break;
828 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
830 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
831 count += GET_BE_DWORD(format->nGroups);
832 break;
834 default:
835 FIXME("table type %i unhandled.\n", type);
839 return count;
842 HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
844 CMAP_Header *CMAP_Table = data;
845 int i, k = 0;
847 if (!CMAP_Table)
848 return E_FAIL;
850 *count = opentype_cmap_get_unicode_ranges_count(CMAP_Table);
852 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables) && k < max_count; i++)
854 WORD type;
855 WORD *table;
856 int j;
858 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
859 continue;
861 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
862 type = GET_BE_WORD(*table);
863 TRACE("table type %i\n", type);
865 switch (type)
867 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
869 CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table;
870 UINT16 segment_count = GET_BE_WORD(format->segCountX2)/2;
871 UINT16 *startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
873 for (j = 0; j < segment_count && GET_BE_WORD(format->endCode[j]) < 0xffff && k < max_count; j++, k++) {
874 ranges[k].first = GET_BE_WORD(startCode[j]);
875 ranges[k].last = GET_BE_WORD(format->endCode[j]);
877 break;
879 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
881 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table;
882 for (j = 0; j < GET_BE_DWORD(format->nGroups) && k < max_count; j++, k++) {
883 ranges[k].first = GET_BE_DWORD(format->groups[j].startCharCode);
884 ranges[k].last = GET_BE_DWORD(format->groups[j].endCharCode);
886 break;
888 default:
889 FIXME("table type %i unhandled.\n", type);
893 return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK;
896 void opentype_get_font_metrics(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index,
897 DWRITE_FONT_METRICS1 *metrics)
899 void *os2_context, *head_context, *post_context, *hhea_context;
900 const TT_OS2_V2 *tt_os2;
901 const TT_HEAD *tt_head;
902 const TT_POST *tt_post;
903 const TT_HHEA *tt_hhea;
905 memset(metrics, 0, sizeof(*metrics));
907 opentype_get_font_table(stream, face_type, face_index, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL);
908 opentype_get_font_table(stream, face_type, face_index, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL);
909 opentype_get_font_table(stream, face_type, face_index, MS_POST_TAG, (const void**)&tt_post, &post_context, NULL, NULL);
910 opentype_get_font_table(stream, face_type, face_index, MS_HHEA_TAG, (const void**)&tt_hhea, &hhea_context, NULL, NULL);
912 if (tt_head) {
913 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
914 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
915 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
916 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
917 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
920 if (tt_os2) {
921 USHORT version = GET_BE_WORD(tt_os2->version);
923 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
924 metrics->descent = GET_BE_WORD(tt_os2->usWinDescent);
926 /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */
927 if (tt_hhea) {
928 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
929 INT32 linegap;
931 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
932 metrics->ascent - metrics->descent;
933 metrics->lineGap = linegap > 0 ? linegap : 0;
936 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
937 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
938 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
939 /* Y offset is stored as positive offset below baseline */
940 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
941 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
942 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
943 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
944 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
945 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
946 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
948 /* version 2 fields */
949 if (version >= 2) {
950 metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight);
951 metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight);
954 /* version 4 fields */
955 if (version >= 4) {
956 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
957 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
958 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
959 metrics->descent = descent < 0 ? -descent : 0;
960 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
961 metrics->hasTypographicMetrics = TRUE;
966 if (tt_post) {
967 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
968 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
971 /* estimate missing metrics */
972 if (metrics->xHeight == 0)
973 metrics->xHeight = metrics->designUnitsPerEm / 2;
974 if (metrics->capHeight == 0)
975 metrics->capHeight = metrics->designUnitsPerEm * 7 / 10;
977 if (tt_os2)
978 IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context);
979 if (tt_head)
980 IDWriteFontFileStream_ReleaseFileFragment(stream, head_context);
981 if (tt_post)
982 IDWriteFontFileStream_ReleaseFileFragment(stream, post_context);
983 if (tt_hhea)
984 IDWriteFontFileStream_ReleaseFileFragment(stream, hhea_context);
987 void opentype_get_font_properties(const void *os2, const void *head, DWRITE_FONT_STRETCH *stretch, DWRITE_FONT_WEIGHT *weight, DWRITE_FONT_STYLE *style)
989 TT_OS2_V2 *tt_os2 = (TT_OS2_V2*)os2;
990 TT_HEAD *tt_head = (TT_HEAD*)head;
992 /* default stretch, weight and style to normal */
993 *stretch = DWRITE_FONT_STRETCH_NORMAL;
994 *weight = DWRITE_FONT_WEIGHT_NORMAL;
995 *style = DWRITE_FONT_STYLE_NORMAL;
997 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
998 if (tt_os2) {
999 if (GET_BE_WORD(tt_os2->usWidthClass) <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
1000 *stretch = GET_BE_WORD(tt_os2->usWidthClass);
1002 *weight = GET_BE_WORD(tt_os2->usWeightClass);
1003 TRACE("stretch=%d, weight=%d\n", *stretch, *weight);
1006 if (tt_head) {
1007 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
1008 if (macStyle & 0x0002)
1009 *style = DWRITE_FONT_STYLE_ITALIC;
1013 static UINT get_name_record_codepage(enum OPENTYPE_PLATFORM_ID platform, USHORT encoding)
1015 UINT codepage = 0;
1017 switch (platform) {
1018 case OPENTYPE_PLATFORM_UNICODE:
1019 break;
1020 case OPENTYPE_PLATFORM_MAC:
1021 switch (encoding)
1023 case TT_NAME_MAC_ENCODING_ROMAN:
1024 codepage = 10000;
1025 break;
1026 case TT_NAME_MAC_ENCODING_JAPANESE:
1027 codepage = 10001;
1028 break;
1029 case TT_NAME_MAC_ENCODING_TRAD_CHINESE:
1030 codepage = 10002;
1031 break;
1032 case TT_NAME_MAC_ENCODING_KOREAN:
1033 codepage = 10003;
1034 break;
1035 case TT_NAME_MAC_ENCODING_ARABIC:
1036 codepage = 10004;
1037 break;
1038 case TT_NAME_MAC_ENCODING_HEBREW:
1039 codepage = 10005;
1040 break;
1041 case TT_NAME_MAC_ENCODING_GREEK:
1042 codepage = 10006;
1043 break;
1044 case TT_NAME_MAC_ENCODING_RUSSIAN:
1045 codepage = 10007;
1046 break;
1047 case TT_NAME_MAC_ENCODING_SIMPL_CHINESE:
1048 codepage = 10008;
1049 break;
1050 case TT_NAME_MAC_ENCODING_THAI:
1051 codepage = 10021;
1052 break;
1053 default:
1054 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1055 break;
1057 break;
1058 case OPENTYPE_PLATFORM_WIN:
1059 switch (encoding)
1061 case TT_NAME_WINDOWS_ENCODING_SYMBOL:
1062 case TT_NAME_WINDOWS_ENCODING_UCS2:
1063 break;
1064 case TT_NAME_WINDOWS_ENCODING_SJIS:
1065 codepage = 932;
1066 break;
1067 case TT_NAME_WINDOWS_ENCODING_PRC:
1068 codepage = 936;
1069 break;
1070 case TT_NAME_WINDOWS_ENCODING_BIG5:
1071 codepage = 950;
1072 break;
1073 case TT_NAME_WINDOWS_ENCODING_WANSUNG:
1074 codepage = 20949;
1075 break;
1076 case TT_NAME_WINDOWS_ENCODING_JOHAB:
1077 codepage = 1361;
1078 break;
1079 default:
1080 FIXME("encoding %u not handled, platform %d.\n", encoding, platform);
1081 break;
1083 break;
1084 default:
1085 FIXME("unknown platform %d\n", platform);
1088 return codepage;
1091 static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform, USHORT lang_id, WCHAR *locale, USHORT locale_len)
1093 static const WCHAR enusW[] = {'e','n','-','U','S',0};
1095 switch (platform) {
1096 case OPENTYPE_PLATFORM_MAC:
1098 const char *locale_name = NULL;
1100 if (lang_id > TT_NAME_MAC_LANGID_AZER_ROMAN)
1101 ERR("invalid mac lang id %d\n", lang_id);
1102 else if (!name_mac_langid_to_locale[lang_id][0])
1103 FIXME("failed to map mac lang id %d to locale name\n", lang_id);
1104 else
1105 locale_name = name_mac_langid_to_locale[lang_id];
1107 if (locale_name)
1108 MultiByteToWideChar(CP_ACP, 0, name_mac_langid_to_locale[lang_id], -1, locale, locale_len);
1109 else
1110 strcpyW(locale, enusW);
1111 break;
1113 case OPENTYPE_PLATFORM_WIN:
1114 if (!LCIDToLocaleName(MAKELCID(lang_id, SORT_DEFAULT), locale, locale_len, 0)) {
1115 FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id, SORT_DEFAULT));
1116 strcpyW(locale, enusW);
1118 break;
1119 default:
1120 FIXME("unknown platform %d\n", platform);
1124 HRESULT opentype_get_font_strings_from_id(const void *table_data, DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings)
1126 const TT_NAME_V0 *header;
1127 BYTE *storage_area = 0;
1128 USHORT count = 0;
1129 UINT16 name_id;
1130 BOOL exists;
1131 HRESULT hr;
1132 int i;
1134 if (!table_data)
1135 return E_FAIL;
1137 hr = create_localizedstrings(strings);
1138 if (FAILED(hr)) return hr;
1140 header = table_data;
1141 storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset);
1142 count = GET_BE_WORD(header->count);
1144 name_id = dwriteid_to_opentypeid[id];
1146 exists = FALSE;
1147 for (i = 0; i < count; i++) {
1148 const TT_NameRecord *record = &header->nameRecord[i];
1149 USHORT lang_id, length, offset, encoding, platform;
1151 if (GET_BE_WORD(record->nameID) != name_id)
1152 continue;
1154 exists = TRUE;
1156 /* Right now only accept unicode and windows encoded fonts */
1157 platform = GET_BE_WORD(record->platformID);
1158 if (platform != OPENTYPE_PLATFORM_UNICODE &&
1159 platform != OPENTYPE_PLATFORM_MAC &&
1160 platform != OPENTYPE_PLATFORM_WIN)
1162 FIXME("platform %i not supported\n", platform);
1163 continue;
1166 lang_id = GET_BE_WORD(record->languageID);
1167 length = GET_BE_WORD(record->length);
1168 offset = GET_BE_WORD(record->offset);
1169 encoding = GET_BE_WORD(record->encodingID);
1171 if (lang_id < 0x8000) {
1172 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
1173 WCHAR *name_string;
1174 UINT codepage;
1176 codepage = get_name_record_codepage(platform, encoding);
1177 get_name_record_locale(platform, lang_id, locale, sizeof(locale)/sizeof(WCHAR));
1179 if (codepage) {
1180 DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0);
1181 name_string = heap_alloc(sizeof(WCHAR) * (len+1));
1182 MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len);
1183 name_string[len] = 0;
1185 else {
1186 int i;
1188 length /= sizeof(WCHAR);
1189 name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length);
1190 for (i = 0; i < length; i++)
1191 name_string[i] = GET_BE_WORD(name_string[i]);
1194 TRACE("string %s for locale %s found\n", debugstr_w(name_string), debugstr_w(locale));
1195 add_localizedstring(*strings, locale, name_string);
1196 heap_free(name_string);
1198 else {
1199 FIXME("handle NAME format 1");
1200 continue;
1204 if (!exists) {
1205 IDWriteLocalizedStrings_Release(*strings);
1206 *strings = NULL;
1209 return hr;