From 82f250dbbb2205bc0e872c3fd71840c3352b5fe1 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Thu, 24 Dec 2015 12:27:37 -0800 Subject: [PATCH] Fix the checks for fake bold/italic EnumFontFamiliesEx doesn't actually use the lfItalic andlfWeight fields, so we have to check separately. --- src/font_file_lister_gdi.cpp | 105 ++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 39 deletions(-) diff --git a/src/font_file_lister_gdi.cpp b/src/font_file_lister_gdi.cpp index 82a46bde5..e4acc121e 100644 --- a/src/font_file_lister_gdi.cpp +++ b/src/font_file_lister_gdi.cpp @@ -109,57 +109,84 @@ CollectionResult GdiFontFileLister::GetFontPaths(std::string const& facename, in LOGFONTW lf{}; lf.lfCharSet = DEFAULT_CHARSET; wcsncpy(lf.lfFaceName, agi::charset::ConvertW(facename).c_str(), LF_FACESIZE); - lf.lfItalic = italic; + lf.lfItalic = italic ? -1 : 0; lf.lfWeight = bold == 0 ? 400 : bold == 1 ? 700 : bold; - auto cb = [&](LOGFONTW const& actual) { - auto hfont = CreateFontIndirectW(&actual); - SelectObject(dc, hfont); - BOOST_SCOPE_EXIT_ALL(=) { - SelectObject(dc, nullptr); - DeleteObject(hfont); + // Gather all of the styles for the given family name + std::vector matches; + using type = decltype(matches); + EnumFontFamiliesEx(dc, &lf, [](const LOGFONT *lf, const TEXTMETRIC *, DWORD, LPARAM lParam) -> int { + reinterpret_cast(lParam)->push_back(*lf); + return 1; + }, (LPARAM)&matches, 0); + + if (matches.empty()) + return ret; + + // If the user asked for a non-regular style, verify that it actually exists + if (italic || bold) { + bool has_bold = false; + bool has_italic = false; + bool has_bold_italic = false; + + auto is_italic = [&](LOGFONTW const& lf) { + return !italic || lf.lfItalic; + }; + auto is_bold = [&](LOGFONTW const& lf) { + return !bold + || (bold == 1 && lf.lfWeight >= 700) + || (bold > 1 && lf.lfWeight > bold); }; - get_font_data(buffer, dc); - - auto it = index.find(buffer); - if (it == end(index)) - return false; // could instead write to a temp dir - - ret.paths.push_back(it->second); - if (actual.lfWeight < lf.lfWeight) - ret.fake_bold = true; - if (actual.lfItalic < lf.lfItalic) - ret.fake_italic = true; - - // Convert the characters to a utf-16 string - std::wstring utf16characters; - utf16characters.reserve(characters.size()); - for (int chr : characters) { - // GetGlyphIndices does not support surrogate pairs, so only check BMP characters - if (chr < std::numeric_limits::max()) - utf16characters.push_back(static_cast(chr)); + for (auto const& match : matches) { + has_bold = has_bold || is_bold(match); + has_italic = has_italic || is_italic(match); + has_bold_italic = has_bold_italic || (is_bold(match) && is_italic(match)); } - std::unique_ptr indices(new WORD[utf16characters.size()]); - GetGlyphIndicesW(dc, utf16characters.data(), utf16characters.size(), - indices.get(), GGI_MARK_NONEXISTING_GLYPHS); + ret.fake_italic = !has_italic; + ret.fake_bold = (italic && has_italic ? !has_bold_italic : !has_bold); + } - for (size_t i = 0; i < utf16characters.size(); ++i) { - if (indices[i] == 0xFFFF) - ret.missing += utf16characters[i]; - } + // Use the family name supplied by EnumFontFamiliesEx as it may be a localized version + memcpy(lf.lfFaceName, matches[0].lfFaceName, LF_FACESIZE); - return true; + // Open the font and get the data for it to look up in the index + auto hfont = CreateFontIndirectW(&lf); + SelectObject(dc, hfont); + BOOST_SCOPE_EXIT_ALL(=) { + SelectObject(dc, nullptr); + DeleteObject(hfont); }; - using type = decltype(cb); - bool found = !EnumFontFamiliesEx(dc, &lf, - [](const LOGFONT *lf, const TEXTMETRIC *, DWORD, LPARAM lParam) -> int { - return !(*reinterpret_cast(lParam))(*lf); - }, (LPARAM)&cb, 0); + get_font_data(buffer, dc); + + auto it = index.find(buffer); + if (it == end(index)) + return ret; // could instead write to a temp dir + + ret.paths.push_back(it->second); + + // Convert the characters to a utf-16 string + std::wstring utf16characters; + utf16characters.reserve(characters.size()); + for (int chr : characters) { + // GetGlyphIndices does not support surrogate pairs, so only check BMP characters + if (chr < std::numeric_limits::max()) + utf16characters.push_back(static_cast(chr)); + } + + // Check the glyph coverage of the matched font + std::unique_ptr indices(new WORD[utf16characters.size()]); + GetGlyphIndicesW(dc, utf16characters.data(), utf16characters.size(), + indices.get(), GGI_MARK_NONEXISTING_GLYPHS); + + for (size_t i = 0; i < utf16characters.size(); ++i) { + if (indices[i] == 0xFFFF) + ret.missing += utf16characters[i]; + } return ret; }