From: Nikolay Sivov Subject: [PATCH 3/3] dwrite: Implement GetInformationalStrings() Message-Id: <5445E948.20902@codeweavers.com> Date: Tue, 21 Oct 2014 09:04:08 +0400 NAME table reading part is based on Aric's work. From a7ac005730072ed88e4a8e4741824d9aea1e6076 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 20 Oct 2014 21:45:57 +0400 Subject: [PATCH 3/3] dwrite: Implement GetInformationalStrings() --- dlls/dwrite/dwrite_private.h | 1 + dlls/dwrite/font.c | 45 ++++++++-- dlls/dwrite/opentype.c | 204 +++++++++++++++++++++++++++++++++++++++++++ dlls/dwrite/tests/font.c | 6 +- 4 files changed, 244 insertions(+), 12 deletions(-) diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index dad9ec8..fad7a21 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -113,6 +113,7 @@ extern HRESULT opentype_get_font_table(IDWriteFontFileStream*,DWRITE_FONT_FACE_T extern void opentype_cmap_get_glyphindex(void*,UINT32,UINT16*) DECLSPEC_HIDDEN; extern HRESULT opentype_cmap_get_unicode_ranges(void*,UINT32,DWRITE_UNICODE_RANGE*,UINT32*) DECLSPEC_HIDDEN; extern VOID get_font_properties(LPCVOID os2, LPCVOID head, LPCVOID post, DWRITE_FONT_METRICS *metrics, DWRITE_FONT_STRETCH *stretch, DWRITE_FONT_WEIGHT *weight, DWRITE_FONT_STYLE *style) DECLSPEC_HIDDEN; +extern HRESULT opentype_get_font_strings_from_id(IDWriteFontFace2*,DWRITE_INFORMATIONAL_STRING_ID,IDWriteLocalizedStrings**) DECLSPEC_HIDDEN; extern HRESULT bidi_computelevels(const WCHAR*,UINT32,UINT8,UINT8*,UINT8*) DECLSPEC_HIDDEN; extern WCHAR bidi_get_mirrored_char(WCHAR) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index e3b4f3c..783b035 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -1,7 +1,8 @@ /* * Font and collections * - * Copyright 2012 Nikolay Sivov for CodeWeavers + * Copyright 2012, 2014 Nikolay Sivov for CodeWeavers + * Copyright 2014 Aric Stewart for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -47,6 +48,7 @@ struct dwrite_font_data { DWRITE_FONT_WEIGHT weight; DWRITE_FONT_SIMULATIONS simulations; DWRITE_FONT_METRICS metrics; + IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1]; struct dwrite_fontface_data *face_data; @@ -220,6 +222,11 @@ static VOID _free_font_data(struct dwrite_font_data *data) i = InterlockedDecrement(&data->ref); if (i > 0) return; + + for (i = DWRITE_INFORMATIONAL_STRING_NONE; i < sizeof(data->info_strings)/sizeof(data->info_strings[0]); i++) { + if (data->info_strings[i]) + IDWriteLocalizedStrings_Release(data->info_strings[i]); + } _free_fontface_data(data->face_data); heap_free(data->facename); heap_free(data); @@ -755,12 +762,9 @@ static HRESULT create_font_base(IDWriteFont **font) HRESULT ret; *font = NULL; - data = heap_alloc(sizeof(*data)); + data = heap_alloc_zero(sizeof(*data)); if (!data) return E_OUTOFMEMORY; - data->ref = 0; - data->face_data = NULL; - ret = create_font_from_data( data, NULL, font ); if (FAILED(ret)) heap_free( data ); return ret; @@ -967,8 +971,35 @@ static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont2 *iface, DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists) { struct dwrite_font *This = impl_from_IDWriteFont2(iface); - FIXME("(%p)->(%d %p %p): stub\n", This, stringid, strings, exists); - return E_NOTIMPL; + struct dwrite_font_data *data = This->data; + HRESULT hr; + + TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists); + + *exists = FALSE; + *strings = NULL; + + if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE) + return S_OK; + + if (!data->info_strings[stringid]) { + IDWriteFontFace2 *fontface; + + hr = get_fontface_from_font(This, &fontface); + if (FAILED(hr)) + return hr; + + hr = opentype_get_font_strings_from_id(fontface, stringid, &data->info_strings[stringid]); + if (FAILED(hr) || !data->info_strings[stringid]) + return hr; + } + + hr = clone_localizedstring(data->info_strings[stringid], strings); + if (FAILED(hr)) + return hr; + + *exists = TRUE; + return hr; } static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont2 *iface) diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 487f56b..ed08899 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -26,6 +26,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dwrite); #define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f') #define MS_OTTO_TAG DWRITE_MAKE_OPENTYPE_TAG('O','T','T','O') +#define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e') #ifdef WORDS_BIGENDIAN #define GET_BE_WORD(x) (x) @@ -185,6 +186,87 @@ typedef struct } TT_OS2_V2; #include "poppack.h" +typedef struct { + WORD platformID; + WORD encodingID; + WORD languageID; + WORD nameID; + WORD length; + WORD offset; +} TT_NameRecord; + +typedef struct { + WORD format; + WORD count; + WORD stringOffset; + TT_NameRecord nameRecord[1]; +} TT_NAME_V0; + +enum TT_NAME_WINDOWS_ENCODING_ID +{ + TT_NAME_WINDOWS_ENCODING_SYMBOL = 0, + TT_NAME_WINDOWS_ENCODING_UCS2, + TT_NAME_WINDOWS_ENCODING_SJIS, + TT_NAME_WINDOWS_ENCODING_PRC, + TT_NAME_WINDOWS_ENCODING_BIG5, + TT_NAME_WINDOWS_ENCODING_WANSUNG, + TT_NAME_WINDOWS_ENCODING_JOHAB, + TT_NAME_WINDOWS_ENCODING_RESERVED1, + TT_NAME_WINDOWS_ENCODING_RESERVED2, + TT_NAME_WINDOWS_ENCODING_RESERVED3, + TT_NAME_WINDOWS_ENCODING_UCS4 +}; + +enum OPENTYPE_STRING_ID +{ + OPENTYPE_STRING_COPYRIGHT_NOTICE = 0, + OPENTYPE_STRING_FAMILY_NAME, + OPENTYPE_STRING_SUBFAMILY_NAME, + OPENTYPE_STRING_UNIQUE_IDENTIFIER, + OPENTYPE_STRING_FULL_FONTNAME, + OPENTYPE_STRING_VERSION_STRING, + OPENTYPE_STRING_POSTSCRIPT_FONTNAME, + OPENTYPE_STRING_TRADEMARK, + OPENTYPE_STRING_MANUFACTURER, + OPENTYPE_STRING_DESIGNER, + OPENTYPE_STRING_DESCRIPTION, + OPENTYPE_STRING_VENDOR_URL, + OPENTYPE_STRING_DESIGNER_URL, + OPENTYPE_STRING_LICENSE_DESCRIPTION, + OPENTYPE_STRING_LICENSE_INFO_URL, + OPENTYPE_STRING_RESERVED_ID15, + OPENTYPE_STRING_PREFERRED_FAMILY_NAME, + OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME, + OPENTYPE_STRING_COMPATIBLE_FULLNAME, + OPENTYPE_STRING_SAMPLE_TEXT, + OPENTYPE_STRING_POSTSCRIPT_CID_NAME, + OPENTYPE_STRING_WWS_FAMILY_NAME, + OPENTYPE_STRING_WWS_SUBFAMILY_NAME +}; + +static const UINT16 dwriteid_to_opentypeid[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1] = +{ + (UINT16)-1, /* DWRITE_INFORMATIONAL_STRING_NONE is not used */ + OPENTYPE_STRING_COPYRIGHT_NOTICE, + OPENTYPE_STRING_VERSION_STRING, + OPENTYPE_STRING_TRADEMARK, + OPENTYPE_STRING_MANUFACTURER, + OPENTYPE_STRING_DESIGNER, + OPENTYPE_STRING_DESIGNER_URL, + OPENTYPE_STRING_DESCRIPTION, + OPENTYPE_STRING_VENDOR_URL, + OPENTYPE_STRING_LICENSE_DESCRIPTION, + OPENTYPE_STRING_LICENSE_INFO_URL, + OPENTYPE_STRING_FAMILY_NAME, + OPENTYPE_STRING_SUBFAMILY_NAME, + OPENTYPE_STRING_PREFERRED_FAMILY_NAME, + OPENTYPE_STRING_PREFERRED_SUBFAMILY_NAME, + OPENTYPE_STRING_SAMPLE_TEXT, + OPENTYPE_STRING_FULL_FONTNAME, + OPENTYPE_STRING_POSTSCRIPT_FONTNAME, + OPENTYPE_STRING_POSTSCRIPT_CID_NAME +}; + HRESULT opentype_analyze_font(IDWriteFontFileStream *stream, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported) { /* TODO: Do font validation */ @@ -532,3 +614,125 @@ VOID get_font_properties(LPCVOID os2, LPCVOID head, LPCVOID post, DWRITE_FONT_ME metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness); } } + +HRESULT opentype_get_font_strings_from_id(IDWriteFontFace2 *fontface, DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings) +{ + const void *table_data = NULL; + void *name_context = NULL; + const TT_NAME_V0 *header; + BYTE *storage_area = 0; + BOOL exists = FALSE; + USHORT count = 0; + UINT16 name_id; + UINT32 size; + HRESULT hr; + int i; + + hr = IDWriteFontFace2_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &name_context, &exists); + if (FAILED(hr) || !exists) { + FIXME("failed to get NAME table\n"); + return E_FAIL; + } + + hr = create_localizedstrings(strings); + if (FAILED(hr)) return hr; + + header = table_data; + storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset); + count = GET_BE_WORD(header->count); + + name_id = dwriteid_to_opentypeid[id]; + + exists = FALSE; + for (i = 0; i < count; i++) { + const TT_NameRecord *record = &header->nameRecord[i]; + USHORT lang_id, length, offset, encoding, platform; + + if (GET_BE_WORD(record->nameID) != name_id) + continue; + + exists = TRUE; + + /* Right now only accept unicode and windows encoded fonts */ + platform = GET_BE_WORD(record->platformID); + if (platform != 0 && platform != 3) { + FIXME("platform %i not supported\n", platform); + continue; + } + + lang_id = GET_BE_WORD(record->languageID); + length = GET_BE_WORD(record->length); + offset = GET_BE_WORD(record->offset); + encoding = GET_BE_WORD(record->encodingID); + + if (lang_id < 0x8000) { + WCHAR locale[LOCALE_NAME_MAX_LENGTH]; + WCHAR *name_string; + UINT codepage = 0; + + if (platform == 3) + { + switch (encoding) + { + case TT_NAME_WINDOWS_ENCODING_SYMBOL: + case TT_NAME_WINDOWS_ENCODING_UCS2: + break; + case TT_NAME_WINDOWS_ENCODING_SJIS: + codepage = 932; + break; + case TT_NAME_WINDOWS_ENCODING_PRC: + codepage = 936; + break; + case TT_NAME_WINDOWS_ENCODING_BIG5: + codepage = 950; + break; + case TT_NAME_WINDOWS_ENCODING_WANSUNG: + codepage = 20949; + break; + case TT_NAME_WINDOWS_ENCODING_JOHAB: + codepage = 1361; + break; + default: + FIXME("encoding %d not handled.\n", encoding); + } + } + + if (codepage) { + DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0); + name_string = heap_alloc(sizeof(WCHAR) * len); + MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len); + } + else { + int i; + + length /= sizeof(WCHAR); + name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length); + for (i = 0; i < length; i++) + name_string[i] = GET_BE_WORD(name_string[i]); + } + + if (!LCIDToLocaleName(MAKELCID(lang_id, SORT_DEFAULT), locale, sizeof(locale)/sizeof(WCHAR), 0)) { + static const WCHAR enusW[] = {'e','n','-','u','s',0}; + FIXME("failed to get locale name for lcid=0x%08x\n", MAKELCID(lang_id, SORT_DEFAULT)); + strcpyW(locale, enusW); + } + + TRACE("string %s for locale %s found\n", debugstr_w(name_string), debugstr_w(locale)); + add_localizedstring(*strings, locale, name_string); + heap_free(name_string); + } + else { + FIXME("handle NAME format 1"); + continue; + } + } + + IDWriteFontFace2_ReleaseFontTable(fontface, name_context); + + if (!exists) { + IDWriteLocalizedStrings_Release(*strings); + *strings = NULL; + } + + return hr; +} diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c index 1bb7754..d4c2a43 100644 --- a/dlls/dwrite/tests/font.c +++ b/dlls/dwrite/tests/font.c @@ -1325,11 +1325,10 @@ static void test_GetInformationalStrings(void) exists = TRUE; strings = (void*)0xdeadbeef; hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1, &strings, &exists); -todo_wine { ok(hr == S_OK, "got 0x%08x\n", hr); ok(exists == FALSE, "got %d\n", exists); ok(strings == NULL, "got %p\n", strings); -} + exists = FALSE; strings = NULL; hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists); @@ -1337,14 +1336,11 @@ todo_wine { ok(hr == S_OK, "got 0x%08x\n", hr); ok(exists == TRUE, "got %d\n", exists); } - exists = TRUE; strings = NULL; hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_NONE, &strings, &exists); -todo_wine { ok(hr == S_OK, "got 0x%08x\n", hr); ok(exists == FALSE, "got %d\n", exists); -} /* strings instance is not reused */ strings2 = NULL; -- 2.1.1