Skip to content

Commit

Permalink
Avoid loading nearby fonts unless necessary
Browse files Browse the repository at this point in the history
  • Loading branch information
lhecker committed Apr 28, 2023
1 parent 0d6642a commit 615dccd
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 91 deletions.
6 changes: 5 additions & 1 deletion src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
std::vector<Editor::Font> monospaceFontList;

// get the font collection; subscribe to updates
const auto fontCollection = ::Microsoft::Console::Render::FontCache::GetFresh();
wil::com_ptr<IDWriteFactory> factory;
THROW_IF_FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(factory), reinterpret_cast<::IUnknown**>(factory.addressof())));

wil::com_ptr<IDWriteFontCollection> fontCollection;
THROW_IF_FAILED(factory->GetSystemFontCollection(fontCollection.addressof(), TRUE));

for (UINT32 i = 0; i < fontCollection->GetFontFamilyCount(); ++i)
{
Expand Down
9 changes: 5 additions & 4 deletions src/inc/til/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ namespace til
class shared_mutex_guard
{
public:
shared_mutex_guard(T& data, std::shared_mutex& mutex) :
#pragma warning(suppress : 26447) // The function is declared 'noexcept' but calls function 'shared_mutex>()' which may throw exceptions (f.6).)
shared_mutex_guard(T& data, std::shared_mutex& mutex) noexcept :
_data{ data },
_lock{ mutex }
{
Expand All @@ -21,17 +22,17 @@ namespace til
shared_mutex_guard(shared_mutex_guard&&) = default;
shared_mutex_guard& operator=(shared_mutex_guard&&) = default;

[[nodiscard]] constexpr T* operator->() const
[[nodiscard]] constexpr T* operator->() const noexcept
{
return &_data;
}

[[nodiscard]] constexpr T& operator*() const&
[[nodiscard]] constexpr T& operator*() const& noexcept
{
return _data;
}

[[nodiscard]] constexpr T&& operator*() const&&
[[nodiscard]] constexpr T&& operator*() const&& noexcept
{
return std::move(_data);
}
Expand Down
13 changes: 12 additions & 1 deletion src/renderer/atlas/AtlasEngine.api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -596,11 +596,22 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
requestedWeight = DWRITE_FONT_WEIGHT_NORMAL;
}

auto fontCollection = FontCache::GetCached();
wil::com_ptr<IDWriteFontCollection> fontCollection;
THROW_IF_FAILED(_p.dwriteFactory->GetSystemFontCollection(fontCollection.addressof(), FALSE));

u32 index = 0;
BOOL exists = false;
THROW_IF_FAILED(fontCollection->FindFamilyName(requestedFaceName, &index, &exists));

if constexpr (Feature_NearbyFontLoading::IsEnabled())
{
if (!exists)
{
fontCollection = FontCache::GetCached();
THROW_IF_FAILED(fontCollection->FindFamilyName(requestedFaceName, &index, &exists));
}
}

THROW_HR_IF(DWRITE_E_NOFONT, !exists);

wil::com_ptr<IDWriteFontFamily> fontFamily;
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/atlas/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <array>
#include <filesystem>
#include <optional>
#include <shared_mutex>
#include <span>
#include <sstream>
#include <string_view>
Expand All @@ -20,8 +21,8 @@
#include <d2d1_3.h>
#include <d3d11_2.h>
#include <d3dcompiler.h>
#include <dwrite_3.h>
#include <dcomp.h>
#include <dwrite_3.h>
#include <dxgi1_3.h>
#include <dxgidebug.h>
#include <VersionHelpers.h>
Expand Down
60 changes: 27 additions & 33 deletions src/renderer/base/FontCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,30 @@

#pragma once

#include <til/mutex.h>

namespace Microsoft::Console::Render::FontCache
{
namespace details
{
inline const std::vector<wil::com_ptr<IDWriteFontFile>>& getNearbyFontFiles(IDWriteFactory5* factory5)
inline wil::com_ptr<IDWriteFontCollection> getFontCollection()
{
static const auto fontFiles = [=]() {
std::vector<wil::com_ptr<IDWriteFontFile>> files;
wil::com_ptr<IDWriteFactory> factory;
THROW_IF_FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(factory), reinterpret_cast<::IUnknown**>(factory.addressof())));

wil::com_ptr<IDWriteFontCollection> systemFontCollection;
THROW_IF_FAILED(factory->GetSystemFontCollection(systemFontCollection.addressof(), FALSE));

if constexpr (Feature_NearbyFontLoading::IsEnabled())
{
// IDWriteFactory5 is supported since Windows 10, build 15021.
const auto factory5 = factory.try_query<IDWriteFactory5>();
if (!factory5)
{
return systemFontCollection;
}

std::vector<wil::com_ptr<IDWriteFontFile>> nearbyFontFiles;

const std::filesystem::path module{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
const auto folder{ module.parent_path() };
Expand All @@ -22,35 +38,11 @@ namespace Microsoft::Console::Render::FontCache
wil::com_ptr<IDWriteFontFile> fontFile;
if (SUCCEEDED_LOG(factory5->CreateFontFileReference(p.path().c_str(), nullptr, fontFile.addressof())))
{
files.emplace_back(std::move(fontFile));
nearbyFontFiles.emplace_back(std::move(fontFile));
}
}
}

files.shrink_to_fit();
return files;
}();
return fontFiles;
}

inline wil::com_ptr<IDWriteFontCollection> getFontCollection(bool forceUpdate)
{
wil::com_ptr<IDWriteFactory> factory;
THROW_IF_FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(factory), reinterpret_cast<::IUnknown**>(factory.addressof())));

wil::com_ptr<IDWriteFontCollection> systemFontCollection;
THROW_IF_FAILED(factory->GetSystemFontCollection(systemFontCollection.addressof(), forceUpdate));

if constexpr (Feature_NearbyFontLoading::IsEnabled())
{
// IDWriteFactory5 is supported since Windows 10, build 15021.
const auto factory5 = factory.try_query<IDWriteFactory5>();
if (!factory5)
{
return systemFontCollection;
}

const auto& nearbyFontFiles = getNearbyFontFiles(factory5.get());
if (nearbyFontFiles.empty())
{
return systemFontCollection;
Expand Down Expand Up @@ -89,11 +81,13 @@ namespace Microsoft::Console::Render::FontCache

inline wil::com_ptr<IDWriteFontCollection> GetCached()
{
return details::getFontCollection(false);
}
static til::shared_mutex<wil::com_ptr<IDWriteFontCollection>> cachedCollection;

inline wil::com_ptr<IDWriteFontCollection> GetFresh()
{
return details::getFontCollection(true);
const auto guard = cachedCollection.lock();
if (!*guard)
{
*guard = details::getFontCollection();
}
return *guard;
}
}
57 changes: 33 additions & 24 deletions src/renderer/dx/DxFontInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,31 @@
#include <unicode.hpp>
#include <VersionHelpers.h>

#include "../base/FontCache.h"

static constexpr std::wstring_view FALLBACK_FONT_FACES[] = { L"Consolas", L"Lucida Console", L"Courier New" };

using namespace Microsoft::Console::Render;

DxFontInfo::DxFontInfo() noexcept :
_weight(DWRITE_FONT_WEIGHT_NORMAL),
_style(DWRITE_FONT_STYLE_NORMAL),
_stretch(DWRITE_FONT_STRETCH_NORMAL),
_didFallback(false)
DxFontInfo::DxFontInfo(IDWriteFactory1* dwriteFactory) :
DxFontInfo{ dwriteFactory, {}, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL }
{
}

DxFontInfo::DxFontInfo(std::wstring_view familyName,
unsigned int weight,
DWRITE_FONT_STYLE style,
DWRITE_FONT_STRETCH stretch) :
DxFontInfo(familyName, static_cast<DWRITE_FONT_WEIGHT>(weight), style, stretch)
{
}

DxFontInfo::DxFontInfo(std::wstring_view familyName,
DWRITE_FONT_WEIGHT weight,
DWRITE_FONT_STYLE style,
DWRITE_FONT_STRETCH stretch) :
DxFontInfo::DxFontInfo(
IDWriteFactory1* dwriteFactory,
std::wstring_view familyName,
DWRITE_FONT_WEIGHT weight,
DWRITE_FONT_STYLE style,
DWRITE_FONT_STRETCH stretch) :
_familyName(familyName),
_weight(weight),
_style(style),
_stretch(stretch),
_didFallback(false)
{
__assume(dwriteFactory != nullptr);
THROW_IF_FAILED(dwriteFactory->GetSystemFontCollection(_fontCollection.addressof(), FALSE));
}

bool DxFontInfo::operator==(const DxFontInfo& other) const noexcept
Expand Down Expand Up @@ -93,6 +88,11 @@ bool DxFontInfo::GetFallback() const noexcept
return _didFallback;
}

IDWriteFontCollection* DxFontInfo::GetFontCollection() const noexcept
{
return _fontCollection.get();
}

void DxFontInfo::SetFromEngine(const std::wstring_view familyName,
const DWRITE_FONT_WEIGHT weight,
const DWRITE_FONT_STYLE style,
Expand All @@ -114,7 +114,7 @@ void DxFontInfo::SetFromEngine(const std::wstring_view familyName,
// - localeName - Locale to search for appropriate fonts
// Return Value:
// - Smart pointer holding interface reference for queryable font data.
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFace1> DxFontInfo::ResolveFontFaceWithFallback(IDWriteFontCollection* fontCollection, std::wstring& localeName)
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFace1> DxFontInfo::ResolveFontFaceWithFallback(std::wstring& localeName)
{
// First attempt to find exactly what the user asked for.
_didFallback = false;
Expand All @@ -125,7 +125,16 @@ void DxFontInfo::SetFromEngine(const std::wstring_view familyName,
// method. We still want to fall back to a font that's reasonable, below.
try
{
face = _FindFontFace(fontCollection, localeName);
face = _FindFontFace(localeName);

if constexpr (Feature_NearbyFontLoading::IsEnabled())
{
if (!face)
{
_fontCollection = FontCache::GetCached();
face = _FindFontFace(localeName);
}
}

if (!face)
{
Expand All @@ -152,7 +161,7 @@ void DxFontInfo::SetFromEngine(const std::wstring_view familyName,
_familyName = _familyName.substr(0, lastSpace);

// Try to find it with the shortened family name
face = _FindFontFace(fontCollection, localeName);
face = _FindFontFace(localeName);
}
}
}
Expand All @@ -167,7 +176,7 @@ void DxFontInfo::SetFromEngine(const std::wstring_view familyName,
{
_familyName = fallbackFace;

face = _FindFontFace(fontCollection, localeName);
face = _FindFontFace(localeName);
if (face)
{
_didFallback = true;
Expand All @@ -189,19 +198,19 @@ void DxFontInfo::SetFromEngine(const std::wstring_view familyName,
// Return Value:
// - Smart pointer holding interface reference for queryable font data.
#pragma warning(suppress : 26429) // C26429: Symbol 'fontCollection' is never tested for nullness, it can be marked as not_null (f.23).
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFace1> DxFontInfo::_FindFontFace(IDWriteFontCollection* fontCollection, std::wstring& localeName)
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFace1> DxFontInfo::_FindFontFace(std::wstring& localeName)
{
Microsoft::WRL::ComPtr<IDWriteFontFace1> fontFace;

UINT32 familyIndex;
BOOL familyExists;

THROW_IF_FAILED(fontCollection->FindFamilyName(_familyName.data(), &familyIndex, &familyExists));
THROW_IF_FAILED(_fontCollection->FindFamilyName(_familyName.data(), &familyIndex, &familyExists));

if (familyExists)
{
Microsoft::WRL::ComPtr<IDWriteFontFamily> fontFamily;
THROW_IF_FAILED(fontCollection->GetFontFamily(familyIndex, &fontFamily));
THROW_IF_FAILED(_fontCollection->GetFontFamily(familyIndex, &fontFamily));

Microsoft::WRL::ComPtr<IDWriteFont> font;
THROW_IF_FAILED(fontFamily->GetFirstMatchingFont(GetWeight(), GetStretch(), GetStyle(), &font));
Expand Down
24 changes: 12 additions & 12 deletions src/renderer/dx/DxFontInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,14 @@ namespace Microsoft::Console::Render
class DxFontInfo
{
public:
DxFontInfo() noexcept;
DxFontInfo(IDWriteFactory1* dwriteFactory);

DxFontInfo(std::wstring_view familyName,
unsigned int weight,
DWRITE_FONT_STYLE style,
DWRITE_FONT_STRETCH stretch);

DxFontInfo(std::wstring_view familyName,
DWRITE_FONT_WEIGHT weight,
DWRITE_FONT_STYLE style,
DWRITE_FONT_STRETCH stretch);
DxFontInfo(
IDWriteFactory1* dwriteFactory,
std::wstring_view familyName,
DWRITE_FONT_WEIGHT weight,
DWRITE_FONT_STYLE style,
DWRITE_FONT_STRETCH stretch);

bool operator==(const DxFontInfo& other) const noexcept;

Expand All @@ -40,16 +37,17 @@ namespace Microsoft::Console::Render
void SetStretch(const DWRITE_FONT_STRETCH stretch) noexcept;

bool GetFallback() const noexcept;
IDWriteFontCollection* GetFontCollection() const noexcept;

void SetFromEngine(const std::wstring_view familyName,
const DWRITE_FONT_WEIGHT weight,
const DWRITE_FONT_STYLE style,
const DWRITE_FONT_STRETCH stretch);

[[nodiscard]] ::Microsoft::WRL::ComPtr<IDWriteFontFace1> ResolveFontFaceWithFallback(IDWriteFontCollection* fontCollection, std::wstring& localeName);
[[nodiscard]] ::Microsoft::WRL::ComPtr<IDWriteFontFace1> ResolveFontFaceWithFallback(std::wstring& localeName);

private:
[[nodiscard]] ::Microsoft::WRL::ComPtr<IDWriteFontFace1> _FindFontFace(IDWriteFontCollection* fontCollection, std::wstring& localeName);
[[nodiscard]] ::Microsoft::WRL::ComPtr<IDWriteFontFace1> _FindFontFace(std::wstring& localeName);

[[nodiscard]] std::wstring _GetFontFamilyName(const gsl::not_null<IDWriteFontFamily*> fontFamily,
std::wstring& localeName);
Expand All @@ -66,6 +64,8 @@ namespace Microsoft::Console::Render
// The stretch of the font is the spacing between each letter
DWRITE_FONT_STRETCH _stretch;

wil::com_ptr<IDWriteFontCollection> _fontCollection;

// Indicates whether we couldn't match the user request and had to choose from a hard-coded default list.
bool _didFallback;
};
Expand Down
Loading

0 comments on commit 615dccd

Please sign in to comment.