Fix the checks for fake bold/italic

EnumFontFamiliesEx doesn't actually use the lfItalic andlfWeight fields,
so we have to check separately.
This commit is contained in:
Thomas Goyne 2015-12-24 12:27:37 -08:00
parent ddc5cd155f
commit 82f250dbbb
1 changed files with 66 additions and 39 deletions

View File

@ -109,57 +109,84 @@ CollectionResult GdiFontFileLister::GetFontPaths(std::string const& facename, in
LOGFONTW lf{}; LOGFONTW lf{};
lf.lfCharSet = DEFAULT_CHARSET; lf.lfCharSet = DEFAULT_CHARSET;
wcsncpy(lf.lfFaceName, agi::charset::ConvertW(facename).c_str(), LF_FACESIZE); wcsncpy(lf.lfFaceName, agi::charset::ConvertW(facename).c_str(), LF_FACESIZE);
lf.lfItalic = italic; lf.lfItalic = italic ? -1 : 0;
lf.lfWeight = bold == 0 ? 400 : lf.lfWeight = bold == 0 ? 400 :
bold == 1 ? 700 : bold == 1 ? 700 :
bold; bold;
auto cb = [&](LOGFONTW const& actual) { // Gather all of the styles for the given family name
auto hfont = CreateFontIndirectW(&actual); std::vector<LOGFONTW> matches;
SelectObject(dc, hfont); using type = decltype(matches);
BOOST_SCOPE_EXIT_ALL(=) { EnumFontFamiliesEx(dc, &lf, [](const LOGFONT *lf, const TEXTMETRIC *, DWORD, LPARAM lParam) -> int {
SelectObject(dc, nullptr); reinterpret_cast<type*>(lParam)->push_back(*lf);
DeleteObject(hfont); 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); for (auto const& match : matches) {
has_bold = has_bold || is_bold(match);
auto it = index.find(buffer); has_italic = has_italic || is_italic(match);
if (it == end(index)) has_bold_italic = has_bold_italic || (is_bold(match) && is_italic(match));
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<wchar_t>::max())
utf16characters.push_back(static_cast<wchar_t>(chr));
} }
std::unique_ptr<WORD[]> indices(new WORD[utf16characters.size()]); ret.fake_italic = !has_italic;
GetGlyphIndicesW(dc, utf16characters.data(), utf16characters.size(), ret.fake_bold = (italic && has_italic ? !has_bold_italic : !has_bold);
indices.get(), GGI_MARK_NONEXISTING_GLYPHS); }
for (size_t i = 0; i < utf16characters.size(); ++i) { // Use the family name supplied by EnumFontFamiliesEx as it may be a localized version
if (indices[i] == 0xFFFF) memcpy(lf.lfFaceName, matches[0].lfFaceName, LF_FACESIZE);
ret.missing += utf16characters[i];
}
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); get_font_data(buffer, dc);
bool found = !EnumFontFamiliesEx(dc, &lf,
[](const LOGFONT *lf, const TEXTMETRIC *, DWORD, LPARAM lParam) -> int { auto it = index.find(buffer);
return !(*reinterpret_cast<type*>(lParam))(*lf); if (it == end(index))
}, (LPARAM)&cb, 0); 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<wchar_t>::max())
utf16characters.push_back(static_cast<wchar_t>(chr));
}
// Check the glyph coverage of the matched font
std::unique_ptr<WORD[]> 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; return ret;
} }