Skip to content

Commit

Permalink
Add support for fractional font sizes (microsoft#14013)
Browse files Browse the repository at this point in the history
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 microsoft#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 ✅
  • Loading branch information
lhecker authored Sep 16, 2022
1 parent 6567201 commit c51bb3a
Show file tree
Hide file tree
Showing 22 changed files with 65 additions and 56 deletions.
4 changes: 2 additions & 2 deletions doc/cascadia/profiles.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@
"default": 12,
"description": "Size of the font in points.",
"minimum": 1,
"type": "integer"
"type": "number"
},
"weight": {
"default": "normal",
Expand Down Expand Up @@ -2252,7 +2252,7 @@
"default": 12,
"description": "[deprecated] Define 'size' within the 'font' object instead.",
"minimum": 1,
"type": "integer",
"type": "number",
"deprecated": true
},
"fontWeight": {
Expand Down
4 changes: 2 additions & 2 deletions src/cascadia/PublicTerminalCore/HwndTerminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down Expand Up @@ -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
Expand Down
24 changes: 14 additions & 10 deletions src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand All @@ -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();
}
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalControl/ControlCore.idl
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
16 changes: 8 additions & 8 deletions src/cascadia/TerminalControl/ControlInteractivity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}

Expand All @@ -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)
{
Expand Down
6 changes: 3 additions & 3 deletions src/cascadia/TerminalControl/ControlInteractivity.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalControl/IControlSettings.idl
Original file line number Diff line number Diff line change
Expand Up @@ -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; };
Expand Down
6 changes: 3 additions & 3 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalControl/TermControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalControl/TermControl.idl
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ namespace Microsoft.Terminal.Control

void SearchMatch(Boolean goForward);

void AdjustFontSize(Int32 fontSizeDelta);
void AdjustFontSize(Single fontSizeDelta);
void ResetFontSize();

void ToggleShaderEffects();
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalSettingsEditor/Appearances.idl
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalSettingsModel/ActionArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalSettingsModel/ActionArgs.idl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()) };
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalSettingsModel/FontConfig.idl
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalSettingsModel/MTSMSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalSettingsModel/TerminalSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/inc/ControlProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
11 changes: 6 additions & 5 deletions src/renderer/atlas/AtlasEngine.api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -573,6 +574,7 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
}
if (!requestedSize.Y)
{
fontSize = 12.0f;
requestedSize = { 0, 12 };
}
if (!requestedWeight)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

{
Expand All @@ -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);
Expand Down
Loading

0 comments on commit c51bb3a

Please sign in to comment.