From 4f206a3fbe6150ce9d547952db7b93a884e024ab Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Sat, 13 Jun 2015 16:29:10 +0200 Subject: [PATCH] directwrite: multiple improvements to font scanning There were various issues with font scanning. This addresses the following: - Synthesized font faces (bold/oblique) were added to the list. Just skip those, this is handled internally by libass. - Use the win32 font family names, if available. Traditionally, Windows groups font families in a different way, so that the number of variants is small (<= 4). With this, Arial Narrow and Arial Black appear as a separate family, which is what we want. - Full names are not mandatory. Correctly handle the case that there are no full names. - Don't use the bogus LOCALE_NAME_MAX_LENGTH constant to determine the size of the name buffer. Names can be almost arbitrarily long. Handle names up to 256 characters correctly and truncate longer names. --- libass/ass_directwrite.cpp | 81 ++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/libass/ass_directwrite.cpp b/libass/ass_directwrite.cpp index f8feecf..9bc8ce9 100644 --- a/libass/ass_directwrite.cpp +++ b/libass/ass_directwrite.cpp @@ -27,6 +27,8 @@ extern "C" { #include "ass_utils.h" } +#define NAME_MAX_LENGTH 256 + /* * The private data stored for every font, detected by this backend. */ @@ -177,9 +179,21 @@ static void destroy_font(void *data) free(priv); } -static int map_width(int stretch) +static int map_width(enum DWRITE_FONT_STRETCH stretch) { - return stretch * (100 / DWRITE_FONT_STRETCH_MEDIUM); + switch (stretch) { + case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: return 50; + case DWRITE_FONT_STRETCH_EXTRA_CONDENSED: return 63; + case DWRITE_FONT_STRETCH_CONDENSED: return FONT_WIDTH_CONDENSED; + case DWRITE_FONT_STRETCH_SEMI_CONDENSED: return 88; + case DWRITE_FONT_STRETCH_MEDIUM: return FONT_WIDTH_NORMAL; + case DWRITE_FONT_STRETCH_SEMI_EXPANDED: return 113; + case DWRITE_FONT_STRETCH_EXPANDED: return FONT_WIDTH_EXPANDED; + case DWRITE_FONT_STRETCH_EXTRA_EXPANDED: return 150; + case DWRITE_FONT_STRETCH_ULTRA_EXPANDED: return 200; + default: + assert(0); + } } /* @@ -197,7 +211,7 @@ static void scan_fonts(IDWriteFactory *factory, DWRITE_FONT_STYLE style; ASS_FontProviderMetaData meta = ASS_FontProviderMetaData(); hr = factory->GetSystemFontCollection(&fontCollection, FALSE); - wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; + wchar_t temp_name[NAME_MAX_LENGTH]; int size_needed = 0; if (FAILED(hr) || !fontCollection) @@ -215,7 +229,7 @@ static void scan_fonts(IDWriteFactory *factory, hr = fontCollection->GetFontFamily(i, &fontFamily); if (FAILED(hr)) - return; + continue; UINT32 fontCount = fontFamily->GetFontCount(); for (UINT32 j = 0; j < fontCount; ++j) { @@ -223,6 +237,13 @@ static void scan_fonts(IDWriteFactory *factory, if (FAILED(hr)) continue; + // Simulations for bold or oblique are sometimes synthesized by + // DirectWrite. We are only interested in physical fonts. + if (font->GetSimulations() != 0) { + font->Release(); + continue; + } + meta.weight = font->GetWeight(); meta.width = map_width(font->GetStretch()); font->GetMetrics(&metrics); @@ -232,68 +253,70 @@ static void scan_fonts(IDWriteFactory *factory, (style == DWRITE_FONT_STYLE_ITALIC) ? FONT_SLANT_ITALIC : FONT_SLANT_NONE; hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &psNames,&exists); - if (FAILED(hr)) { font->Release(); continue; } if (exists) { - hr = psNames->GetString(0, localeName, LOCALE_NAME_MAX_LENGTH + 1); + hr = psNames->GetString(0, temp_name, NAME_MAX_LENGTH); if (FAILED(hr)) { psNames->Release(); font->Release(); continue; } - size_needed = WideCharToMultiByte(CP_UTF8, 0, localeName, -1, NULL, 0,NULL, NULL); + temp_name[NAME_MAX_LENGTH-1] = 0; + size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0,NULL, NULL); psName = (char *) malloc(size_needed); - WideCharToMultiByte(CP_UTF8, 0, localeName, -1, psName,size_needed, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, psName, size_needed, NULL, NULL); + psNames->Release(); } - psNames->Release(); - hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_FULL_NAME, &fontNames,&exists); if (FAILED(hr)) { font->Release(); continue; } - meta.n_fullname = fontNames->GetCount(); - meta.fullnames = (char **) calloc(meta.n_fullname, sizeof(char *)); - for (UINT32 k = 0; k < meta.n_fullname; ++k) { - hr = fontNames->GetString(k, localeName,LOCALE_NAME_MAX_LENGTH + 1); - - if (FAILED(hr)) { - continue; + if (exists) { + meta.n_fullname = fontNames->GetCount(); + meta.fullnames = (char **) calloc(meta.n_fullname, sizeof(char *)); + for (UINT32 k = 0; k < meta.n_fullname; ++k) { + hr = fontNames->GetString(k, temp_name, NAME_MAX_LENGTH); + if (FAILED(hr)) { + continue; + } + + temp_name[NAME_MAX_LENGTH-1] = 0; + size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0, NULL, NULL); + char *mbName = (char *) malloc(size_needed); + WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, mbName, size_needed, NULL, NULL); + meta.fullnames[k] = mbName; } - - size_needed = WideCharToMultiByte(CP_UTF8, 0, localeName, -1, NULL, 0, NULL, NULL); - char *mbName = (char *) malloc(size_needed); - WideCharToMultiByte(CP_UTF8, 0, localeName, -1, mbName,size_needed, NULL, NULL); - meta.fullnames[k] = mbName; + fontNames->Release(); } - fontNames->Release(); - hr = fontFamily->GetFamilyNames(&familyNames); + hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &familyNames, &exists); + if (!exists) + hr = fontFamily->GetFamilyNames(&familyNames); if (FAILED(hr)) { font->Release(); continue; } - meta.n_family = familyNames->GetCount(); meta.families = (char **) calloc(meta.n_family, sizeof(char *)); for (UINT32 k = 0; k < meta.n_family; ++k) { - hr = familyNames->GetString(k, localeName, LOCALE_NAME_MAX_LENGTH + 1); - + hr = familyNames->GetString(k, temp_name, NAME_MAX_LENGTH); if (FAILED(hr)) { continue; } - size_needed = WideCharToMultiByte(CP_UTF8, 0, localeName, -1, NULL, 0,NULL, NULL); + temp_name[NAME_MAX_LENGTH-1] = 0; + size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0,NULL, NULL); char *mbName = (char *) malloc(size_needed); - WideCharToMultiByte(CP_UTF8, 0, localeName, -1, mbName,size_needed, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, mbName, size_needed, NULL, NULL); meta.families[k] = mbName; } familyNames->Release(); -- 2.40.0