mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 18:43:54 -06:00
* Since `FindFontWithLocalizedName` is broken (intentionally and temporarily until #16943 is fixed) we have to be extra be careful not to return a nullptr `Font`. * Portable builds may not have a broken font cache, but also not have the given font (Cascadia Mono for instance) installed. This requires us to load the nearby fonts even if there aren't any exceptions. ## Validation Steps Performed * Open `src/cascadia/CascadiaResources.build.items` and remove the `Condition` for .ttf files * Deploy on a clean Windows 10 VM * Cascadia Mono loads without issues ✅ * Open the `Settings > Defaults > Appearance`, enter a non-existing font and hit Save * Doesn't crash ✅
This commit is contained in:
parent
3cc82a51d8
commit
9f3dbab7bf
@ -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<IDWriteFontFamily> fontFamily;
|
||||
THROW_IF_FAILED(fontCollection->GetFontFamily(index, fontFamily.addressof()));
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -482,32 +482,17 @@ void AtlasEngine::SetWarningCallback(std::function<void(HRESULT, wil::zwstring_v
|
||||
// commit 9e86c98 (PR #16196), because it showed that it's definitely not due to FindFamilyName() failing.
|
||||
//
|
||||
// The workaround is to catch the exception and retry it with our nearby fonts manually loaded in.
|
||||
HRESULT hr = _updateFont(fontInfoDesired, fontInfo, features, axes);
|
||||
|
||||
if constexpr (Feature_NearbyFontLoading::IsEnabled())
|
||||
{
|
||||
try
|
||||
if (FAILED(hr) && _updateWithNearbyFontCollection())
|
||||
{
|
||||
_updateFont(fontInfoDesired, fontInfo, features, axes);
|
||||
return S_OK;
|
||||
hr = _updateFont(fontInfoDesired, fontInfo, features, axes);
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
// _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.
|
||||
try
|
||||
{
|
||||
_api.s.write()->font.write()->fontCollection = FontCache::GetCached();
|
||||
}
|
||||
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<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes)
|
||||
[[nodiscard]] HRESULT AtlasEngine::_updateFont(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, const std::unordered_map<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes) noexcept
|
||||
try
|
||||
{
|
||||
std::vector<DWRITE_FONT_FEATURE> 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);
|
||||
}
|
||||
|
||||
void AtlasEngine::_resolveFontMetrics(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, FontSettings* fontMetrics) const
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
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<IDWriteFontCollection> 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;
|
||||
}
|
||||
|
||||
@ -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<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes);
|
||||
void _resolveFontMetrics(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, FontSettings* fontMetrics = nullptr) const;
|
||||
[[nodiscard]] HRESULT _updateFont(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, const std::unordered_map<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes) noexcept;
|
||||
void _resolveFontMetrics(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, FontSettings* fontMetrics = nullptr);
|
||||
[[nodiscard]] bool _updateWithNearbyFontCollection() noexcept;
|
||||
|
||||
// AtlasEngine.r.cpp
|
||||
ATLAS_ATTR_COLD void _recreateAdapter();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user