1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-29 02:40:05 +00:00

DirectWriteTypeface: Use GDI fallback behaviour for missing fonts

Previously, when attempting to create a font with a name different to
that of any font on the system, the returned typeface could be nullptr.
This could lead to crashes when attempting to use the typeface.

Now, if we fail to find a matching font using DirectWrite, we fall back
to the older LOGFONT and DC approach, which will generally locate a
usable typeface, though not necessarily an exact match.

The new behaviour more closely matches the behaviour of JUCE 7, which
would attempt to construct a DirectWrite typeface, but would fall back
to creating an HFONT on failure.
This commit is contained in:
reuk 2024-09-17 16:00:14 +01:00
parent 1e0f23baf8
commit 54b157bb8c
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C

View file

@ -181,6 +181,19 @@ public:
return {};
}
ComSmartPtr<IDWriteFont> findFontForFace (IDWriteFontFace* face)
{
for (const auto& collection : collections)
{
ComSmartPtr<IDWriteFont> result;
if (SUCCEEDED (collection->GetFontFromFontFace (face, result.resetAndGetPointerAddress())))
return result;
}
return {};
}
void addCollection (ComSmartPtr<IDWriteFontCollection> collection)
{
const std::scoped_lock lock { mutex };
@ -552,7 +565,7 @@ public:
const auto family = factories->getFonts().getFamilyByName (name.toWideCharPointer());
if (family == nullptr)
return {};
return getLastResortTypeface (f);
const auto weight = f.isBold() ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL;
const auto italic = f.isItalic() ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
@ -831,6 +844,52 @@ private:
collection);
}
// This attempts to replicate the behaviour of the non-directwrite typeface lookup in JUCE 7 and older
static Typeface::Ptr getLastResortTypeface (const Font& font)
{
auto* dc = CreateCompatibleDC (nullptr);
const ScopeGuard deleteDC { [&] { DeleteDC (dc); } };
SetMapperFlags (dc, 0);
SetMapMode (dc, MM_TEXT);
const auto style = font.getTypefaceStyle();
LOGFONTW lf{};
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
lf.lfQuality = PROOF_QUALITY;
lf.lfItalic = (BYTE) (style.contains ("Italic") ? TRUE : FALSE);
lf.lfWeight = style.contains ("Bold") ? FW_BOLD : FW_NORMAL;
lf.lfHeight = -256;
font.getTypefaceName().copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName));
auto* hfont = CreateFontIndirectW (&lf);
const ScopeGuard deleteFont { [&] { DeleteObject (hfont); } };
auto* prevFont = hfont != nullptr ? SelectObject (dc, hfont) : nullptr;
const ScopeGuard reinstateFont { [&] { if (prevFont != nullptr) SelectObject (dc, prevFont); } };
SharedResourcePointer<Direct2DFactories> factories;
ComSmartPtr<IDWriteGdiInterop> interop;
if (FAILED (factories->getDWriteFactory()->GetGdiInterop (interop.resetAndGetPointerAddress())) || interop == nullptr)
return {};
ComSmartPtr<IDWriteFontFace> dwFontFace;
if (FAILED (interop->CreateFontFaceFromHdc (dc, dwFontFace.resetAndGetPointerAddress())) || dwFontFace == nullptr)
return {};
const auto dwFont = factories->getFonts().findFontForFace (dwFontFace);
if (dwFont == nullptr)
return {};
return fromFont (dwFont, nullptr, nullptr, MetricsMechanism::gdiWithDwriteFallback);
}
SharedResourcePointer<Direct2DFactories> factories;
ComSmartPtr<IDWriteFontCollection> collection;
ComSmartPtr<IDWriteFont> dwFont;