diff --git a/Common/Gfx/CanvasD2D.cpp b/Common/Gfx/CanvasD2D.cpp index fbf96bb2..4624a03a 100644 --- a/Common/Gfx/CanvasD2D.cpp +++ b/Common/Gfx/CanvasD2D.cpp @@ -55,6 +55,7 @@ namespace Gfx { UINT CanvasD2D::c_Instances = 0; ID2D1Factory* CanvasD2D::c_D2D = nullptr; IDWriteFactory* CanvasD2D::c_DW = nullptr; +IDWriteGdiInterop* CanvasD2D::c_DWGDIInterop = nullptr; IWICImagingFactory* CanvasD2D::c_WIC = nullptr; CanvasD2D::CanvasD2D() : Canvas(), @@ -102,6 +103,9 @@ bool CanvasD2D::Initialize() __uuidof(IDWriteFactory), (IUnknown**)&c_DW); if (FAILED(hr)) return false; + + hr = c_DW->GetGdiInterop(&c_DWGDIInterop); + if (FAILED(hr)) return false; } return true; @@ -114,6 +118,7 @@ void CanvasD2D::Finalize() { SafeRelease(&c_D2D); SafeRelease(&c_WIC); + SafeRelease(&c_DWGDIInterop); SafeRelease(&c_DW); } } diff --git a/Common/Gfx/CanvasD2D.h b/Common/Gfx/CanvasD2D.h index c86e6348..d45f6bb1 100644 --- a/Common/Gfx/CanvasD2D.h +++ b/Common/Gfx/CanvasD2D.h @@ -98,6 +98,7 @@ private: static UINT c_Instances; static ID2D1Factory* c_D2D; static IDWriteFactory* c_DW; + static IDWriteGdiInterop* c_DWGDIInterop; static IWICImagingFactory* c_WIC; }; diff --git a/Common/Gfx/TextFormatD2D.cpp b/Common/Gfx/TextFormatD2D.cpp index 5ddc3669..af5144d6 100644 --- a/Common/Gfx/TextFormatD2D.cpp +++ b/Common/Gfx/TextFormatD2D.cpp @@ -92,15 +92,46 @@ void TextFormatD2D::SetProperties(const WCHAR* fontFamily, int size, bool bold, { Dispose(); - HRESULT hr = CanvasD2D::c_DW->CreateTextFormat( - fontFamily, - nullptr, - bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_REGULAR, - italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, - DWRITE_FONT_STRETCH_NORMAL, - size * (4.0f / 3.0f), - L"", - &m_TextFormat); + HRESULT hr = E_FAIL; + + // |fontFamily| uses the GDI/GDI+ font naming convention so try to create DirectWrite font + // using the GDI family name and then create a text format using the DirectWrite family name + // obtained from it. + IDWriteFont* dwFont = CreateDWFontFromGDIFamilyName(fontFamily, bold, italic); + if (dwFont) + { + WCHAR buffer[LF_FACESIZE]; + if (GetDWFontFamilyName(dwFont, buffer, _countof(buffer))) + { + // TODO: If |fontFamily| is e.g. 'Segoe UI Semibold' and |bold| is true, we might want + // to make the weight heaver to match GDI+. + hr = CanvasD2D::c_DW->CreateTextFormat( + buffer, + nullptr, + dwFont->GetWeight(), + dwFont->GetStyle(), + DWRITE_FONT_STRETCH_NORMAL, + size * (4.0f / 3.0f), + L"", + &m_TextFormat); + } + + dwFont->Release(); + } + + if (FAILED(hr)) + { + // Fallback in case above fails. + hr = CanvasD2D::c_DW->CreateTextFormat( + fontFamily, + nullptr, + bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_REGULAR, + italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, + size * (4.0f / 3.0f), + L"", + &m_TextFormat); + } if (SUCCEEDED(hr)) { @@ -160,4 +191,58 @@ void TextFormatD2D::SetVerticalAlignment(VerticalAlignment alignment) } } +IDWriteFont* TextFormatD2D::CreateDWFontFromGDIFamilyName(const WCHAR* fontFamily, bool bold, bool italic) +{ + IDWriteGdiInterop* dwGdiInterop; + HRESULT hr = CanvasD2D::c_DW->GetGdiInterop(&dwGdiInterop); + if (SUCCEEDED(hr)) + { + LOGFONT lf = {}; + wcscpy_s(lf.lfFaceName, fontFamily); + lf.lfWidth = 12; + lf.lfHeight = 12; + lf.lfWeight = bold ? FW_BOLD : FW_NORMAL; + lf.lfItalic = (BYTE)italic; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = ANTIALIASED_QUALITY; + lf.lfPitchAndFamily = VARIABLE_PITCH; + + IDWriteFont* dwFont; + hr = dwGdiInterop->CreateFontFromLOGFONT(&lf, &dwFont); + if (SUCCEEDED(hr)) + { + return dwFont; + } + + dwGdiInterop->Release(); + } + + return nullptr; +} + +bool TextFormatD2D::GetDWFontFamilyName(IDWriteFont* font, WCHAR* buffer, const UINT bufferSize) +{ + bool result = false; + IDWriteFontFamily* dwFontFamily; + HRESULT hr = font->GetFontFamily(&dwFontFamily); + if (SUCCEEDED(hr)) + { + IDWriteLocalizedStrings* dwFamilyNames; + hr = dwFontFamily->GetFamilyNames(&dwFamilyNames); + if (SUCCEEDED(hr)) + { + // TODO: Determine the best index? + hr = dwFamilyNames->GetString(0, buffer, bufferSize); + result = SUCCEEDED(hr); + dwFamilyNames->Release(); + } + + dwFontFamily->Release(); + } + + return result; +} + } // namespace Gfx diff --git a/Common/Gfx/TextFormatD2D.h b/Common/Gfx/TextFormatD2D.h index 7e44bf39..c6a9ecc9 100644 --- a/Common/Gfx/TextFormatD2D.h +++ b/Common/Gfx/TextFormatD2D.h @@ -50,6 +50,14 @@ private: // changes. void CreateLayout(const WCHAR* str, UINT strLen, float maxW, float maxH); + // Creates a IDWriteFont using the GDI family name instead of the DirectWrite family name. For + // example, 'Segoe UI' and 'Segoe UI Semibold' are separate family names with GDI whereas + // DirectWrite uses the family name 'Segoe UI' for both and differentiates them by the font + // style. + static IDWriteFont* CreateDWFontFromGDIFamilyName(const WCHAR* fontFamily, bool bold, bool italic); + + static bool GetDWFontFamilyName(IDWriteFont* font, WCHAR* buffer, UINT bufferSize); + IDWriteTextFormat* m_TextFormat; IDWriteTextLayout* m_TextLayout; IDWriteInlineObject* m_InlineEllipsis;