diff --git a/src/renderer/gdi/gdirenderer.hpp b/src/renderer/gdi/gdirenderer.hpp index d8bac22131..c418e24f5a 100644 --- a/src/renderer/gdi/gdirenderer.hpp +++ b/src/renderer/gdi/gdirenderer.hpp @@ -102,8 +102,25 @@ namespace Microsoft::Console::Render HDC _hdcMemoryContext; bool _isTrueTypeFont; UINT _fontCodepage; - HFONT _hfont; - HFONT _hfontItalic; + + enum class FontType : uint8_t + { + // Indices for _hfonts array below + Default, + Bold, + Italic, + BoldItalic, + + // The number of fonts in _hfonts array below + FontCount, + + // Other + Undefined = FontCount, + Soft + }; + + std::array(FontType::FontCount)> _hfonts{}; + TEXTMETRICW _tmFontMetrics; FontResource _softFont; @@ -147,13 +164,6 @@ namespace Microsoft::Console::Render COLORREF _lastFg; COLORREF _lastBg; - enum class FontType : uint8_t - { - Undefined, - Default, - Italic, - Soft - }; FontType _lastFontType; bool _fontHasWesternScript = false; @@ -194,8 +204,7 @@ namespace Microsoft::Console::Render [[nodiscard]] HRESULT _GetProposedFont(const FontInfoDesired& FontDesired, _Out_ FontInfo& Font, const int iDpi, - _Inout_ wil::unique_hfont& hFont, - _Inout_ wil::unique_hfont& hFontItalic) noexcept; + _Inout_ std::array(FontType::FontCount)>& hFonts) noexcept; til::size _GetFontSize() const; bool _IsMinimized() const; diff --git a/src/renderer/gdi/state.cpp b/src/renderer/gdi/state.cpp index 8e498fc7dd..62a20591c5 100644 --- a/src/renderer/gdi/state.cpp +++ b/src/renderer/gdi/state.cpp @@ -34,8 +34,6 @@ GdiEngine::GdiEngine() : _currentLineRendition(LineRendition::SingleWidth), _fPaintStarted(false), _invalidCharacters{}, - _hfont(nullptr), - _hfontItalic(nullptr), _pool{ til::pmr::get_default_resource() }, // It's important the pool is first so it can be given to the others on construction. _polyStrings{ &_pool }, _polyWidths{ &_pool } @@ -90,16 +88,13 @@ GdiEngine::~GdiEngine() _hbitmapMemorySurface = nullptr; } - if (_hfont != nullptr) + for (auto& hfont : _hfonts) { - LOG_HR_IF(E_FAIL, !(DeleteObject(_hfont))); - _hfont = nullptr; - } - - if (_hfontItalic != nullptr) - { - LOG_HR_IF(E_FAIL, !(DeleteObject(_hfontItalic))); - _hfontItalic = nullptr; + if (hfont != nullptr) + { + LOG_HR_IF(E_FAIL, !(DeleteObject(hfont))); + hfont = nullptr; + } } if (_hdcMemoryContext != nullptr) @@ -300,24 +295,48 @@ GdiEngine::~GdiEngine() } // If the font type has changed, select an appropriate font variant or soft font. - const auto usingItalicFont = textAttributes.IsItalic(); - const auto fontType = usingSoftFont ? FontType::Soft : - usingItalicFont ? FontType::Italic : - FontType::Default; + const auto fontType = [&] { + if (usingSoftFont) + { + return FontType::Soft; + } + + // TODO: GH-18919 "Intense text as bold" option + const auto usingBoldFont = textAttributes.IsBold(false); + const auto usingItalicFont = textAttributes.IsItalic(); + + if (usingBoldFont && !usingItalicFont) + { + return FontType::Bold; + } + if (!usingBoldFont && usingItalicFont) + { + return FontType::Italic; + } + if (usingBoldFont && usingItalicFont) + { + return FontType::BoldItalic; + } + return FontType::Default; + }(); + if (fontType != _lastFontType) { switch (fontType) { + case FontType::Default: + case FontType::Bold: + case FontType::Italic: + case FontType::BoldItalic: + SelectFont(_hdcMemoryContext, _hfonts[static_cast(fontType)]); + break; + case FontType::Soft: SelectFont(_hdcMemoryContext, _softFont); break; - case FontType::Italic: - SelectFont(_hdcMemoryContext, _hfontItalic); - break; - case FontType::Default: + default: - SelectFont(_hdcMemoryContext, _hfont); - break; + __assume(false); } _lastFontType = fontType; _fontHasWesternScript = FontHasWesternScript(_hdcMemoryContext); @@ -336,11 +355,11 @@ GdiEngine::~GdiEngine() // - S_OK if set successfully or relevant GDI error via HRESULT. [[nodiscard]] HRESULT GdiEngine::UpdateFont(const FontInfoDesired& FontDesired, _Out_ FontInfo& Font) noexcept { - wil::unique_hfont hFont, hFontItalic; - RETURN_IF_FAILED(_GetProposedFont(FontDesired, Font, _iCurrentDpi, hFont, hFontItalic)); + std::array(FontType::FontCount)> hFonts; + RETURN_IF_FAILED(_GetProposedFont(FontDesired, Font, _iCurrentDpi, hFonts)); // Select into DC - RETURN_HR_IF_NULL(E_FAIL, SelectFont(_hdcMemoryContext, hFont.get())); + RETURN_HR_IF_NULL(E_FAIL, SelectFont(_hdcMemoryContext, hFonts[static_cast(FontType::Default)].get())); // Save off the font metrics for various other calculations RETURN_HR_IF(E_FAIL, !(GetTextMetricsW(_hdcMemoryContext, &_tmFontMetrics))); @@ -454,26 +473,19 @@ GdiEngine::~GdiEngine() // Now find the size of a 0 in this current font and save it for conversions done later. _coordFontLast = Font.GetSize(); - // Persist font for cleanup (and free existing if necessary) - if (_hfont != nullptr) + for (auto& hfont : _hfonts) { - LOG_HR_IF(E_FAIL, !(DeleteObject(_hfont))); - _hfont = nullptr; + // Persist font for cleanup (and free existing if necessary) + if (hfont != nullptr) + { + LOG_HR_IF(E_FAIL, !(DeleteObject(hfont))); + hfont = nullptr; + } + + // Save the font. + hfont = hFonts[&hfont - _hfonts.data()].release(); } - // Save the font. - _hfont = hFont.release(); - - // Persist italic font for cleanup (and free existing if necessary) - if (_hfontItalic != nullptr) - { - LOG_HR_IF(E_FAIL, !(DeleteObject(_hfontItalic))); - _hfontItalic = nullptr; - } - - // Save the italic font. - _hfontItalic = hFontItalic.release(); - // Save raster vs. TrueType and codepage data in case we need to convert. _isTrueTypeFont = Font.IsTrueTypeFont(); _fontCodepage = Font.GetCodePage(); @@ -500,10 +512,10 @@ GdiEngine::~GdiEngine() { // If we previously called SelectFont(_hdcMemoryContext, _softFont), it will // still hold a reference to the _softFont object we're planning to overwrite. - // --> First revert back to the standard _hfont, lest we have dangling pointers. + // --> First revert back to the standard font, lest we have dangling pointers. if (_lastFontType == FontType::Soft) { - RETURN_HR_IF_NULL(E_FAIL, SelectFont(_hdcMemoryContext, _hfont)); + RETURN_HR_IF_NULL(E_FAIL, SelectFont(_hdcMemoryContext, _hfonts[static_cast(FontType::Default)])); _lastFontType = FontType::Default; } @@ -550,8 +562,8 @@ GdiEngine::~GdiEngine() // - S_OK if set successfully or relevant GDI error via HRESULT. [[nodiscard]] HRESULT GdiEngine::GetProposedFont(const FontInfoDesired& FontDesired, _Out_ FontInfo& Font, const int iDpi) noexcept { - wil::unique_hfont hFont, hFontItalic; - return _GetProposedFont(FontDesired, Font, iDpi, hFont, hFontItalic); + std::array(FontType::FontCount)> hFonts; + return _GetProposedFont(FontDesired, Font, iDpi, hFonts); } // Method Description: @@ -576,15 +588,13 @@ GdiEngine::~GdiEngine() // - FontDesired - reference to font information we should use while instantiating a font. // - Font - the actual font // - iDpi - The DPI we will have when rendering -// - hFont - A smart pointer to receive a handle to a ready-to-use GDI font. -// - hFontItalic - A smart pointer to receive a handle to an italic variant of the font. +// - hFonts - An array of smart pointers to receive handles to ready-to-use GDI fonts, corresponding to FontType enum. // Return Value: // - S_OK if set successfully or relevant GDI error via HRESULT. [[nodiscard]] HRESULT GdiEngine::_GetProposedFont(const FontInfoDesired& FontDesired, _Out_ FontInfo& Font, const int iDpi, - _Inout_ wil::unique_hfont& hFont, - _Inout_ wil::unique_hfont& hFontItalic) noexcept + _Inout_ std::array(FontType::FontCount)>& hFonts) noexcept { wil::unique_hdc hdcTemp(CreateCompatibleDC(_hdcMemoryContext)); RETURN_HR_IF_NULL(E_FAIL, hdcTemp.get()); @@ -600,8 +610,10 @@ GdiEngine::~GdiEngine() // We do this because, for instance, if we ask GDI for an 8x12 OEM_FIXED_FONT, // it may very well decide to choose Courier New instead of the Terminal raster. #pragma prefast(suppress : 38037, "raster fonts get special handling, we need to get it this way") - hFont.reset((HFONT)GetStockObject(OEM_FIXED_FONT)); - hFontItalic.reset((HFONT)GetStockObject(OEM_FIXED_FONT)); + for (auto& hFont : hFonts) + { + hFont.reset((HFONT)GetStockObject(OEM_FIXED_FONT)); + } } else { @@ -658,18 +670,35 @@ GdiEngine::~GdiEngine() FontDesired.FillLegacyNameBuffer(lf.lfFaceName); - // Create font. - hFont.reset(CreateFontIndirectW(&lf)); - RETURN_HR_IF_NULL(E_FAIL, hFont.get()); + struct FontStyle + { + LONG weight; + BYTE italic; + }; - // Create italic variant of the font. - lf.lfItalic = TRUE; - hFontItalic.reset(CreateFontIndirectW(&lf)); - RETURN_HR_IF_NULL(E_FAIL, hFontItalic.get()); + static constexpr FontStyle s_fontStyles[] = { + { FW_NORMAL, FALSE }, // Default + { FW_BOLD, FALSE }, // Bold + { FW_NORMAL, TRUE }, // Italic + { FW_BOLD, TRUE }, // BoldItalic + }; + + static_assert(std::size(s_fontStyles) == static_cast(FontType::FontCount)); + + for (const auto& style : s_fontStyles) + { + lf.lfWeight = style.weight == FW_NORMAL ? FontDesired.GetWeight() : style.weight; + lf.lfItalic = style.italic; + + // Create font. + auto& hFont = hFonts[&style - s_fontStyles]; + hFont.reset(CreateFontIndirectW(&lf)); + RETURN_HR_IF_NULL(E_FAIL, hFont.get()); + } } // Select into DC - wil::unique_hfont hFontOld(SelectFont(hdcTemp.get(), hFont.get())); + wil::unique_hfont hFontOld(SelectFont(hdcTemp.get(), hFonts[static_cast(FontType::Default)].get())); RETURN_HR_IF_NULL(E_FAIL, hFontOld.get()); // Save off the font metrics for various other calculations