Use nearby fonts for font fallback (#11764)
This commit is a minimal fix in order to pass the `IDWriteFontCollection` we create out of .ttf files residing next to our binaries to the `IDWriteFontFallback::MapCharacters` call. The `IDWriteTextFormat` is used in order to carry the font collection over into `CustomTextLayout`. ## Validation * Put `JetBrainsMono-Regular.ttf` into the binary output directory * Modify `HKCU:\Console\*\FaceName` to `JetBrains Mono` * Launch OpenConsole.exe * OpenConsole uses JetBrains Mono ✔️ Closes #11032 Closes #11648
This commit is contained in:
parent
7bfaad4592
commit
131f5d2b32
|
@ -32,6 +32,7 @@ hyperlink
|
|||
hyperlinking
|
||||
hyperlinks
|
||||
img
|
||||
inlined
|
||||
It'd
|
||||
kje
|
||||
liga
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "pch.h"
|
||||
#include "Profiles.h"
|
||||
|
||||
#include "PreviewConnection.h"
|
||||
#include "Profiles.g.cpp"
|
||||
#include "EnumEntry.h"
|
||||
|
@ -10,6 +11,54 @@
|
|||
#include <LibraryResources.h>
|
||||
#include "..\WinRTUtils\inc\Utils.h"
|
||||
|
||||
// This function is a copy of DxFontInfo::_NearbyCollection() with
|
||||
// * the call to DxFontInfo::s_GetNearbyFonts() inlined
|
||||
// * checkForUpdates for GetSystemFontCollection() set to true
|
||||
static wil::com_ptr<IDWriteFontCollection1> NearbyCollection(IDWriteFactory* dwriteFactory)
|
||||
{
|
||||
// The convenience interfaces for loading fonts from files
|
||||
// are only available on Windows 10+.
|
||||
wil::com_ptr<IDWriteFactory6> factory6;
|
||||
// wil's query() facilities don't work inside WinRT land at the moment.
|
||||
// They produce a compilation error due to IUnknown and winrt::Windows::Foundation::IUnknown being ambiguous.
|
||||
if (!SUCCEEDED(dwriteFactory->QueryInterface(__uuidof(IDWriteFactory6), factory6.put_void())))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
wil::com_ptr<IDWriteFontCollection1> systemFontCollection;
|
||||
THROW_IF_FAILED(factory6->GetSystemFontCollection(false, systemFontCollection.addressof(), true));
|
||||
|
||||
wil::com_ptr<IDWriteFontSet> systemFontSet;
|
||||
THROW_IF_FAILED(systemFontCollection->GetFontSet(systemFontSet.addressof()));
|
||||
|
||||
wil::com_ptr<IDWriteFontSetBuilder2> fontSetBuilder2;
|
||||
THROW_IF_FAILED(factory6->CreateFontSetBuilder(fontSetBuilder2.addressof()));
|
||||
|
||||
THROW_IF_FAILED(fontSetBuilder2->AddFontSet(systemFontSet.get()));
|
||||
|
||||
{
|
||||
const std::filesystem::path module{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
|
||||
const auto folder{ module.parent_path() };
|
||||
|
||||
for (const auto& p : std::filesystem::directory_iterator(folder))
|
||||
{
|
||||
if (til::ends_with(p.path().native(), L".ttf"))
|
||||
{
|
||||
fontSetBuilder2->AddFontFile(p.path().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wil::com_ptr<IDWriteFontSet> fontSet;
|
||||
THROW_IF_FAILED(fontSetBuilder2->CreateFontSet(fontSet.addressof()));
|
||||
|
||||
wil::com_ptr<IDWriteFontCollection1> fontCollection;
|
||||
THROW_IF_FAILED(factory6->CreateFontCollectionFromFontSet(fontSet.get(), &fontCollection));
|
||||
|
||||
return fontCollection;
|
||||
}
|
||||
|
||||
using namespace winrt::Windows::UI::Text;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
|
@ -107,8 +156,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
reinterpret_cast<::IUnknown**>(factory.put())));
|
||||
|
||||
// get the font collection; subscribe to updates
|
||||
com_ptr<IDWriteFontCollection> fontCollection;
|
||||
THROW_IF_FAILED(factory->GetSystemFontCollection(fontCollection.put(), TRUE));
|
||||
const auto fontCollection = NearbyCollection(factory.get());
|
||||
|
||||
for (UINT32 i = 0; i < fontCollection->GetFontFamilyCount(); ++i)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// pch.h
|
||||
|
@ -51,8 +51,7 @@
|
|||
|
||||
#include <shlobj.h>
|
||||
#include <shobjidl_core.h>
|
||||
#include <dwrite.h>
|
||||
#include <dwrite_1.h>
|
||||
#include <dwrite_3.h>
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#include "til.h"
|
||||
|
|
|
@ -96,6 +96,11 @@ bool DxFontInfo::GetFallback() const noexcept
|
|||
return _didFallback;
|
||||
}
|
||||
|
||||
IDWriteFontCollection* DxFontInfo::GetNearbyCollection() const noexcept
|
||||
{
|
||||
return _nearbyCollection.Get();
|
||||
}
|
||||
|
||||
void DxFontInfo::SetFromEngine(const std::wstring_view familyName,
|
||||
const DWRITE_FONT_WEIGHT weight,
|
||||
const DWRITE_FONT_STYLE style,
|
||||
|
@ -223,13 +228,11 @@ void DxFontInfo::SetFromEngine(const std::wstring_view familyName,
|
|||
// If the system collection missed, try the files sitting next to our binary.
|
||||
if (withNearbyLookup && !familyExists)
|
||||
{
|
||||
auto&& nearbyCollection = _NearbyCollection(dwriteFactory);
|
||||
|
||||
// May be null on OS below Windows 10. If null, just skip the attempt.
|
||||
if (nearbyCollection)
|
||||
if (const auto nearbyCollection = _NearbyCollection(dwriteFactory))
|
||||
{
|
||||
nearbyCollection.As(&fontCollection);
|
||||
THROW_IF_FAILED(fontCollection->FindFamilyName(_familyName.data(), &familyIndex, &familyExists));
|
||||
THROW_IF_FAILED(nearbyCollection->FindFamilyName(_familyName.data(), &familyIndex, &familyExists));
|
||||
fontCollection = nearbyCollection;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,42 +335,48 @@ void DxFontInfo::SetFromEngine(const std::wstring_view familyName,
|
|||
// - dwriteFactory - The DWrite factory to use
|
||||
// Return Value:
|
||||
// - DirectWrite font collection. May be null if one cannot be created.
|
||||
[[nodiscard]] const Microsoft::WRL::ComPtr<IDWriteFontCollection1>& DxFontInfo::_NearbyCollection(gsl::not_null<IDWriteFactory1*> dwriteFactory) const
|
||||
[[nodiscard]] IDWriteFontCollection* DxFontInfo::_NearbyCollection(gsl::not_null<IDWriteFactory1*> dwriteFactory)
|
||||
{
|
||||
// Magic static so we only attempt to grovel the hard disk once no matter how many instances
|
||||
// of the font collection itself we require.
|
||||
static const auto knownPaths = s_GetNearbyFonts();
|
||||
if (_nearbyCollection)
|
||||
{
|
||||
return _nearbyCollection.Get();
|
||||
}
|
||||
|
||||
// The convenience interfaces for loading fonts from files
|
||||
// are only available on Windows 10+.
|
||||
// Don't try to look up if below that OS version.
|
||||
static const bool s_isWindows10OrGreater = IsWindows10OrGreater();
|
||||
|
||||
if (s_isWindows10OrGreater && !_nearbyCollection)
|
||||
::Microsoft::WRL::ComPtr<IDWriteFactory6> factory6;
|
||||
if (FAILED(dwriteFactory->QueryInterface<IDWriteFactory6>(&factory6)))
|
||||
{
|
||||
// Factory3 has a convenience to get us a font set builder.
|
||||
::Microsoft::WRL::ComPtr<IDWriteFactory3> factory3;
|
||||
THROW_IF_FAILED(dwriteFactory->QueryInterface<IDWriteFactory3>(&factory3));
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontSetBuilder> fontSetBuilder;
|
||||
THROW_IF_FAILED(factory3->CreateFontSetBuilder(&fontSetBuilder));
|
||||
|
||||
// Builder2 has a convenience to just feed in paths to font files.
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontSetBuilder2> fontSetBuilder2;
|
||||
THROW_IF_FAILED(fontSetBuilder.As(&fontSetBuilder2));
|
||||
|
||||
for (auto& p : knownPaths)
|
||||
{
|
||||
fontSetBuilder2->AddFontFile(p.c_str());
|
||||
}
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontSet> fontSet;
|
||||
THROW_IF_FAILED(fontSetBuilder2->CreateFontSet(&fontSet));
|
||||
|
||||
THROW_IF_FAILED(factory3->CreateFontCollectionFromFontSet(fontSet.Get(), &_nearbyCollection));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _nearbyCollection;
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontCollection1> systemFontCollection;
|
||||
THROW_IF_FAILED(factory6->GetSystemFontCollection(false, &systemFontCollection, 0));
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontSet> systemFontSet;
|
||||
THROW_IF_FAILED(systemFontCollection->GetFontSet(&systemFontSet));
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontSetBuilder2> fontSetBuilder2;
|
||||
THROW_IF_FAILED(factory6->CreateFontSetBuilder(&fontSetBuilder2));
|
||||
|
||||
THROW_IF_FAILED(fontSetBuilder2->AddFontSet(systemFontSet.Get()));
|
||||
|
||||
// Magic static so we only attempt to grovel the hard disk once no matter how many instances
|
||||
// of the font collection itself we require.
|
||||
static const auto knownPaths = s_GetNearbyFonts();
|
||||
for (auto& p : knownPaths)
|
||||
{
|
||||
fontSetBuilder2->AddFontFile(p.c_str());
|
||||
}
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontSet> fontSet;
|
||||
THROW_IF_FAILED(fontSetBuilder2->CreateFontSet(&fontSet));
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontCollection1> fontCollection;
|
||||
THROW_IF_FAILED(factory6->CreateFontCollectionFromFontSet(fontSet.Get(), &fontCollection));
|
||||
|
||||
_nearbyCollection = fontCollection;
|
||||
return _nearbyCollection.Get();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -386,18 +395,11 @@ void DxFontInfo::SetFromEngine(const std::wstring_view familyName,
|
|||
const std::filesystem::path module{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
|
||||
const auto folder{ module.parent_path() };
|
||||
|
||||
for (auto& p : std::filesystem::directory_iterator(folder))
|
||||
for (const auto& p : std::filesystem::directory_iterator(folder))
|
||||
{
|
||||
if (p.is_regular_file())
|
||||
if (til::ends_with(p.path().native(), L".ttf"))
|
||||
{
|
||||
auto extension = p.path().extension().wstring();
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), std::towlower);
|
||||
|
||||
static constexpr std::wstring_view ttfExtension{ L".ttf" };
|
||||
if (ttfExtension == extension)
|
||||
{
|
||||
paths.push_back(p);
|
||||
}
|
||||
paths.push_back(p.path());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@ namespace Microsoft::Console::Render
|
|||
|
||||
bool GetFallback() const noexcept;
|
||||
|
||||
IDWriteFontCollection* GetNearbyCollection() const noexcept;
|
||||
|
||||
void SetFromEngine(const std::wstring_view familyName,
|
||||
const DWRITE_FONT_WEIGHT weight,
|
||||
const DWRITE_FONT_STYLE style,
|
||||
|
@ -57,11 +59,11 @@ namespace Microsoft::Console::Render
|
|||
[[nodiscard]] std::wstring _GetFontFamilyName(gsl::not_null<IDWriteFontFamily*> const fontFamily,
|
||||
std::wstring& localeName);
|
||||
|
||||
[[nodiscard]] const Microsoft::WRL::ComPtr<IDWriteFontCollection1>& _NearbyCollection(gsl::not_null<IDWriteFactory1*> dwriteFactory) const;
|
||||
[[nodiscard]] IDWriteFontCollection* _NearbyCollection(gsl::not_null<IDWriteFactory1*> dwriteFactory);
|
||||
|
||||
[[nodiscard]] static std::vector<std::filesystem::path> s_GetNearbyFonts();
|
||||
|
||||
mutable ::Microsoft::WRL::ComPtr<IDWriteFontCollection1> _nearbyCollection;
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontCollection> _nearbyCollection;
|
||||
|
||||
// The font name we should be looking for
|
||||
std::wstring _familyName;
|
||||
|
|
|
@ -894,11 +894,11 @@ void DxFontRenderData::_BuildFontRenderData(const FontInfoDesired& desired, Font
|
|||
_glyphCell = actual.GetSize();
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> DxFontRenderData::_BuildTextFormat(const DxFontInfo fontInfo, const std::wstring_view localeName)
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> DxFontRenderData::_BuildTextFormat(const DxFontInfo& fontInfo, const std::wstring_view localeName)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> format;
|
||||
THROW_IF_FAILED(_dwriteFactory->CreateTextFormat(fontInfo.GetFamilyName().data(),
|
||||
nullptr,
|
||||
fontInfo.GetNearbyCollection(),
|
||||
fontInfo.GetWeight(),
|
||||
fontInfo.GetStyle(),
|
||||
fontInfo.GetStretch(),
|
||||
|
|
|
@ -122,7 +122,7 @@ namespace Microsoft::Console::Render
|
|||
float _FontStretchToWidthAxisValue(DWRITE_FONT_STRETCH fontStretch) noexcept;
|
||||
float _FontStyleToSlantFixedAxisValue(DWRITE_FONT_STYLE fontStyle) noexcept;
|
||||
void _BuildFontRenderData(const FontInfoDesired& desired, FontInfo& actual, const int dpi);
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> _BuildTextFormat(const DxFontInfo fontInfo, const std::wstring_view localeName);
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> _BuildTextFormat(const DxFontInfo& fontInfo, const std::wstring_view localeName);
|
||||
|
||||
std::unordered_map<FontAttributeMapKey, ::Microsoft::WRL::ComPtr<IDWriteTextFormat>> _textFormatMap;
|
||||
std::unordered_map<FontAttributeMapKey, ::Microsoft::WRL::ComPtr<IDWriteFontFace1>> _fontFaceMap;
|
||||
|
|
|
@ -18,21 +18,21 @@
|
|||
<ClCompile Include="..\BoxDrawingEffect.cpp" />
|
||||
<ClCompile Include="..\CustomTextLayout.cpp" />
|
||||
<ClCompile Include="..\CustomTextRenderer.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\DxFontInfo.cpp" />
|
||||
<ClCompile Include="..\DxFontRenderData.cpp" />
|
||||
<ClCompile Include="..\DxRenderer.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\BoxDrawingEffect.h" />
|
||||
<ClInclude Include="..\CustomTextLayout.h" />
|
||||
<ClInclude Include="..\CustomTextRenderer.h" />
|
||||
<ClInclude Include="..\precomp.h" />
|
||||
<ClInclude Include="..\DxRenderer.hpp" />
|
||||
<ClInclude Include="..\DxFontInfo.h" />
|
||||
<ClInclude Include="..\DxFontRenderData.h" />
|
||||
<ClInclude Include="..\DxRenderer.hpp" />
|
||||
<ClInclude Include="..\precomp.h" />
|
||||
<ClInclude Include="..\ScreenPixelShader.h" />
|
||||
<ClInclude Include="..\ScreenVertexShader.h" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -4,24 +4,26 @@
|
|||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\BoxDrawingEffect.cpp" />
|
||||
<ClCompile Include="..\CustomTextLayout.cpp" />
|
||||
<ClCompile Include="..\CustomTextRenderer.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp" />
|
||||
<ClCompile Include="..\DxFontInfo.cpp" />
|
||||
<ClCompile Include="..\DxFontRenderData.cpp" />
|
||||
<ClCompile Include="..\DxRenderer.cpp" />
|
||||
<ClCompile Include="..\BoxDrawingEffect.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\BoxDrawingEffect.h" />
|
||||
<ClInclude Include="..\CustomTextLayout.h" />
|
||||
<ClInclude Include="..\CustomTextRenderer.h" />
|
||||
<ClInclude Include="..\precomp.h" />
|
||||
<ClInclude Include="..\DxFontRenderData.h"/>
|
||||
<ClInclude Include="..\DxFontInfo.h" />
|
||||
<ClInclude Include="..\DxFontRenderData.h" />
|
||||
<ClInclude Include="..\DxRenderer.hpp" />
|
||||
<ClInclude Include="..\precomp.h" />
|
||||
<ClInclude Include="..\ScreenPixelShader.h" />
|
||||
<ClInclude Include="..\ScreenVertexShader.h" />
|
||||
<ClInclude Include="..\BoxDrawingEffect.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="..\IBoxDrawingEffect.idl" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
Loading…
Reference in New Issue