Allow users to set font features and font axes (#10525)
Adds support for users to be able to set font features and axes (see the spec for more details!)
## Detailed Description
**CustomTextLayout**
- Asks the `DxFontRenderData` for the font features when getting glyphs
- _If any features have been set/updated, we always skip the "isTextSimple" shortcut_
- Asks the `_formatInUse` for any font axes when mapping characters in `_AnalyzeFontFallback`
**DxFontRenderData**
- Stores a map of font features (initialized to the [standard feature list])
- Stores a map of font axes
- Has methods to add font features/axes to the map or update existing ones
- Has methods to retrieve the font features/axes
- Sets the font axes in the `IDWriteTextFormat` when creating it
## Validation Steps Performed
It works!
[standard feature list]: ac5aef67d1/DrawableObject.ixx (L802)
Specified in #10457
Related to #1790
Closes #759
Closes #5828
This commit is contained in:
parent
335f69e099
commit
4c16cb278e
8
.github/actions/spelling/allow/allow.txt
vendored
8
.github/actions/spelling/allow/allow.txt
vendored
|
@ -1,6 +1,9 @@
|
|||
apc
|
||||
calt
|
||||
ccmp
|
||||
Apc
|
||||
clickable
|
||||
clig
|
||||
copyable
|
||||
dalet
|
||||
dcs
|
||||
|
@ -14,6 +17,7 @@ dzhe
|
|||
Enum'd
|
||||
formattings
|
||||
ftp
|
||||
fvar
|
||||
geeksforgeeks
|
||||
ghe
|
||||
gje
|
||||
|
@ -27,7 +31,9 @@ It'd
|
|||
kje
|
||||
liga
|
||||
lje
|
||||
locl
|
||||
maxed
|
||||
mkmk
|
||||
mru
|
||||
nje
|
||||
ogonek
|
||||
|
@ -37,10 +43,12 @@ postmodern
|
|||
ptys
|
||||
qof
|
||||
qps
|
||||
rclt
|
||||
reimplementation
|
||||
reserialization
|
||||
reserialize
|
||||
reserializes
|
||||
rlig
|
||||
runtimes
|
||||
shcha
|
||||
slnt
|
||||
|
|
|
@ -155,6 +155,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// Set up the DX Engine
|
||||
auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
|
||||
_renderer->AddRenderEngine(dxEngine.get());
|
||||
_renderEngine = std::move(dxEngine);
|
||||
|
||||
// Initialize our font with the renderer
|
||||
// We don't have to care about DPI. We'll get a change message immediately if it's not 96
|
||||
|
@ -168,12 +169,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// Then, using the font, get the number of characters that can fit.
|
||||
// Resize our terminal connection to match that size, and initialize the terminal with that size.
|
||||
const auto viewInPixels = Viewport::FromDimensions({ 0, 0 }, windowSize);
|
||||
LOG_IF_FAILED(dxEngine->SetWindowSize({ viewInPixels.Width(), viewInPixels.Height() }));
|
||||
LOG_IF_FAILED(_renderEngine->SetWindowSize({ viewInPixels.Width(), viewInPixels.Height() }));
|
||||
|
||||
// Update DxEngine's SelectionBackground
|
||||
dxEngine->SetSelectionBackground(til::color{ _settings.SelectionBackground() });
|
||||
_renderEngine->SetSelectionBackground(til::color{ _settings.SelectionBackground() });
|
||||
|
||||
const auto vp = dxEngine->GetViewportInCharacters(viewInPixels);
|
||||
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
|
||||
const auto width = vp.Width();
|
||||
const auto height = vp.Height();
|
||||
_connection.Resize(height, width);
|
||||
|
@ -188,27 +189,26 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// after Enable, then it'll be possible to paint the frame once
|
||||
// _before_ the warning handler is set up, and then warnings from
|
||||
// the first paint will be ignored!
|
||||
dxEngine->SetWarningCallback(std::bind(&ControlCore::_rendererWarning, this, std::placeholders::_1));
|
||||
_renderEngine->SetWarningCallback(std::bind(&ControlCore::_rendererWarning, this, std::placeholders::_1));
|
||||
|
||||
// Tell the DX Engine to notify us when the swap chain changes.
|
||||
// We do this after we initially set the swapchain so as to avoid unnecessary callbacks (and locking problems)
|
||||
dxEngine->SetCallback(std::bind(&ControlCore::_renderEngineSwapChainChanged, this));
|
||||
_renderEngine->SetCallback(std::bind(&ControlCore::_renderEngineSwapChainChanged, this));
|
||||
|
||||
dxEngine->SetRetroTerminalEffect(_settings.RetroTerminalEffect());
|
||||
dxEngine->SetPixelShaderPath(_settings.PixelShaderPath());
|
||||
dxEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
|
||||
dxEngine->SetSoftwareRendering(_settings.SoftwareRendering());
|
||||
_renderEngine->SetRetroTerminalEffect(_settings.RetroTerminalEffect());
|
||||
_renderEngine->SetPixelShaderPath(_settings.PixelShaderPath());
|
||||
_renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
|
||||
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
|
||||
|
||||
_updateAntiAliasingMode(dxEngine.get());
|
||||
_updateAntiAliasingMode(_renderEngine.get());
|
||||
|
||||
// GH#5098: Inform the engine of the opacity of the default text background.
|
||||
if (_settings.UseAcrylic())
|
||||
{
|
||||
dxEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast<float>(_settings.TintOpacity()));
|
||||
_renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast<float>(_settings.TintOpacity()));
|
||||
}
|
||||
|
||||
THROW_IF_FAILED(dxEngine->Enable());
|
||||
_renderEngine = std::move(dxEngine);
|
||||
THROW_IF_FAILED(_renderEngine->Enable());
|
||||
|
||||
_initializedTerminal = true;
|
||||
} // scope for TerminalLock
|
||||
|
@ -603,9 +603,34 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
_terminal->SetFontInfo(_actualFont);
|
||||
|
||||
// TODO: MSFT:20895307 If the font doesn't exist, this doesn't
|
||||
// actually fail. We need a way to gracefully fallback.
|
||||
_renderer->TriggerFontChange(newDpi, _desiredFont, _actualFont);
|
||||
if (_renderEngine)
|
||||
{
|
||||
std::unordered_map<std::wstring_view, uint32_t> featureMap;
|
||||
if (const auto fontFeatures = _settings.FontFeatures())
|
||||
{
|
||||
featureMap.reserve(fontFeatures.Size());
|
||||
|
||||
for (const auto& [tag, param] : fontFeatures)
|
||||
{
|
||||
featureMap.emplace(tag, param);
|
||||
}
|
||||
}
|
||||
std::unordered_map<std::wstring_view, float> axesMap;
|
||||
if (const auto fontAxes = _settings.FontAxes())
|
||||
{
|
||||
axesMap.reserve(fontAxes.Size());
|
||||
|
||||
for (const auto& [axis, value] : fontAxes)
|
||||
{
|
||||
axesMap.emplace(axis, value);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: MSFT:20895307 If the font doesn't exist, this doesn't
|
||||
// actually fail. We need a way to gracefully fallback.
|
||||
LOG_IF_FAILED(_renderEngine->UpdateDpi(newDpi));
|
||||
LOG_IF_FAILED(_renderEngine->UpdateFont(_desiredFont, _actualFont, featureMap, axesMap));
|
||||
}
|
||||
|
||||
// If the actual font isn't what was requested...
|
||||
if (_actualFont.GetFaceName() != _desiredFont.GetFaceName())
|
||||
|
|
|
@ -36,6 +36,8 @@ namespace Microsoft.Terminal.Control
|
|||
Int32 FontSize;
|
||||
Windows.UI.Text.FontWeight FontWeight;
|
||||
String Padding;
|
||||
Windows.Foundation.Collections.IMap<String, UInt32> FontFeatures;
|
||||
Windows.Foundation.Collections.IMap<String, Single> FontAxes;
|
||||
|
||||
Microsoft.Terminal.Control.IKeyBindings KeyBindings;
|
||||
|
||||
|
|
|
@ -335,6 +335,8 @@ winrt::Microsoft::Terminal::Settings::Model::Profile CascadiaSettings::Duplicate
|
|||
DUPLICATE_SETTING_MACRO_SUB(font, target, FontFace);
|
||||
DUPLICATE_SETTING_MACRO_SUB(font, target, FontSize);
|
||||
DUPLICATE_SETTING_MACRO_SUB(font, target, FontWeight);
|
||||
DUPLICATE_SETTING_MACRO_SUB(font, target, FontFeatures);
|
||||
DUPLICATE_SETTING_MACRO_SUB(font, target, FontAxes);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -14,6 +14,8 @@ static constexpr std::string_view FontInfoKey{ "font" };
|
|||
static constexpr std::string_view FontFaceKey{ "face" };
|
||||
static constexpr std::string_view FontSizeKey{ "size" };
|
||||
static constexpr std::string_view FontWeightKey{ "weight" };
|
||||
static constexpr std::string_view FontFeaturesKey{ "features" };
|
||||
static constexpr std::string_view FontAxesKey{ "axes" };
|
||||
static constexpr std::string_view LegacyFontFaceKey{ "fontFace" };
|
||||
static constexpr std::string_view LegacyFontSizeKey{ "fontSize" };
|
||||
static constexpr std::string_view LegacyFontWeightKey{ "fontWeight" };
|
||||
|
@ -29,6 +31,8 @@ winrt::com_ptr<FontConfig> FontConfig::CopyFontInfo(const winrt::com_ptr<FontCon
|
|||
fontInfo->_FontFace = source->_FontFace;
|
||||
fontInfo->_FontSize = source->_FontSize;
|
||||
fontInfo->_FontWeight = source->_FontWeight;
|
||||
fontInfo->_FontAxes = source->_FontAxes;
|
||||
fontInfo->_FontFeatures = source->_FontFeatures;
|
||||
return fontInfo;
|
||||
}
|
||||
|
||||
|
@ -39,6 +43,8 @@ Json::Value FontConfig::ToJson() const
|
|||
JsonUtils::SetValueForKey(json, FontFaceKey, _FontFace);
|
||||
JsonUtils::SetValueForKey(json, FontSizeKey, _FontSize);
|
||||
JsonUtils::SetValueForKey(json, FontWeightKey, _FontWeight);
|
||||
JsonUtils::SetValueForKey(json, FontAxesKey, _FontAxes);
|
||||
JsonUtils::SetValueForKey(json, FontFeaturesKey, _FontFeatures);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
@ -65,6 +71,8 @@ void FontConfig::LayerJson(const Json::Value& json)
|
|||
JsonUtils::GetValueForKey(fontInfoJson, FontFaceKey, _FontFace);
|
||||
JsonUtils::GetValueForKey(fontInfoJson, FontSizeKey, _FontSize);
|
||||
JsonUtils::GetValueForKey(fontInfoJson, FontWeightKey, _FontWeight);
|
||||
JsonUtils::GetValueForKey(fontInfoJson, FontFeaturesKey, _FontFeatures);
|
||||
JsonUtils::GetValueForKey(fontInfoJson, FontAxesKey, _FontAxes);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -23,6 +23,9 @@ Author(s):
|
|||
#include "IInheritable.h"
|
||||
#include <DefaultSettings.h>
|
||||
|
||||
using IFontAxesMap = winrt::Windows::Foundation::Collections::IMap<winrt::hstring, float>;
|
||||
using IFontFeatureMap = winrt::Windows::Foundation::Collections::IMap<winrt::hstring, uint32_t>;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{
|
||||
struct FontConfig : FontConfigT<FontConfig>, IInheritable<FontConfig>
|
||||
|
@ -39,6 +42,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
INHERITABLE_SETTING(Model::FontConfig, hstring, FontFace, DEFAULT_FONT_FACE);
|
||||
INHERITABLE_SETTING(Model::FontConfig, int32_t, FontSize, DEFAULT_FONT_SIZE);
|
||||
INHERITABLE_SETTING(Model::FontConfig, Windows::UI::Text::FontWeight, FontWeight, DEFAULT_FONT_WEIGHT);
|
||||
INHERITABLE_SETTING(Model::FontConfig, IFontAxesMap, FontAxes);
|
||||
INHERITABLE_SETTING(Model::FontConfig, IFontFeatureMap, FontFeatures);
|
||||
|
||||
private:
|
||||
winrt::weak_ref<Profile> _sourceProfile;
|
||||
|
|
|
@ -8,6 +8,8 @@ import "Profile.idl";
|
|||
_BASE_INHERITABLE_SETTING(Type, Name); \
|
||||
Microsoft.Terminal.Settings.Model.FontConfig Name##OverrideSource { get; }
|
||||
|
||||
#define COMMA ,
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Model
|
||||
{
|
||||
[default_interface] runtimeclass FontConfig {
|
||||
|
@ -16,5 +18,8 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
INHERITABLE_FONT_SETTING(String, FontFace);
|
||||
INHERITABLE_FONT_SETTING(Int32, FontSize);
|
||||
INHERITABLE_FONT_SETTING(Windows.UI.Text.FontWeight, FontWeight);
|
||||
|
||||
INHERITABLE_FONT_SETTING(Windows.Foundation.Collections.IMap<String COMMA UInt32>, FontFeatures);
|
||||
INHERITABLE_FONT_SETTING(Windows.Foundation.Collections.IMap<String COMMA Single>, FontAxes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -177,6 +177,58 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ConversionTrait<std::unordered_map<std::string, T>>
|
||||
{
|
||||
std::unordered_map<std::string, T> FromJson(const Json::Value& json) const
|
||||
{
|
||||
std::unordered_map<std::string, T> val;
|
||||
val.reserve(json.size());
|
||||
|
||||
ConversionTrait<T> trait;
|
||||
for (auto it = json.begin(), end = json.end(); it != end; ++it)
|
||||
{
|
||||
GetValue(*it, val[it.name()], trait);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
bool CanConvert(const Json::Value& json) const
|
||||
{
|
||||
if (!json.isObject())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ConversionTrait<T> trait;
|
||||
for (const auto& v : json)
|
||||
{
|
||||
if (!trait.CanConvert(v))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Json::Value ToJson(const std::unordered_map<std::string, T>& val)
|
||||
{
|
||||
Json::Value json{ Json::objectValue };
|
||||
|
||||
for (const auto& [k, v] : val)
|
||||
{
|
||||
SetValueForKey(json, k, v);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
std::string TypeDescription() const
|
||||
{
|
||||
return fmt::format("map (string, {})", ConversionTrait<T>{}.TypeDescription());
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef WINRT_BASE_H
|
||||
template<>
|
||||
struct ConversionTrait<winrt::hstring> : public ConversionTrait<std::wstring>
|
||||
|
@ -206,6 +258,58 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
|
|||
return ConversionTrait<std::wstring>::CanConvert(json) || json.isNull();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ConversionTrait<winrt::Windows::Foundation::Collections::IMap<winrt::hstring, T>>
|
||||
{
|
||||
winrt::Windows::Foundation::Collections::IMap<winrt::hstring, T> FromJson(const Json::Value& json) const
|
||||
{
|
||||
std::unordered_map<winrt::hstring, T> val;
|
||||
val.reserve(json.size());
|
||||
|
||||
ConversionTrait<T> trait;
|
||||
for (auto it = json.begin(), end = json.end(); it != end; ++it)
|
||||
{
|
||||
GetValue(*it, val[winrt::to_hstring(it.name())], trait);
|
||||
}
|
||||
|
||||
return winrt::single_threaded_map<winrt::hstring, T>(std::move(val));
|
||||
}
|
||||
|
||||
bool CanConvert(const Json::Value& json) const
|
||||
{
|
||||
if (!json.isObject())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ConversionTrait<T> trait;
|
||||
for (const auto& v : json)
|
||||
{
|
||||
if (!trait.CanConvert(v))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Json::Value ToJson(const winrt::Windows::Foundation::Collections::IMap<winrt::hstring, T>& val)
|
||||
{
|
||||
Json::Value json{ Json::objectValue };
|
||||
|
||||
for (const auto& [k, v] : val)
|
||||
{
|
||||
SetValueForKey(json, til::u16u8(k), v);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
std::string TypeDescription() const
|
||||
{
|
||||
return fmt::format("map (string, {})", ConversionTrait<T>{}.TypeDescription());
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
|
|
|
@ -279,6 +279,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
_FontFace = profile.FontInfo().FontFace();
|
||||
_FontSize = profile.FontInfo().FontSize();
|
||||
_FontWeight = profile.FontInfo().FontWeight();
|
||||
_FontFeatures = profile.FontInfo().FontFeatures();
|
||||
_FontAxes = profile.FontInfo().FontAxes();
|
||||
_Padding = profile.Padding();
|
||||
|
||||
_Commandline = profile.Commandline();
|
||||
|
|
|
@ -21,6 +21,9 @@ Author(s):
|
|||
#include <DefaultSettings.h>
|
||||
#include <conattrs.hpp>
|
||||
|
||||
using IFontAxesMap = winrt::Windows::Foundation::Collections::IMap<winrt::hstring, float>;
|
||||
using IFontFeatureMap = winrt::Windows::Foundation::Collections::IMap<winrt::hstring, uint32_t>;
|
||||
|
||||
// fwdecl unittest classes
|
||||
namespace SettingsModelLocalTests
|
||||
{
|
||||
|
@ -123,6 +126,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
INHERITABLE_SETTING(Model::TerminalSettings, int32_t, FontSize, DEFAULT_FONT_SIZE);
|
||||
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, winrt::Windows::UI::Text::FontWeight, FontWeight);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, IFontAxesMap, FontAxes);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, IFontFeatureMap, FontFeatures);
|
||||
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, hstring, BackgroundImage);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, double, BackgroundImageOpacity, 1.0);
|
||||
|
|
|
@ -8,6 +8,9 @@ Licensed under the MIT license.
|
|||
#include <DefaultSettings.h>
|
||||
#include <conattrs.hpp>
|
||||
|
||||
using IFontFeatureMap = winrt::Windows::Foundation::Collections::IMap<winrt::hstring, uint32_t>;
|
||||
using IFontAxesMap = winrt::Windows::Foundation::Collections::IMap<winrt::hstring, float>;
|
||||
|
||||
namespace ControlUnitTests
|
||||
{
|
||||
class MockControlSettings : public winrt::implements<MockControlSettings, winrt::Microsoft::Terminal::Core::ICoreSettings, winrt::Microsoft::Terminal::Control::IControlSettings, winrt::Microsoft::Terminal::Core::ICoreAppearance, winrt::Microsoft::Terminal::Control::IControlAppearance>
|
||||
|
@ -80,6 +83,9 @@ namespace ControlUnitTests
|
|||
|
||||
WINRT_PROPERTY(winrt::hstring, PixelShaderPath);
|
||||
|
||||
WINRT_PROPERTY(IFontFeatureMap, FontFeatures);
|
||||
WINRT_PROPERTY(IFontAxesMap, FontAxes);
|
||||
|
||||
private:
|
||||
std::array<winrt::Microsoft::Terminal::Core::Color, COLOR_TABLE_SIZE> _ColorTable;
|
||||
|
||||
|
|
|
@ -357,7 +357,7 @@ CATCH_RETURN()
|
|||
_glyphIndices.resize(totalGlyphsArrayCount);
|
||||
}
|
||||
|
||||
if (_isEntireTextSimple)
|
||||
if (_isEntireTextSimple && !_fontRenderData->DidUserSetFeatures())
|
||||
{
|
||||
// When the entire text is simple, we can skip GetGlyphs and directly retrieve glyph indices and
|
||||
// advances(in font design unit). With the help of font metrics, we can calculate the actual glyph
|
||||
|
@ -396,10 +396,18 @@ CATCH_RETURN()
|
|||
std::vector<DWRITE_SHAPING_TEXT_PROPERTIES> textProps(textLength);
|
||||
std::vector<DWRITE_SHAPING_GLYPH_PROPERTIES> glyphProps(maxGlyphCount);
|
||||
|
||||
// Get the features to apply to the font
|
||||
auto features = _fontRenderData->DefaultFontFeatures();
|
||||
DWRITE_FONT_FEATURE* featureList = features.data();
|
||||
DWRITE_TYPOGRAPHIC_FEATURES typographicFeatures = { &featureList[0], gsl::narrow<uint32_t>(features.size()) };
|
||||
DWRITE_TYPOGRAPHIC_FEATURES const* typographicFeaturesPointer = &typographicFeatures;
|
||||
const uint32_t fontFeatureLengths[] = { textLength };
|
||||
|
||||
// Get the glyphs from the text, retrying if needed.
|
||||
|
||||
int tries = 0;
|
||||
|
||||
#pragma warning(suppress : 26485) // so we can pass in the fontFeatureLengths to GetGlyphs without the analyzer complaining
|
||||
HRESULT hr = S_OK;
|
||||
do
|
||||
{
|
||||
|
@ -412,9 +420,9 @@ CATCH_RETURN()
|
|||
&run.script,
|
||||
_localeName.data(),
|
||||
(run.isNumberSubstituted) ? _numberSubstitution.Get() : nullptr,
|
||||
nullptr, // features
|
||||
nullptr, // featureLengths
|
||||
0, // featureCount
|
||||
&typographicFeaturesPointer, // features
|
||||
&fontFeatureLengths[0], // featureLengths
|
||||
1, // featureCount
|
||||
maxGlyphCount, // maxGlyphCount
|
||||
&_glyphClusters.at(textStart),
|
||||
&textProps.at(0),
|
||||
|
@ -462,9 +470,9 @@ CATCH_RETURN()
|
|||
(run.bidiLevel & 1), // isRightToLeft
|
||||
&run.script,
|
||||
_localeName.data(),
|
||||
nullptr, // features
|
||||
nullptr, // featureRangeLengths
|
||||
0, // featureRanges
|
||||
&typographicFeaturesPointer, // features
|
||||
&fontFeatureLengths[0], // featureLengths
|
||||
1, // featureCount
|
||||
&_glyphAdvances.at(glyphStart),
|
||||
&_glyphOffsets.at(glyphStart));
|
||||
|
||||
|
@ -1264,29 +1272,71 @@ CATCH_RETURN();
|
|||
fallback = _fontRenderData->SystemFontFallback();
|
||||
}
|
||||
|
||||
// Walk through and analyze the entire string
|
||||
while (textLength > 0)
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontFallback1> fallback1;
|
||||
::Microsoft::WRL::ComPtr<IDWriteTextFormat3> format3;
|
||||
|
||||
// If the OS supports IDWriteFontFallback1 and IDWriteTextFormat3, we can use the
|
||||
// newer MapCharacters to apply axes of variation to the font
|
||||
if (!FAILED(_formatInUse->QueryInterface(IID_PPV_ARGS(&format3))) && !FAILED(fallback->QueryInterface(IID_PPV_ARGS(&fallback1))))
|
||||
{
|
||||
UINT32 mappedLength = 0;
|
||||
::Microsoft::WRL::ComPtr<IDWriteFont> mappedFont;
|
||||
FLOAT scale = 0.0f;
|
||||
const auto axesVector = _fontRenderData->GetAxisVector(weight, stretch, style, format3.Get());
|
||||
// Walk through and analyze the entire string
|
||||
while (textLength > 0)
|
||||
{
|
||||
UINT32 mappedLength = 0;
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontFace5> mappedFont;
|
||||
FLOAT scale = 0.0f;
|
||||
|
||||
fallback->MapCharacters(source,
|
||||
textPosition,
|
||||
textLength,
|
||||
collection.Get(),
|
||||
familyName.data(),
|
||||
weight,
|
||||
style,
|
||||
stretch,
|
||||
&mappedLength,
|
||||
&mappedFont,
|
||||
&scale);
|
||||
fallback1->MapCharacters(source,
|
||||
textPosition,
|
||||
textLength,
|
||||
collection.Get(),
|
||||
familyName.data(),
|
||||
axesVector.data(),
|
||||
gsl::narrow<uint32_t>(axesVector.size()),
|
||||
&mappedLength,
|
||||
&scale,
|
||||
&mappedFont);
|
||||
|
||||
RETURN_IF_FAILED(_SetMappedFont(textPosition, mappedLength, mappedFont.Get(), scale));
|
||||
RETURN_IF_FAILED(_SetMappedFontFace(textPosition, mappedLength, mappedFont, scale));
|
||||
|
||||
textPosition += mappedLength;
|
||||
textLength -= mappedLength;
|
||||
textPosition += mappedLength;
|
||||
textLength -= mappedLength;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The chunk of code below is very similar to the one above, unfortunately this needs
|
||||
// to stay for Win7 compatibility reasons. It is also not possible to combine the two
|
||||
// because they call different versions of MapCharacters
|
||||
|
||||
// Walk through and analyze the entire string
|
||||
while (textLength > 0)
|
||||
{
|
||||
UINT32 mappedLength = 0;
|
||||
::Microsoft::WRL::ComPtr<IDWriteFont> mappedFont;
|
||||
FLOAT scale = 0.0f;
|
||||
|
||||
fallback->MapCharacters(source,
|
||||
textPosition,
|
||||
textLength,
|
||||
collection.Get(),
|
||||
familyName.data(),
|
||||
weight,
|
||||
style,
|
||||
stretch,
|
||||
&mappedLength,
|
||||
&mappedFont,
|
||||
&scale);
|
||||
|
||||
RETURN_LAST_ERROR_IF(!mappedFont);
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontFace> face;
|
||||
RETURN_IF_FAILED(mappedFont->CreateFontFace(&face));
|
||||
RETURN_IF_FAILED(_SetMappedFontFace(textPosition, mappedLength, face, scale));
|
||||
|
||||
textPosition += mappedLength;
|
||||
textLength -= mappedLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
@ -1300,14 +1350,14 @@ CATCH_RETURN();
|
|||
// Arguments:
|
||||
// - textPosition - the index to start the substring operation
|
||||
// - textLength - the length of the substring operation
|
||||
// - font - the font that applies to the substring range
|
||||
// - fontFace - the fontFace that applies to the substring range
|
||||
// - scale - the scale of the font to apply
|
||||
// Return Value:
|
||||
// - S_OK or appropriate STL/GSL failure code.
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE CustomTextLayout::_SetMappedFont(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
_In_ IDWriteFont* const font,
|
||||
FLOAT const scale)
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE CustomTextLayout::_SetMappedFontFace(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
const ::Microsoft::WRL::ComPtr<IDWriteFontFace>& fontFace,
|
||||
FLOAT const scale)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -1317,14 +1367,9 @@ CATCH_RETURN();
|
|||
{
|
||||
auto& run = _FetchNextRun(textLength);
|
||||
|
||||
if (font != nullptr)
|
||||
if (fontFace != nullptr)
|
||||
{
|
||||
// Get font face from font metadata
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontFace> face;
|
||||
RETURN_IF_FAILED(font->CreateFontFace(&face));
|
||||
|
||||
// QI for Face5 interface from base face interface, store into run
|
||||
RETURN_IF_FAILED(face.As(&run.fontFace));
|
||||
RETURN_IF_FAILED(fontFace.As(&run.fontFace));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -126,7 +126,7 @@ namespace Microsoft::Console::Render
|
|||
void _OrderRuns();
|
||||
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE _AnalyzeFontFallback(IDWriteTextAnalysisSource* const source, UINT32 textPosition, UINT32 textLength);
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE _SetMappedFont(UINT32 textPosition, UINT32 textLength, IDWriteFont* const font, FLOAT const scale);
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE _SetMappedFontFace(UINT32 textPosition, UINT32 textLength, const ::Microsoft::WRL::ComPtr<IDWriteFontFace>& fontFace, FLOAT const scale);
|
||||
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE _AnalyzeBoxDrawing(gsl::not_null<IDWriteTextAnalysisSource*> const source, UINT32 textPosition, UINT32 textLength);
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE _SetBoxEffect(UINT32 textPosition, UINT32 textLength);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
static constexpr float POINTS_PER_INCH = 72.0f;
|
||||
static constexpr std::wstring_view FALLBACK_FONT_FACES[] = { L"Consolas", L"Lucida Console", L"Courier New" };
|
||||
static constexpr std::wstring_view FALLBACK_LOCALE = L"en-us";
|
||||
static constexpr size_t TAG_LENGTH = 4;
|
||||
|
||||
using namespace Microsoft::Console::Render;
|
||||
|
||||
|
@ -93,6 +94,11 @@ DxFontRenderData::DxFontRenderData(::Microsoft::WRL::ComPtr<IDWriteFactory1> dwr
|
|||
return _defaultFontInfo.GetStretch();
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<DWRITE_FONT_FEATURE>& DxFontRenderData::DefaultFontFeatures() const noexcept
|
||||
{
|
||||
return _featureVector;
|
||||
}
|
||||
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteTextFormat> DxFontRenderData::DefaultTextFormat()
|
||||
{
|
||||
return TextFormatWithAttribute(_defaultFontInfo.GetWeight(), _defaultFontInfo.GetStyle(), _defaultFontInfo.GetStretch());
|
||||
|
@ -178,7 +184,7 @@ DxFontRenderData::DxFontRenderData(::Microsoft::WRL::ComPtr<IDWriteFactory1> dwr
|
|||
// - dpi - The DPI of the screen
|
||||
// Return Value:
|
||||
// - S_OK or relevant DirectX error
|
||||
[[nodiscard]] HRESULT DxFontRenderData::UpdateFont(const FontInfoDesired& desired, FontInfo& actual, const int dpi) noexcept
|
||||
[[nodiscard]] HRESULT DxFontRenderData::UpdateFont(const FontInfoDesired& desired, FontInfo& actual, const int dpi, const std::unordered_map<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -193,6 +199,9 @@ DxFontRenderData::DxFontRenderData(::Microsoft::WRL::ComPtr<IDWriteFactory1> dwr
|
|||
DWRITE_FONT_STYLE_NORMAL,
|
||||
DWRITE_FONT_STRETCH_NORMAL);
|
||||
|
||||
_SetFeatures(features);
|
||||
_SetAxes(axes);
|
||||
|
||||
_BuildFontRenderData(desired, actual, dpi);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
@ -441,6 +450,195 @@ try
|
|||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
// Routine Description:
|
||||
// - Returns whether the user set or updated any of the font features to be applied
|
||||
bool DxFontRenderData::DidUserSetFeatures() const noexcept
|
||||
{
|
||||
return _didUserSetFeatures;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Updates our internal map of font features with the given features
|
||||
// - NOTE TO CALLER: Make sure to call _BuildFontRenderData after calling this for the feature changes
|
||||
// to take place
|
||||
// Arguments:
|
||||
// - features - the features to update our map with
|
||||
void DxFontRenderData::_SetFeatures(const std::unordered_map<std::wstring_view, uint32_t>& features)
|
||||
{
|
||||
// Populate the feature map with the standard list first
|
||||
std::unordered_map<DWRITE_FONT_FEATURE_TAG, uint32_t> featureMap{
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('r', 'l', 'i', 'g'), 1 }, // Required Ligatures
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('r', 'c', 'l', 't'), 1 }, // Required Contextual Alternates
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('l', 'o', 'c', 'l'), 1 }, // Localized Forms
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('c', 'c', 'm', 'p'), 1 }, // Glyph Composition / Decomposition
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('c', 'a', 'l', 't'), 1 }, // Contextual Alternates
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('l', 'i', 'g', 'a'), 1 }, // Standard Ligatures
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('c', 'l', 'i', 'g'), 1 }, // Contextual Ligatures
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('k', 'e', 'r', 'n'), 1 }, // Kerning
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('m', 'a', 'r', 'k'), 1 }, // Mark Positioning
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('m', 'k', 'm', 'k'), 1 }, // Mark to Mark Positioning
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('d', 'i', 's', 't'), 1 } // Distances
|
||||
};
|
||||
|
||||
// Update our feature map with the provided features
|
||||
if (!features.empty())
|
||||
{
|
||||
for (const auto [tag, param] : features)
|
||||
{
|
||||
if (tag.length() == TAG_LENGTH)
|
||||
{
|
||||
featureMap.insert_or_assign(DWRITE_MAKE_FONT_FEATURE_TAG(til::at(tag, 0), til::at(tag, 1), til::at(tag, 2), til::at(tag, 3)), param);
|
||||
}
|
||||
}
|
||||
_didUserSetFeatures = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_didUserSetFeatures = false;
|
||||
}
|
||||
|
||||
// Convert the data to DWRITE_FONT_FEATURE and store it in a vector for CustomTextLayout
|
||||
_featureVector.clear();
|
||||
for (const auto [tag, param] : featureMap)
|
||||
{
|
||||
_featureVector.push_back(DWRITE_FONT_FEATURE{ tag, param });
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Updates our internal map of font axes with the given axes
|
||||
// - NOTE TO CALLER: Make sure to call _BuildFontRenderData after calling this for the axes changes
|
||||
// to take place
|
||||
// Arguments:
|
||||
// - axes - the axes to update our map with
|
||||
void DxFontRenderData::_SetAxes(const std::unordered_map<std::wstring_view, float>& axes)
|
||||
{
|
||||
_axesVector.clear();
|
||||
|
||||
// Update our axis map with the provided axes
|
||||
#pragma warning(suppress : 26445) // the analyzer doesn't like reference to string_view
|
||||
for (const auto& [axis, value] : axes)
|
||||
{
|
||||
if (axis.length() == TAG_LENGTH)
|
||||
{
|
||||
const auto dwriteTag = DWRITE_MAKE_FONT_AXIS_TAG(til::at(axis, 0), til::at(axis, 1), til::at(axis, 2), til::at(axis, 3));
|
||||
_axesVector.emplace_back(DWRITE_FONT_AXIS_VALUE{ dwriteTag, value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Converts a DWRITE_FONT_STRETCH enum into the corresponding float value to
|
||||
// create a DWRITE_FONT_AXIS_VALUE with
|
||||
// Arguments:
|
||||
// - fontStretch: the old DWRITE_FONT_STRETCH enum to be converted into an axis value
|
||||
// Return value:
|
||||
// - The float value corresponding to the passed in fontStretch
|
||||
float DxFontRenderData::_FontStretchToWidthAxisValue(DWRITE_FONT_STRETCH fontStretch) noexcept
|
||||
{
|
||||
// 10 elements from DWRITE_FONT_STRETCH_UNDEFINED (0) to DWRITE_FONT_STRETCH_ULTRA_EXPANDED (9)
|
||||
static constexpr auto fontStretchEnumToVal = std::array{ 100.0f, 50.0f, 62.5f, 75.0f, 87.5f, 100.0f, 112.5f, 125.0f, 150.0f, 200.0f };
|
||||
|
||||
if (gsl::narrow_cast<size_t>(fontStretch) > fontStretchEnumToVal.size())
|
||||
{
|
||||
fontStretch = DWRITE_FONT_STRETCH_NORMAL;
|
||||
}
|
||||
|
||||
return til::at(fontStretchEnumToVal, fontStretch);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Converts a DWRITE_FONT_STYLE enum into the corresponding float value to
|
||||
// create a DWRITE_FONT_AXIS_VALUE with
|
||||
// Arguments:
|
||||
// - fontStyle: the old DWRITE_FONT_STYLE enum to be converted into an axis value
|
||||
// Return value:
|
||||
// - The float value corresponding to the passed in fontStyle
|
||||
float DxFontRenderData::_FontStyleToSlantFixedAxisValue(DWRITE_FONT_STYLE fontStyle) noexcept
|
||||
{
|
||||
// DWRITE_FONT_STYLE_NORMAL (0), DWRITE_FONT_STYLE_OBLIQUE (1), DWRITE_FONT_STYLE_ITALIC (2)
|
||||
static constexpr auto fontStyleEnumToVal = std::array{ 0.0f, -20.0f, -12.0f };
|
||||
|
||||
// Both DWRITE_FONT_STYLE_OBLIQUE and DWRITE_FONT_STYLE_ITALIC default to having slant.
|
||||
// Though an italic font technically need not have slant (there exist upright ones), the
|
||||
// vast majority of italic fonts are also slanted. Ideally the slant comes from the
|
||||
// 'slnt' value in the STAT or fvar table, or the post table italic angle.
|
||||
|
||||
if (gsl::narrow_cast<size_t>(fontStyle) > fontStyleEnumToVal.size())
|
||||
{
|
||||
fontStyle = DWRITE_FONT_STYLE_NORMAL;
|
||||
}
|
||||
|
||||
return til::at(fontStyleEnumToVal, fontStyle);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Fill any missing axis values that might be known but were unspecified, such as omitting
|
||||
// the 'wght' axis tag but specifying the old DWRITE_FONT_WEIGHT enum
|
||||
// - This function will only be called with a valid IDWriteTextFormat3
|
||||
// (on platforms where IDWriteTextFormat3 is supported)
|
||||
// Arguments:
|
||||
// - fontWeight: the old DWRITE_FONT_WEIGHT enum to be converted into an axis value
|
||||
// - fontStretch: the old DWRITE_FONT_STRETCH enum to be converted into an axis value
|
||||
// - fontStyle: the old DWRITE_FONT_STYLE enum to be converted into an axis value
|
||||
// - fontSize: the number to convert into an axis value
|
||||
// - format: the IDWriteTextFormat3 to get the defined axes from
|
||||
// Return value:
|
||||
// - The fully formed axes vector
|
||||
#pragma warning(suppress : 26429) // the analyzer doesn't detect that our FAIL_FAST_IF_NULL macro \
|
||||
// checks format for nullness
|
||||
std::vector<DWRITE_FONT_AXIS_VALUE> DxFontRenderData::GetAxisVector(const DWRITE_FONT_WEIGHT fontWeight,
|
||||
const DWRITE_FONT_STRETCH fontStretch,
|
||||
const DWRITE_FONT_STYLE fontStyle,
|
||||
IDWriteTextFormat3* format)
|
||||
{
|
||||
FAIL_FAST_IF_NULL(format);
|
||||
|
||||
const auto axesCount = format->GetFontAxisValueCount();
|
||||
std::vector<DWRITE_FONT_AXIS_VALUE> axesVector;
|
||||
axesVector.resize(axesCount);
|
||||
format->GetFontAxisValues(axesVector.data(), axesCount);
|
||||
|
||||
auto axisTagPresence = AxisTagPresence::None;
|
||||
for (const auto& fontAxisValue : axesVector)
|
||||
{
|
||||
switch (fontAxisValue.axisTag)
|
||||
{
|
||||
case DWRITE_FONT_AXIS_TAG_WEIGHT:
|
||||
WI_SetFlag(axisTagPresence, AxisTagPresence::Weight);
|
||||
break;
|
||||
case DWRITE_FONT_AXIS_TAG_WIDTH:
|
||||
WI_SetFlag(axisTagPresence, AxisTagPresence::Width);
|
||||
break;
|
||||
case DWRITE_FONT_AXIS_TAG_ITALIC:
|
||||
WI_SetFlag(axisTagPresence, AxisTagPresence::Italic);
|
||||
break;
|
||||
case DWRITE_FONT_AXIS_TAG_SLANT:
|
||||
WI_SetFlag(axisTagPresence, AxisTagPresence::Slant);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (WI_IsFlagClear(axisTagPresence, AxisTagPresence::Weight))
|
||||
{
|
||||
axesVector.emplace_back(DWRITE_FONT_AXIS_VALUE{ DWRITE_FONT_AXIS_TAG_WEIGHT, gsl::narrow<float>(fontWeight) });
|
||||
}
|
||||
if (WI_IsFlagClear(axisTagPresence, AxisTagPresence::Width))
|
||||
{
|
||||
axesVector.emplace_back(DWRITE_FONT_AXIS_VALUE{ DWRITE_FONT_AXIS_TAG_WIDTH, _FontStretchToWidthAxisValue(fontStretch) });
|
||||
}
|
||||
if (WI_IsFlagClear(axisTagPresence, AxisTagPresence::Italic))
|
||||
{
|
||||
axesVector.emplace_back(DWRITE_FONT_AXIS_VALUE{ DWRITE_FONT_AXIS_TAG_ITALIC, (fontStyle == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f) });
|
||||
}
|
||||
if (WI_IsFlagClear(axisTagPresence, AxisTagPresence::Slant))
|
||||
{
|
||||
axesVector.emplace_back(DWRITE_FONT_AXIS_VALUE{ DWRITE_FONT_AXIS_TAG_SLANT, _FontStyleToSlantFixedAxisValue(fontStyle) });
|
||||
}
|
||||
|
||||
return axesVector;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Build the needed data for rendering according to the font used
|
||||
// Arguments:
|
||||
|
@ -649,5 +847,14 @@ Microsoft::WRL::ComPtr<IDWriteTextFormat> DxFontRenderData::_BuildTextFormat(con
|
|||
_fontSize,
|
||||
localeName.data(),
|
||||
&format));
|
||||
|
||||
// If the OS supports IDWriteTextFormat3, set the font axes
|
||||
::Microsoft::WRL::ComPtr<IDWriteTextFormat3> format3;
|
||||
if (!_axesVector.empty() && !FAILED(format->QueryInterface(IID_PPV_ARGS(&format3))))
|
||||
{
|
||||
DWRITE_FONT_AXIS_VALUE const* axesList = _axesVector.data();
|
||||
format3->SetFontAxisValues(axesList, gsl::narrow<uint32_t>(_axesVector.size()));
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,16 @@
|
|||
|
||||
namespace Microsoft::Console::Render
|
||||
{
|
||||
enum class AxisTagPresence : BYTE
|
||||
{
|
||||
None = 0x00,
|
||||
Weight = 0x01,
|
||||
Width = 0x02,
|
||||
Italic = 0x04,
|
||||
Slant = 0x08,
|
||||
};
|
||||
DEFINE_ENUM_FLAG_OPERATORS(AxisTagPresence);
|
||||
|
||||
class DxFontRenderData
|
||||
{
|
||||
public:
|
||||
|
@ -51,6 +61,9 @@ namespace Microsoft::Console::Render
|
|||
// The stretch of default font
|
||||
[[nodiscard]] DWRITE_FONT_STRETCH DefaultFontStretch() noexcept;
|
||||
|
||||
// The font features of the default font
|
||||
[[nodiscard]] const std::vector<DWRITE_FONT_FEATURE>& DefaultFontFeatures() const noexcept;
|
||||
|
||||
// The DirectWrite format object representing the size and other text properties to be applied (by default)
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteTextFormat> DefaultTextFormat();
|
||||
|
||||
|
@ -70,19 +83,37 @@ namespace Microsoft::Console::Render
|
|||
DWRITE_FONT_STYLE style,
|
||||
DWRITE_FONT_STRETCH stretch);
|
||||
|
||||
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& desired, FontInfo& fiFontInfo, const int dpi) noexcept;
|
||||
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& desired, FontInfo& fiFontInfo, const int dpi, const std::unordered_map<std::wstring_view, uint32_t>& features = {}, const std::unordered_map<std::wstring_view, float>& axes = {}) noexcept;
|
||||
|
||||
[[nodiscard]] static HRESULT STDMETHODCALLTYPE s_CalculateBoxEffect(IDWriteTextFormat* format, size_t widthPixels, IDWriteFontFace1* face, float fontScale, IBoxDrawingEffect** effect) noexcept;
|
||||
|
||||
bool DidUserSetFeatures() const noexcept;
|
||||
|
||||
std::vector<DWRITE_FONT_AXIS_VALUE> GetAxisVector(const DWRITE_FONT_WEIGHT fontWeight,
|
||||
const DWRITE_FONT_STRETCH fontStretch,
|
||||
const DWRITE_FONT_STYLE fontStyle,
|
||||
IDWriteTextFormat3* format);
|
||||
|
||||
private:
|
||||
using FontAttributeMapKey = uint32_t;
|
||||
|
||||
bool _didUserSetFeatures{ false };
|
||||
// The font features to apply to the text
|
||||
std::vector<DWRITE_FONT_FEATURE> _featureVector;
|
||||
|
||||
// The font axes to apply to the text
|
||||
std::vector<DWRITE_FONT_AXIS_VALUE> _axesVector;
|
||||
|
||||
// We use this to identify font variants with different attributes.
|
||||
static FontAttributeMapKey _ToMapKey(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch) noexcept
|
||||
{
|
||||
return (weight << 16) | (style << 8) | stretch;
|
||||
};
|
||||
|
||||
void _SetFeatures(const std::unordered_map<std::wstring_view, uint32_t>& features);
|
||||
void _SetAxes(const std::unordered_map<std::wstring_view, float>& axes);
|
||||
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);
|
||||
|
||||
|
|
|
@ -1978,15 +1978,30 @@ CATCH_RETURN()
|
|||
|
||||
// Routine Description:
|
||||
// - Updates the font used for drawing
|
||||
// - This is the version that complies with the IRenderEngine interface
|
||||
// Arguments:
|
||||
// - pfiFontInfoDesired - Information specifying the font that is requested
|
||||
// - fiFontInfo - Filled with the nearest font actually chosen for drawing
|
||||
// Return Value:
|
||||
// - S_OK or relevant DirectX error
|
||||
[[nodiscard]] HRESULT DxEngine::UpdateFont(const FontInfoDesired& pfiFontInfoDesired, FontInfo& fiFontInfo) noexcept
|
||||
{
|
||||
return UpdateFont(pfiFontInfoDesired, fiFontInfo, {}, {});
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Updates the font used for drawing
|
||||
// Arguments:
|
||||
// - pfiFontInfoDesired - Information specifying the font that is requested
|
||||
// - fiFontInfo - Filled with the nearest font actually chosen for drawing
|
||||
// - features - The map of font features to use
|
||||
// - axes - The map of font axes to use
|
||||
// Return Value:
|
||||
// - S_OK or relevant DirectX error
|
||||
[[nodiscard]] HRESULT DxEngine::UpdateFont(const FontInfoDesired& pfiFontInfoDesired, FontInfo& fiFontInfo, const std::unordered_map<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes) noexcept
|
||||
try
|
||||
{
|
||||
RETURN_IF_FAILED(_fontRenderData->UpdateFont(pfiFontInfoDesired, fiFontInfo, _dpi));
|
||||
RETURN_IF_FAILED(_fontRenderData->UpdateFont(pfiFontInfoDesired, fiFontInfo, _dpi, features, axes));
|
||||
|
||||
// Prepare the text layout.
|
||||
_customLayout = WRL::Make<CustomTextLayout>(_fontRenderData.get());
|
||||
|
|
|
@ -109,6 +109,7 @@ namespace Microsoft::Console::Render
|
|||
const gsl::not_null<IRenderData*> pData,
|
||||
const bool isSettingDefaultBrushes) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, const std::unordered_map<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes) noexcept;
|
||||
[[nodiscard]] HRESULT UpdateDpi(int const iDpi) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateViewport(const SMALL_RECT srNewViewport) noexcept override;
|
||||
|
||||
|
|
Loading…
Reference in a new issue