diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.cpp b/src/cascadia/TerminalSettingsEditor/Appearances.cpp index fe9cabc824f..15417166ad2 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.cpp +++ b/src/cascadia/TerminalSettingsEditor/Appearances.cpp @@ -419,6 +419,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation BOOL hasPowerlineCharacters = FALSE; til::iterate_font_families(fontFace, [&](wil::zwstring_view name) { + if (primaryFontName.empty()) + { + primaryFontName = name; + } + std::wstring* accumulator = nullptr; UINT32 index = 0; @@ -434,11 +439,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation break; } - if (primaryFontName.empty()) - { - primaryFontName = name; - } - wil::com_ptr fontFamily; THROW_IF_FAILED(fontCollection->GetFontFamily(index, fontFamily.addressof())); diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp index a00a077ef5b..d373926b380 100644 --- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp +++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp @@ -187,6 +187,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation UpdateFontList(); } const auto& currentFontList{ CompleteFontList() }; + fallbackFont = currentFontList.First().Current(); for (const auto& font : currentFontList) { if (font.LocalizedName() == name) diff --git a/src/renderer/atlas/AtlasEngine.api.cpp b/src/renderer/atlas/AtlasEngine.api.cpp index c031f67a154..9c98a12cf52 100644 --- a/src/renderer/atlas/AtlasEngine.api.cpp +++ b/src/renderer/atlas/AtlasEngine.api.cpp @@ -482,32 +482,17 @@ void AtlasEngine::SetWarningCallback(std::functionfont->fontCollection` for a pre-existing font collection, - // before falling back to using the system font collection. This way we can inject our custom one. - // Doing it this way is a bit hacky, but it does have the benefit that we can cache a font collection - // instance across font changes, like when zooming the font size rapidly using the scroll wheel. - try + if (FAILED(hr) && _updateWithNearbyFontCollection()) { - _api.s.write()->font.write()->fontCollection = FontCache::GetCached(); + hr = _updateFont(fontInfoDesired, fontInfo, features, axes); } - CATCH_LOG(); } - try - { - _updateFont(fontInfoDesired, fontInfo, features, axes); - return S_OK; - } - CATCH_RETURN(); + return hr; } void AtlasEngine::UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept @@ -536,7 +521,8 @@ void AtlasEngine::_resolveTransparencySettings() noexcept } } -void AtlasEngine::_updateFont(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, const std::unordered_map& features, const std::unordered_map& axes) +[[nodiscard]] HRESULT AtlasEngine::_updateFont(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, const std::unordered_map& features, const std::unordered_map& axes) noexcept +try { std::vector fontFeatures; if (!features.empty()) @@ -616,9 +602,12 @@ void AtlasEngine::_updateFont(const FontInfoDesired& fontInfoDesired, FontInfo& _resolveFontMetrics(fontInfoDesired, fontInfo, font); font->fontFeatures = std::move(fontFeatures); font->fontAxisValues = std::move(fontAxisValues); + + return S_OK; } +CATCH_RETURN() -void AtlasEngine::_resolveFontMetrics(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, FontSettings* fontMetrics) const +void AtlasEngine::_resolveFontMetrics(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, FontSettings* fontMetrics) { const auto& faceName = fontInfoDesired.GetFaceName(); const auto requestedFamily = fontInfoDesired.GetFamily(); @@ -659,6 +648,16 @@ void AtlasEngine::_resolveFontMetrics(const FontInfoDesired& fontInfoDesired, Fo BOOL exists = false; THROW_IF_FAILED(fontCollection->FindFamilyName(fontName.c_str(), &index, &exists)); + // In case of a portable build, the given font may not be installed and instead be bundled next to our executable. + if constexpr (Feature_NearbyFontLoading::IsEnabled()) + { + if (!exists && _updateWithNearbyFontCollection()) + { + fontCollection = _api.s->font->fontCollection; + THROW_IF_FAILED(fontCollection->FindFamilyName(fontName.c_str(), &index, &exists)); + } + } + if (!exists) { if (!missingFontNames.empty()) @@ -869,3 +868,29 @@ void AtlasEngine::_resolveFontMetrics(const FontInfoDesired& fontInfoDesired, Fo fontMetrics->colorGlyphs = fontInfoDesired.GetEnableColorGlyphs(); } } + +// Nearby fonts are described a couple of times throughout the file. +// This abstraction in particular helps us avoid retrying when it's pointless: +// After all, if the font collection didn't change (no nearby fonts, loading failed, it's already loaded), +// we don't need to try it again. It returns true if retrying is necessary. +[[nodiscard]] bool AtlasEngine::_updateWithNearbyFontCollection() noexcept +{ + // _resolveFontMetrics() checks `_api.s->font->fontCollection` for a pre-existing font collection, + // before falling back to using the system font collection. This way we can inject our custom one. + // Doing it this way is a bit hacky, but it does have the benefit that we can cache a font collection + // instance across font changes, like when zooming the font size rapidly using the scroll wheel. + wil::com_ptr collection; + try + { + collection = FontCache::GetCached(); + } + CATCH_LOG(); + + if (!collection || _api.s->font->fontCollection == collection) + { + return false; + } + + _api.s.write()->font.write()->fontCollection = std::move(collection); + return true; +} diff --git a/src/renderer/atlas/AtlasEngine.h b/src/renderer/atlas/AtlasEngine.h index 5c9f954ae2f..6d346d7bfe4 100644 --- a/src/renderer/atlas/AtlasEngine.h +++ b/src/renderer/atlas/AtlasEngine.h @@ -94,8 +94,9 @@ namespace Microsoft::Console::Render::Atlas // AtlasEngine.api.cpp void _resolveTransparencySettings() noexcept; - void _updateFont(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, const std::unordered_map& features, const std::unordered_map& axes); - void _resolveFontMetrics(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, FontSettings* fontMetrics = nullptr) const; + [[nodiscard]] HRESULT _updateFont(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, const std::unordered_map& features, const std::unordered_map& axes) noexcept; + void _resolveFontMetrics(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, FontSettings* fontMetrics = nullptr); + [[nodiscard]] bool _updateWithNearbyFontCollection() noexcept; // AtlasEngine.r.cpp ATLAS_ATTR_COLD void _recreateAdapter();