Fonts.cpp (6758B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include <AppInstallerStrings.h> 5 #include <winget/Fonts.h> 6 #include <winget/Locale.h> 7 8 namespace AppInstaller::Fonts 9 { 10 namespace 11 { 12 std::vector<std::filesystem::path> GetFontFilePaths(const wil::com_ptr<IDWriteFontFace>& fontFace) 13 { 14 UINT32 fileCount = 0; 15 THROW_IF_FAILED(fontFace->GetFiles(&fileCount, nullptr)); 16 17 static_assert(sizeof(wil::com_ptr<IDWriteFontFile>) == sizeof(IDWriteFontFile*)); 18 std::vector<wil::com_ptr<IDWriteFontFile>> fontFiles; 19 fontFiles.resize(fileCount); 20 21 THROW_IF_FAILED(fontFace->GetFiles(&fileCount, fontFiles[0].addressof())); 22 23 std::vector<std::filesystem::path> filePaths; 24 for (UINT32 i = 0; i < fileCount; ++i) { 25 wil::com_ptr<IDWriteFontFileLoader> loader; 26 THROW_IF_FAILED(fontFiles[i]->GetLoader(loader.addressof())); 27 28 const void* fontFileReferenceKey; 29 UINT32 fontFileReferenceKeySize; 30 THROW_IF_FAILED(fontFiles[i]->GetReferenceKey(&fontFileReferenceKey, &fontFileReferenceKeySize)); 31 32 if (const auto localLoader = loader.try_query<IDWriteLocalFontFileLoader>()) { 33 UINT32 pathLength; 34 THROW_IF_FAILED(localLoader->GetFilePathLengthFromKey(fontFileReferenceKey, fontFileReferenceKeySize, &pathLength)); 35 pathLength += 1; // Account for the trailing null terminator during allocation. 36 37 std::wstring path; 38 path.resize(pathLength); 39 THROW_IF_FAILED(localLoader->GetFilePathFromKey(fontFileReferenceKey, fontFileReferenceKeySize, &path[0], pathLength)); 40 path.resize(pathLength - 1); // Remove the null char. 41 filePaths.emplace_back(std::move(path)); 42 } 43 } 44 45 return filePaths; 46 } 47 } 48 49 FontCatalog::FontCatalog() 50 { 51 m_preferredLocales = AppInstaller::Locale::GetUserPreferredLanguagesUTF16(); 52 } 53 54 std::vector<FontFamily> FontCatalog::GetInstalledFontFamilies(std::optional<std::wstring> familyName) 55 { 56 wil::com_ptr<IDWriteFactory7> factory; 57 THROW_IF_FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(factory), factory.put_unknown())); 58 59 wil::com_ptr<IDWriteFontCollection> collection; 60 THROW_IF_FAILED(factory->GetSystemFontCollection(collection.addressof(), FALSE)); 61 62 std::vector<FontFamily> installedFontFamilies; 63 64 if (familyName.has_value()) 65 { 66 UINT32 index; 67 BOOL exists; 68 THROW_IF_FAILED(collection->FindFamilyName(familyName.value().c_str(), &index, &exists)); 69 70 if (exists) 71 { 72 installedFontFamilies.emplace_back(GetFontFamilyByIndex(collection, index)); 73 } 74 } 75 else 76 { 77 UINT32 familyCount = collection->GetFontFamilyCount(); 78 79 for (UINT32 index = 0; index < familyCount; index++) 80 { 81 installedFontFamilies.emplace_back(GetFontFamilyByIndex(collection, index)); 82 } 83 } 84 85 return installedFontFamilies; 86 } 87 88 std::wstring FontCatalog::GetLocalizedStringFromFont(const wil::com_ptr<IDWriteLocalizedStrings>& localizedStringCollection) 89 { 90 UINT32 index = 0; 91 BOOL exists = false; 92 93 for (const auto& locale : m_preferredLocales) 94 { 95 if (SUCCEEDED_LOG(localizedStringCollection->FindLocaleName(locale.c_str(), &index, &exists)) && exists) 96 { 97 break; 98 } 99 } 100 101 // If the locale does not exist, resort to the default value at the 0 index. 102 if (!exists) 103 { 104 index = 0; 105 } 106 107 UINT32 length = 0; 108 THROW_IF_FAILED(localizedStringCollection->GetStringLength(index, &length)); 109 length += 1; // Account for the trailing null terminator during allocation. 110 111 std::wstring localizedString; 112 localizedString.resize(length); 113 THROW_IF_FAILED(localizedStringCollection->GetString(index, &localizedString[0], length)); 114 localizedString.resize(length - 1); // Remove the null char. 115 return localizedString; 116 } 117 118 std::wstring FontCatalog::GetFontFaceName(const wil::com_ptr<IDWriteFont>& font) 119 { 120 wil::com_ptr<IDWriteLocalizedStrings> faceNames; 121 THROW_IF_FAILED(font->GetFaceNames(faceNames.addressof())); 122 return GetLocalizedStringFromFont(faceNames); 123 } 124 125 std::wstring FontCatalog::GetFontFamilyName(const wil::com_ptr<IDWriteFontFamily>& fontFamily) 126 { 127 wil::com_ptr<IDWriteLocalizedStrings> familyNames; 128 THROW_IF_FAILED(fontFamily->GetFamilyNames(familyNames.addressof())); 129 return GetLocalizedStringFromFont(familyNames); 130 } 131 132 Utility::OpenTypeFontVersion FontCatalog::GetFontFaceVersion(const wil::com_ptr<IDWriteFont>& font) 133 { 134 wil::com_ptr<IDWriteLocalizedStrings> fontVersion; 135 BOOL exists; 136 THROW_IF_FAILED(font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS, fontVersion.addressof(), &exists)); 137 if (!exists) 138 { 139 return {}; 140 } 141 142 std::string value = AppInstaller::Utility::ConvertToUTF8(GetLocalizedStringFromFont(fontVersion)); 143 Utility::OpenTypeFontVersion openTypeFontVersion{ value }; 144 return openTypeFontVersion; 145 } 146 147 FontFamily FontCatalog::GetFontFamilyByIndex(const wil::com_ptr<IDWriteFontCollection>& collection, UINT32 index) 148 { 149 wil::com_ptr<IDWriteFontFamily> family; 150 THROW_IF_FAILED(collection->GetFontFamily(index, family.addressof())); 151 std::wstring familyName = GetFontFamilyName(family); 152 153 std::vector<FontFace> fontFaces; 154 UINT32 fontCount = family->GetFontCount(); 155 for (UINT32 fontIndex = 0; fontIndex < fontCount; fontIndex++) 156 { 157 wil::com_ptr<IDWriteFont> font; 158 THROW_IF_FAILED(family->GetFont(fontIndex, font.addressof())); 159 160 wil::com_ptr<IDWriteFontFace> fontFace; 161 THROW_IF_FAILED(font->CreateFontFace(fontFace.addressof())); 162 163 FontFace fontFaceEntry; 164 fontFaceEntry.Name = GetFontFaceName(font); 165 fontFaceEntry.Version = GetFontFaceVersion(font); 166 fontFaceEntry.FilePaths = GetFontFilePaths(fontFace); 167 fontFaces.emplace_back(std::move(fontFaceEntry)); 168 } 169 170 FontFamily fontFamily; 171 fontFamily.Name = std::move(familyName); 172 fontFamily.Faces = std::move(fontFaces); 173 return fontFamily; 174 } 175 }