A minor cleanup of ProfileViewModel (#16788)

This is just a minor cleanup I did as a drive-by while working on
customized font fallback. The benefit of this change is that it's
a tiny bit less expensive, but also that it's a lot easier to read.
The split into "get index" and "get string by index" helps us to
more easily handle both, missing locales and locale fallback.
The code that ties everything together then ends up being just 7 lines.
This commit is contained in:
Leonard Hecker 2024-02-29 21:25:29 +01:00 committed by GitHub
parent 6e451a2d4b
commit b780d8ab7e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 38 additions and 54 deletions

View File

@ -31,9 +31,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
struct Font : FontT<Font>
{
public:
Font(std::wstring name, std::wstring localizedName, IDWriteFontFamily* family) :
_Name{ name },
_LocalizedName{ localizedName }
Font(winrt::hstring name, winrt::hstring localizedName, IDWriteFontFamily* family) :
_Name{ std::move(name) },
_LocalizedName{ std::move(localizedName) }
{
_family.copy_from(family);
}

View File

@ -22,7 +22,7 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
static Editor::Font _FontObjectForDWriteFont(IDWriteFontFamily* family);
static Editor::Font fontObjectForDWriteFont(IDWriteFontFamily* family, const wchar_t* locale);
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_MonospaceFontList{ nullptr };
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_FontList{ nullptr };
@ -119,6 +119,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
wil::com_ptr<IDWriteFontCollection> fontCollection;
THROW_IF_FAILED(factory->GetSystemFontCollection(fontCollection.addressof(), TRUE));
wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
if (!GetUserDefaultLocaleName(&localeName[0], LOCALE_NAME_MAX_LENGTH))
{
memcpy(&localeName[0], L"en-US", 12);
}
for (UINT32 i = 0; i < fontCollection->GetFontFamilyCount(); ++i)
{
try
@ -128,7 +134,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
THROW_IF_FAILED(fontCollection->GetFontFamily(i, fontFamily.put()));
// construct a font entry for tracking
if (const auto fontEntry{ _FontObjectForDWriteFont(fontFamily.get()) })
if (const auto fontEntry{ fontObjectForDWriteFont(fontFamily.get(), &localeName[0]) })
{
// check if the font is monospaced
try
@ -199,65 +205,43 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return fallbackFont;
}
static Editor::Font _FontObjectForDWriteFont(IDWriteFontFamily* family)
static winrt::hstring getLocalizedStringByIndex(IDWriteLocalizedStrings* strings, UINT32 index)
{
// used for the font's name as an identifier (i.e. text block's font family property)
std::wstring nameID;
UINT32 nameIDIndex;
UINT32 length = 0;
THROW_IF_FAILED(strings->GetStringLength(index, &length));
// used for the font's localized name
std::wstring localizedName;
UINT32 localizedNameIndex;
winrt::impl::hstring_builder builder{ length };
THROW_IF_FAILED(strings->GetString(index, builder.data(), length + 1));
// get the font's localized names
winrt::com_ptr<IDWriteLocalizedStrings> localizedFamilyNames;
THROW_IF_FAILED(family->GetFamilyNames(localizedFamilyNames.put()));
return builder.to_hstring();
}
// use our current locale to find the localized name
auto exists{ FALSE };
HRESULT hr;
wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH))
static UINT32 getLocalizedStringIndex(IDWriteLocalizedStrings* strings, const wchar_t* locale, UINT32 fallback)
{
UINT32 index;
BOOL exists;
if (FAILED(strings->FindLocaleName(locale, &index, &exists)) || !exists)
{
hr = localizedFamilyNames->FindLocaleName(localeName, &localizedNameIndex, &exists);
}
if (SUCCEEDED(hr) && !exists)
{
// if we can't find the font for our locale, fallback to the en-us one
// Source: https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritelocalizedstrings-findlocalename
hr = localizedFamilyNames->FindLocaleName(L"en-us", &localizedNameIndex, &exists);
}
if (!exists)
{
// failed to find the correct locale, using the first one
localizedNameIndex = 0;
index = fallback;
}
return index;
}
// get the localized name
UINT32 nameLength;
THROW_IF_FAILED(localizedFamilyNames->GetStringLength(localizedNameIndex, &nameLength));
static Editor::Font fontObjectForDWriteFont(IDWriteFontFamily* family, const wchar_t* locale)
{
wil::com_ptr<IDWriteLocalizedStrings> familyNames;
THROW_IF_FAILED(family->GetFamilyNames(familyNames.addressof()));
localizedName.resize(nameLength);
THROW_IF_FAILED(localizedFamilyNames->GetString(localizedNameIndex, localizedName.data(), nameLength + 1));
// If en-us is missing we fall back to whatever is at index 0.
const auto ci = getLocalizedStringIndex(familyNames.get(), L"en-us", 0);
// If our locale is missing we fall back to en-us.
const auto li = getLocalizedStringIndex(familyNames.get(), locale, ci);
// now get the nameID
hr = localizedFamilyNames->FindLocaleName(L"en-us", &nameIDIndex, &exists);
if (FAILED(hr) || !exists)
{
// failed to find it, using the first one
nameIDIndex = 0;
}
auto canonical = getLocalizedStringByIndex(familyNames.get(), ci);
// If the canonical/localized indices are the same, there's no need to get the other string.
auto localized = ci == li ? canonical : getLocalizedStringByIndex(familyNames.get(), li);
// get the nameID
THROW_IF_FAILED(localizedFamilyNames->GetStringLength(nameIDIndex, &nameLength));
nameID.resize(nameLength);
THROW_IF_FAILED(localizedFamilyNames->GetString(nameIDIndex, nameID.data(), nameLength + 1));
if (!nameID.empty() && !localizedName.empty())
{
return make<Font>(nameID, localizedName, family);
}
return nullptr;
return make<Font>(std::move(canonical), std::move(localized), family);
}
winrt::guid ProfileViewModel::OriginalProfileGuid() const noexcept