From d04bb46009e51bd5a681f5b0373c23d26ecbe656 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Fri, 12 Apr 2013 19:41:47 +0300 Subject: [PATCH] Gfx: Improve D2D local font support --- Common/Gfx/TextFormatD2D.cpp | 38 ++++++--- Common/Gfx/Util/DWriteHelpers.cpp | 125 ++++++++++++++++++++++++------ Common/Gfx/Util/DWriteHelpers.h | 8 ++ 3 files changed, 136 insertions(+), 35 deletions(-) diff --git a/Common/Gfx/TextFormatD2D.cpp b/Common/Gfx/TextFormatD2D.cpp index a9618a8c..333a0da0 100644 --- a/Common/Gfx/TextFormatD2D.cpp +++ b/Common/Gfx/TextFormatD2D.cpp @@ -93,15 +93,20 @@ void TextFormatD2D::SetProperties( const WCHAR* fontFamily, int size, bool bold, bool italic, const FontCollection* fontCollection) { + auto fontCollectionD2D = (FontCollectionD2D*)fontCollection; + Dispose(); + WCHAR dwriteFamilyName[LF_FACESIZE]; + DWRITE_FONT_WEIGHT dwriteFontWeight = + bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_REGULAR; + DWRITE_FONT_STYLE dwriteFontStyle = + italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; + DWRITE_FONT_STRETCH dwriteFontStretch = DWRITE_FONT_STRETCH_NORMAL; + // |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. - WCHAR dwriteFamilyName[LF_FACESIZE]; - DWRITE_FONT_WEIGHT dwriteFontWeight; - DWRITE_FONT_STYLE dwriteFontStyle; - DWRITE_FONT_STRETCH dwriteFontStretch; HRESULT hr = Util::GetDWritePropertiesFromGDIProperties( CanvasD2D::c_DWFactory, fontFamily, bold, italic, dwriteFontWeight, dwriteFontStyle, dwriteFontStretch, dwriteFamilyName, _countof(dwriteFamilyName)); @@ -121,15 +126,28 @@ void TextFormatD2D::SetProperties( if (FAILED(hr)) { IDWriteFontCollection* dwriteFontCollection = nullptr; - auto fontCollectionD2D = (FontCollectionD2D*)fontCollection; // If |fontFamily| is not in the system collection, use the font collection from // |fontCollectionD2D| if possible. - // - // TODO: Need to check GDI family names of the collection in |fontCollectionD2D|. if (!Util::IsFamilyInSystemFontCollection(CanvasD2D::c_DWFactory, fontFamily) && (fontCollectionD2D && fontCollectionD2D->InitializeCollection())) { + IDWriteFont* dwriteFont = Util::FindDWriteFontInFontCollectionByGDIFamilyName( + fontCollectionD2D->m_Collection, fontFamily); + if (dwriteFont) + { + hr = Util::GetFamilyNameFromDWriteFont( + dwriteFont, dwriteFamilyName, _countof(dwriteFamilyName)); + { + fontFamily = dwriteFamilyName; + Util::GetPropertiesFromDWriteFont( + dwriteFont, bold, italic, &dwriteFontWeight, &dwriteFontStyle, + &dwriteFontStretch); + } + + dwriteFont->Release(); + } + dwriteFontCollection = fontCollectionD2D->m_Collection; } @@ -137,9 +155,9 @@ void TextFormatD2D::SetProperties( hr = CanvasD2D::c_DWFactory->CreateTextFormat( fontFamily, dwriteFontCollection, - bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_REGULAR, - italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, - DWRITE_FONT_STRETCH_NORMAL, + dwriteFontWeight, + dwriteFontStyle, + dwriteFontStretch, size * (4.0f / 3.0f), L"", &m_TextFormat); diff --git a/Common/Gfx/Util/DWriteHelpers.cpp b/Common/Gfx/Util/DWriteHelpers.cpp index dbd55808..dd250bf6 100644 --- a/Common/Gfx/Util/DWriteHelpers.cpp +++ b/Common/Gfx/Util/DWriteHelpers.cpp @@ -32,31 +32,8 @@ HRESULT GetDWritePropertiesFromGDIProperties( { if (GetFamilyNameFromDWriteFont(dwriteFont, dwriteFamilyName, dwriteFamilyNameSize)) { - dwriteFontWeight = dwriteFont->GetWeight(); - if (gdiBold) - { - if (dwriteFontWeight == DWRITE_FONT_WEIGHT_NORMAL) - { - dwriteFontWeight = DWRITE_FONT_WEIGHT_BOLD; - } - else if (dwriteFontWeight < DWRITE_FONT_WEIGHT_ULTRA_BOLD) - { - // If 'gdiFamilyName' was e.g. 'Segoe UI Light', |dwFontWeight| wil be equal to - // DWRITE_FONT_WEIGHT_LIGHT. If |gdiBold| is true in that case, we need to - // increase the weight a little more for similar results with GDI+. - // TODO: Is +100 enough? - dwriteFontWeight = (DWRITE_FONT_WEIGHT)(dwriteFontWeight + 100); - } - } - - dwriteFontStyle = dwriteFont->GetStyle(); - if (gdiItalic && dwriteFontStyle == DWRITE_FONT_STYLE_NORMAL) - { - dwriteFontStyle = DWRITE_FONT_STYLE_ITALIC; - } - - dwriteFontStretch = dwriteFont->GetStretch(); - + GetPropertiesFromDWriteFont( + dwriteFont, gdiBold, gdiItalic, &dwriteFontWeight, &dwriteFontStyle, &dwriteFontStretch); hr = S_OK; } @@ -66,6 +43,37 @@ HRESULT GetDWritePropertiesFromGDIProperties( return hr; } +void GetPropertiesFromDWriteFont( + IDWriteFont* dwriteFont, const bool bold, const bool italic, + DWRITE_FONT_WEIGHT* dwriteFontWeight, DWRITE_FONT_STYLE* dwriteFontStyle, + DWRITE_FONT_STRETCH* dwriteFontStretch) +{ + *dwriteFontWeight = dwriteFont->GetWeight(); + if (bold) + { + if (*dwriteFontWeight == DWRITE_FONT_WEIGHT_NORMAL) + { + *dwriteFontWeight = DWRITE_FONT_WEIGHT_BOLD; + } + else if (*dwriteFontWeight < DWRITE_FONT_WEIGHT_ULTRA_BOLD) + { + // If 'gdiFamilyName' was e.g. 'Segoe UI Light', |dwFontWeight| wil be equal to + // DWRITE_FONT_WEIGHT_LIGHT. If |gdiBold| is true in that case, we need to + // increase the weight a little more for similar results with GDI+. + // TODO: Is +100 enough? + *dwriteFontWeight = (DWRITE_FONT_WEIGHT)(*dwriteFontWeight + 100); + } + } + + *dwriteFontStyle = dwriteFont->GetStyle(); + if (italic && *dwriteFontStyle == DWRITE_FONT_STYLE_NORMAL) + { + *dwriteFontStyle = DWRITE_FONT_STYLE_ITALIC; + } + + *dwriteFontStretch = dwriteFont->GetStretch(); +} + IDWriteFont* CreateDWriteFontFromGDIFamilyName(IDWriteFactory* factory, const WCHAR* gdiFamilyName) { IDWriteGdiInterop* dwGdiInterop; @@ -145,5 +153,72 @@ bool IsFamilyInSystemFontCollection(IDWriteFactory* factory, const WCHAR* family return result; } +HRESULT GetGDIFamilyNameFromDWriteFont(IDWriteFont* font, WCHAR* buffer, UINT bufferSize) +{ + bool result = false; + IDWriteLocalizedStrings* strings; + BOOL stringsExist; + HRESULT hr = font->GetInformationalStrings( + DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &stringsExist); + if (SUCCEEDED(hr) && stringsExist) + { + hr = strings->GetString(0, buffer, bufferSize); + if (SUCCEEDED(hr)) + { + result = true; + } + } + + return result; +} + +IDWriteFont* FindDWriteFontInFontFamilyByGDIFamilyName( + IDWriteFontFamily* fontFamily, const WCHAR* gdiFamilyName) +{ + const UINT32 fontFamilyFontCount = fontFamily->GetFontCount(); + for (UINT32 j = 0; j < fontFamilyFontCount; ++j) + { + IDWriteFont* font; + HRESULT hr = fontFamily->GetFont(j, &font); + if (SUCCEEDED(hr)) + { + WCHAR buffer[LF_FACESIZE]; + if (GetGDIFamilyNameFromDWriteFont(font, buffer, _countof(buffer)) && + _wcsicmp(gdiFamilyName, buffer) == 0) + { + return font; + } + + font->Release(); + } + } + + return nullptr; +} + +IDWriteFont* FindDWriteFontInFontCollectionByGDIFamilyName( + IDWriteFontCollection* fontCollection, const WCHAR* gdiFamilyName) +{ + const UINT32 fontCollectionFamilyCount = fontCollection->GetFontFamilyCount(); + for (UINT32 i = 0; i < fontCollectionFamilyCount; ++i) + { + IDWriteFontFamily* fontFamily; + HRESULT hr = fontCollection->GetFontFamily(i, &fontFamily); + if (SUCCEEDED(hr)) + { + IDWriteFont* font = FindDWriteFontInFontFamilyByGDIFamilyName( + fontFamily, gdiFamilyName); + fontFamily->Release(); + + if (font) + { + return font; + } + } + } + + return nullptr; +} + } // namespace Util } // namespace Gfx diff --git a/Common/Gfx/Util/DWriteHelpers.h b/Common/Gfx/Util/DWriteHelpers.h index 2dbd579d..4ff00413 100644 --- a/Common/Gfx/Util/DWriteHelpers.h +++ b/Common/Gfx/Util/DWriteHelpers.h @@ -31,6 +31,11 @@ HRESULT GetDWritePropertiesFromGDIProperties( DWRITE_FONT_WEIGHT& dwriteFontWeight, DWRITE_FONT_STYLE& dwriteFontStyle, DWRITE_FONT_STRETCH& dwriteFontStretch, WCHAR* dwriteFamilyName, UINT dwriteFamilyNameSize); +void GetPropertiesFromDWriteFont( + IDWriteFont* dwriteFont, const bool bold, const bool italic, + DWRITE_FONT_WEIGHT* dwriteFontWeight, DWRITE_FONT_STYLE* dwriteFontStyle, + DWRITE_FONT_STRETCH* dwriteFontStretch); + // 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 @@ -44,6 +49,9 @@ HRESULT GetFamilyNameFromDWriteFontFamily( bool IsFamilyInSystemFontCollection(IDWriteFactory* factory, const WCHAR* familyName); +IDWriteFont* FindDWriteFontInFontCollectionByGDIFamilyName( + IDWriteFontCollection* fontCollection, const WCHAR* gdiFamilyName); + } // namespace Util } // namespace Gfx