Add support for fractional font sizes (#14013)

After this commit a user may specify fractional font sizes.
Support was only implemented for AtlasEngine however.
DxEngine continues to use rounded (integer) font sizes.

Closes #6678

## Validation Steps Performed
* Install a bitmap font that requires fractional font sizes
  (e.g. Terminus TTF, https://files.ax86.net/terminus-ttf/)
* Set font size to something integer (e.g. 14pt)
  Glyphs are blurry 
* Set font size to something fractional (e.g. 13.5pt)
  Glyphs are crisp 
This commit is contained in:
Leonard Hecker
2022-09-17 00:37:56 +02:00
committed by GitHub
parent 6567201e0e
commit c51bb3a7a6
22 changed files with 65 additions and 56 deletions

View File

@@ -244,7 +244,7 @@
"default": 12,
"description": "Size of the font in points.",
"minimum": 1,
"type": "integer"
"type": "number"
},
"weight": {
"default": "normal",
@@ -2252,7 +2252,7 @@
"default": 12,
"description": "[deprecated] Define 'size' within the 'font' object instead.",
"minimum": 1,
"type": "integer",
"type": "number",
"deprecated": true
},
"fontWeight": {

View File

@@ -169,7 +169,7 @@ static bool RegisterTermClass(HINSTANCE hInstance) noexcept
}
HwndTerminal::HwndTerminal(HWND parentHwnd) :
_desiredFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, { 0, 14 }, CP_UTF8 },
_desiredFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, 14, CP_UTF8 },
_actualFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, { 0, 14 }, CP_UTF8, false },
_uiaProvider{ nullptr },
_currentDpi{ USER_DEFAULT_SCREEN_DPI },
@@ -799,7 +799,7 @@ void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR font
publicTerminal->_terminal->SetCursorStyle(static_cast<DispatchTypes::CursorStyle>(theme.CursorStyle));
publicTerminal->_desiredFont = { fontFamily, 0, DEFAULT_FONT_WEIGHT, { 0, fontSize }, CP_UTF8 };
publicTerminal->_desiredFont = { fontFamily, 0, DEFAULT_FONT_WEIGHT, static_cast<float>(fontSize), CP_UTF8 };
publicTerminal->_UpdateFont(newDpi);
// When the font changes the terminal dimensions need to be recalculated since the available row and column

View File

@@ -95,7 +95,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ITerminalConnection connection) :
_connection{ connection },
_desiredFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8 },
_desiredFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, DEFAULT_FONT_SIZE, CP_UTF8 },
_actualFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false }
{
_EnsureStaticInitialization();
@@ -859,15 +859,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - fontSize: The size of the font.
// Return Value:
// - Returns true if you need to call _refreshSizeUnderLock().
bool ControlCore::_setFontSizeUnderLock(int fontSize)
bool ControlCore::_setFontSizeUnderLock(float fontSize)
{
// Make sure we have a non-zero font size
const auto newSize = std::max(fontSize, 1);
const auto newSize = std::max(fontSize, 1.0f);
const auto fontFace = _settings->FontFace();
const auto fontWeight = _settings->FontWeight();
_actualFont = { fontFace, 0, fontWeight.Weight, { 0, newSize }, CP_UTF8, false };
_desiredFont = { fontFace, 0, fontWeight.Weight, newSize, CP_UTF8 };
_actualFont = { fontFace, 0, fontWeight.Weight, _desiredFont.GetEngineSize(), CP_UTF8, false };
_actualFontFaceName = { fontFace };
_desiredFont = { _actualFont };
const auto before = _actualFont.GetSize();
_updateFont();
@@ -893,11 +893,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - Adjust the font size of the terminal control.
// Arguments:
// - fontSizeDelta: The amount to increase or decrease the font size by.
void ControlCore::AdjustFontSize(int fontSizeDelta)
void ControlCore::AdjustFontSize(float fontSizeDelta)
{
const auto lock = _terminal->LockForWriting();
if (_setFontSizeUnderLock(_desiredFont.GetEngineSize().Y + fontSizeDelta))
if (_setFontSizeUnderLock(_desiredFont.GetFontSize() + fontSizeDelta))
{
_refreshSizeUnderLock();
}
@@ -1211,10 +1211,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return static_cast<uint16_t>(_actualFont.GetWeight());
}
til::size ControlCore::FontSizeInDips() const
winrt::Windows::Foundation::Size ControlCore::FontSizeInDips() const
{
const til::size fontSize{ _actualFont.GetSize() };
return fontSize.scale(til::math::rounding, 1.0f / ::base::saturated_cast<float>(_compositionScale));
const auto fontSize = _actualFont.GetSize();
const auto scale = 1.0f / static_cast<float>(_compositionScale);
return {
fontSize.width * scale,
fontSize.height * scale,
};
}
TerminalConnection::ConnectionState ControlCore::ConnectionState() const

View File

@@ -76,10 +76,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SizeChanged(const double width, const double height);
void ScaleChanged(const double scale);
void AdjustFontSize(int fontSizeDelta);
void AdjustFontSize(float fontSizeDelta);
void ResetFontSize();
FontInfo GetFont() const;
til::size FontSizeInDips() const;
winrt::Windows::Foundation::Size FontSizeInDips() const;
winrt::Windows::Foundation::Size FontSize() const noexcept;
winrt::hstring FontFaceName() const noexcept;
@@ -282,7 +282,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
std::unique_ptr<til::throttled_func_trailing<>> _updatePatternLocations;
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> _updateScrollBar;
bool _setFontSizeUnderLock(int fontSize);
bool _setFontSizeUnderLock(float fontSize);
void _updateFont(const bool initialUpdate = false);
void _refreshSizeUnderLock();
void _updateSelectionUI();

View File

@@ -105,7 +105,7 @@ namespace Microsoft.Terminal.Control
void ClearHoveredCell();
void ResetFontSize();
void AdjustFontSize(Int32 fontSizeDelta);
void AdjustFontSize(Single fontSizeDelta);
void SizeChanged(Double width, Double height);
void ScaleChanged(Double scale);

View File

@@ -301,7 +301,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto touchdownPoint = *_singleClickTouchdownPos;
const auto dx = pixelPosition.X - touchdownPoint.X;
const auto dy = pixelPosition.Y - touchdownPoint.Y;
const auto w = fontSizeInDips.width;
const auto w = fontSizeInDips.Width;
const auto distanceSquared = dx * dx + dy * dy;
const auto maxDistanceSquared = w * w / 16; // (w / 4)^2
@@ -337,16 +337,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto fontSizeInDips{ _core->FontSizeInDips() };
// Get the difference between the point we've dragged to and the start of the touch.
const auto dy = static_cast<double>(newTouchPoint.Y - anchor.Y);
const auto dy = static_cast<float>(newTouchPoint.Y - anchor.Y);
// Start viewport scroll after we've moved more than a half row of text
if (std::abs(dy) > (fontSizeInDips.height / 2.0))
if (std::abs(dy) > (fontSizeInDips.Height / 2.0f))
{
// Multiply by -1, because moving the touch point down will
// create a positive delta, but we want the viewport to move up,
// so we'll need a negative scroll amount (and the inverse for
// panning down)
const auto numRows = dy / -fontSizeInDips.height;
const auto numRows = dy / -fontSizeInDips.Height;
const auto currentOffset = _core->ScrollOffset();
const auto newValue = numRows + currentOffset;
@@ -459,7 +459,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// scrolling event.
// Arguments:
// - mouseDelta: the mouse wheel delta that triggered this event.
void ControlInteractivity::_mouseTransparencyHandler(const double mouseDelta)
void ControlInteractivity::_mouseTransparencyHandler(const int32_t mouseDelta) const
{
// Transparency is on a scale of [0.0,1.0], so only increment by .01.
const auto effectiveDelta = mouseDelta < 0 ? -.01 : .01;
@@ -471,9 +471,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// event.
// Arguments:
// - mouseDelta: the mouse wheel delta that triggered this event.
void ControlInteractivity::_mouseZoomHandler(const double mouseDelta)
void ControlInteractivity::_mouseZoomHandler(const int32_t mouseDelta) const
{
const auto fontDelta = mouseDelta < 0 ? -1 : 1;
const auto fontDelta = mouseDelta < 0 ? -1.0f : 1.0f;
_core->AdjustFontSize(fontDelta);
}
@@ -483,7 +483,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - mouseDelta: the mouse wheel delta that triggered this event.
// - pixelPosition: the location of the mouse during this event
// - isLeftButtonPressed: true iff the left mouse button was pressed during this event.
void ControlInteractivity::_mouseScrollHandler(const double mouseDelta,
void ControlInteractivity::_mouseScrollHandler(const int32_t mouseDelta,
const Core::Point pixelPosition,
const bool isLeftButtonPressed)
{

View File

@@ -132,9 +132,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
unsigned int _numberOfClicks(Core::Point clickPos, Timestamp clickTime);
void _updateSystemParameterSettings() noexcept;
void _mouseTransparencyHandler(const double mouseDelta);
void _mouseZoomHandler(const double mouseDelta);
void _mouseScrollHandler(const double mouseDelta,
void _mouseTransparencyHandler(const int32_t mouseDelta) const;
void _mouseZoomHandler(const int32_t mouseDelta) const;
void _mouseScrollHandler(const int32_t mouseDelta,
const Core::Point terminalPosition,
const bool isLeftButtonPressed);

View File

@@ -36,7 +36,7 @@ namespace Microsoft.Terminal.Control
Boolean UseAtlasEngine { get; };
String FontFace { get; };
Int32 FontSize { get; };
Single FontSize { get; };
Windows.UI.Text.FontWeight FontWeight { get; };
String Padding { get; };
Windows.Foundation.Collections.IMap<String, UInt32> FontFeatures { get; };

View File

@@ -1517,7 +1517,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - Adjust the font size of the terminal control.
// Arguments:
// - fontSizeDelta: The amount to increase or decrease the font size by.
void TermControl::AdjustFontSize(int fontSizeDelta)
void TermControl::AdjustFontSize(float fontSizeDelta)
{
_core.AdjustFontSize(fontSizeDelta);
}
@@ -2082,8 +2082,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// The family is only used to determine if the font is truetype or
// not, but DX doesn't use that info at all.
// The Codepage is additionally not actually used by the DX engine at all.
FontInfo actualFont = { fontFace, 0, fontWeight.Weight, { 0, fontSize }, CP_UTF8, false };
FontInfoDesired desiredFont = { actualFont };
FontInfoDesired desiredFont{ fontFace, 0, fontWeight.Weight, fontSize, CP_UTF8 };
FontInfo actualFont{ fontFace, 0, fontWeight.Weight, desiredFont.GetEngineSize(), CP_UTF8, false };
// Create a DX engine and initialize it with our font and DPI. We'll
// then use it to measure how much space the requested rows and columns

View File

@@ -82,7 +82,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ScrollViewport(int viewTop);
void AdjustFontSize(int fontSizeDelta);
void AdjustFontSize(float fontSizeDelta);
void ResetFontSize();
til::point GetFontSize() const;

View File

@@ -71,7 +71,7 @@ namespace Microsoft.Terminal.Control
void SearchMatch(Boolean goForward);
void AdjustFontSize(Int32 fontSizeDelta);
void AdjustFontSize(Single fontSizeDelta);
void ResetFontSize();
void ToggleShaderEffects();

View File

@@ -34,7 +34,7 @@ namespace Microsoft.Terminal.Settings.Editor
IHostedInWindow WindowRoot; // necessary to send the right HWND into the file picker dialogs.
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, FontFace);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Int32, FontSize);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Single, FontSize);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Text.FontWeight, FontWeight);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, ColorSchemeName);

View File

@@ -117,7 +117,7 @@ private:
////////////////////////////////////////////////////////////////////////////////
#define ADJUST_FONT_SIZE_ARGS(X) \
X(int32_t, Delta, "delta", false, 0)
X(float, Delta, "delta", false, 0)
////////////////////////////////////////////////////////////////////////////////
#define SEND_INPUT_ARGS(X) \

View File

@@ -187,7 +187,7 @@ namespace Microsoft.Terminal.Settings.Model
[default_interface] runtimeclass AdjustFontSizeArgs : IActionArgs
{
Int32 Delta { get; };
Single Delta { get; };
};
[default_interface] runtimeclass SendInputArgs : IActionArgs

View File

@@ -1110,8 +1110,9 @@ void CascadiaSettings::WriteSettingsToDisk()
// write current settings to current settings file
Json::StreamWriterBuilder wbuilder;
wbuilder.settings_["indentation"] = " ";
wbuilder.settings_["enableYAMLCompatibility"] = true; // suppress spaces around colons
wbuilder.settings_["indentation"] = " ";
wbuilder.settings_["precision"] = 6; // prevent values like 1.1000000000000001
FILETIME lastWriteTime{};
const auto styledString{ Json::writeString(wbuilder, ToJson()) };

View File

@@ -16,7 +16,7 @@ namespace Microsoft.Terminal.Settings.Model
Microsoft.Terminal.Settings.Model.Profile SourceProfile { get; };
INHERITABLE_FONT_SETTING(String, FontFace);
INHERITABLE_FONT_SETTING(Int32, FontSize);
INHERITABLE_FONT_SETTING(Single, FontSize);
INHERITABLE_FONT_SETTING(Windows.UI.Text.FontWeight, FontWeight);
INHERITABLE_FONT_SETTING(Windows.Foundation.Collections.IMap<String COMMA UInt32>, FontFeatures);

View File

@@ -96,7 +96,7 @@ Author(s):
#define MTSM_FONT_SETTINGS(X) \
X(hstring, FontFace, "face", DEFAULT_FONT_FACE) \
X(int32_t, FontSize, "size", DEFAULT_FONT_SIZE) \
X(float, FontSize, "size", DEFAULT_FONT_SIZE) \
X(winrt::Windows::UI::Text::FontWeight, FontWeight, "weight", DEFAULT_FONT_WEIGHT) \
X(IFontAxesMap, FontAxes, "axes") \
X(IFontFeatureMap, FontFeatures, "features")

View File

@@ -121,7 +121,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::TerminalSettings, double, Opacity, UseAcrylic() ? 0.5 : 1.0);
INHERITABLE_SETTING(Model::TerminalSettings, hstring, Padding, DEFAULT_PADDING);
INHERITABLE_SETTING(Model::TerminalSettings, hstring, FontFace, DEFAULT_FONT_FACE);
INHERITABLE_SETTING(Model::TerminalSettings, int32_t, FontSize, DEFAULT_FONT_SIZE);
INHERITABLE_SETTING(Model::TerminalSettings, float, FontSize, DEFAULT_FONT_SIZE);
INHERITABLE_SETTING(Model::TerminalSettings, winrt::Windows::UI::Text::FontWeight, FontWeight);
INHERITABLE_SETTING(Model::TerminalSettings, IFontAxesMap, FontAxes);

View File

@@ -57,7 +57,7 @@
X(bool, UseAcrylic, false) \
X(winrt::hstring, Padding, DEFAULT_PADDING) \
X(winrt::hstring, FontFace, L"Consolas") \
X(int32_t, FontSize, DEFAULT_FONT_SIZE) \
X(float, FontSize, DEFAULT_FONT_SIZE) \
X(winrt::Windows::UI::Text::FontWeight, FontWeight) \
X(IFontFeatureMap, FontFeatures) \
X(IFontAxesMap, FontAxes) \

View File

@@ -561,6 +561,7 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
{
const auto requestedFamily = fontInfoDesired.GetFamily();
auto requestedWeight = fontInfoDesired.GetWeight();
auto fontSize = fontInfoDesired.GetFontSize();
auto requestedSize = fontInfoDesired.GetEngineSize();
if (!requestedFaceName)
@@ -573,6 +574,7 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
}
if (!requestedSize.Y)
{
fontSize = 12.0f;
requestedSize = { 0, 12 };
}
if (!requestedWeight)
@@ -614,8 +616,8 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
// Point sizes are commonly treated at a 72 DPI scale
// (including by OpenType), whereas DirectWrite uses 96 DPI.
// Since we want the height in px we multiply by the display's DPI.
const auto fontSizeInDIP = requestedSize.Y / 72.0f * 96.0f;
const auto fontSizeInPx = requestedSize.Y / 72.0f * _api.dpi;
const auto fontSizeInDIP = fontSize / 72.0f * 96.0f;
const auto fontSizeInPx = fontSize / 72.0f * _api.dpi;
const auto designUnitsPerPx = fontSizeInPx / static_cast<float>(metrics.designUnitsPerEm);
const auto ascent = static_cast<float>(metrics.ascent) * designUnitsPerPx;
@@ -662,7 +664,7 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
// Our cells can't overlap each other so we additionally clamp the bottom line to be inside the cell boundaries.
doubleUnderlinePosBottom = std::min(doubleUnderlinePosBottom, lineHeight - thinLineWidth);
const auto cellWidth = gsl::narrow<u16>(std::roundf(advanceWidth));
const auto cellWidth = gsl::narrow<u16>(std::lroundf(advanceWidth));
const auto cellHeight = gsl::narrow<u16>(lineHeight);
{
@@ -675,8 +677,7 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
// The coordSizeUnscaled parameter to SetFromEngine is used for API functions like GetConsoleFontSize.
// Since clients expect that settings the font height to Y yields back a font height of Y,
// we're scaling the X relative/proportional to the actual cellWidth/cellHeight ratio.
// The code below uses a poor form of integer rounding.
requestedSize.X = (requestedSize.Y * cellWidth + cellHeight / 2) / cellHeight;
requestedSize.X = gsl::narrow_cast<til::CoordType>(std::lroundf(fontSize / cellHeight * cellWidth));
}
fontInfo.SetFromEngine(requestedFaceName, requestedFamily, requestedWeight, false, coordSize, requestedSize);

View File

@@ -8,23 +8,24 @@
FontInfoDesired::FontInfoDesired(const std::wstring_view& faceName,
const unsigned char family,
const unsigned int weight,
const til::size coordSizeDesired,
const float fontSize,
const unsigned int codePage) noexcept :
FontInfoBase(faceName, family, weight, false, codePage),
_coordSizeDesired(coordSizeDesired)
_coordSizeDesired{ 0, lroundf(fontSize) },
_fontSize{ fontSize }
{
}
FontInfoDesired::FontInfoDesired(const FontInfo& fiFont) noexcept :
FontInfoBase(fiFont),
_coordSizeDesired(fiFont.GetUnscaledSize())
_coordSizeDesired{ fiFont.GetUnscaledSize() },
_fontSize{ static_cast<float>(_coordSizeDesired.height) }
{
}
bool FontInfoDesired::operator==(const FontInfoDesired& other) noexcept
float FontInfoDesired::GetFontSize() const noexcept
{
return FontInfoBase::operator==(other) &&
_coordSizeDesired == other._coordSizeDesired;
return _fontSize;
}
til::size FontInfoDesired::GetEngineSize() const noexcept

View File

@@ -27,15 +27,17 @@ public:
FontInfoDesired(const std::wstring_view& faceName,
const unsigned char family,
const unsigned int weight,
const til::size coordSizeDesired,
const float fontSize,
const unsigned int uiCodePage) noexcept;
FontInfoDesired(const FontInfo& fiFont) noexcept;
bool operator==(const FontInfoDesired& other) noexcept;
bool operator==(const FontInfoDesired& other) = delete;
float GetFontSize() const noexcept;
til::size GetEngineSize() const noexcept;
bool IsDefaultRasterFont() const noexcept;
private:
til::size _coordSizeDesired;
float _fontSize;
};