Repository: microsoft/terminal (language: cpp)

Issue:
Permit fractional 0.5 sized font scaling
<!-- 
🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨

I ACKNOWLEDGE THE FOLLOWING BEFORE PROCEEDING:
1. If I delete this entire template and go my own path, the core team may close my issue without further explanation or engagement.
2. If I list multiple bugs/concerns in this one issue, the core team may close my issue without further explanation or engagement.
3. If I write an issue that has many duplicates, the core team may close my issue without further explanation or engagement (and without necessarily spending time to find the exact duplicate ID number).
4. If I leave the title incomplete when filing the issue, the core team may close my issue without further explanation or engagement.
5. If I file something completely blank in the body, the core team may close my issue without further explanation or engagement.

All good? Then proceed!
-->

# Description of the new feature/enhancement

Allow users to set font sizes in `0.5` increments, e.g.:
```
            "fontSize": 8.5
```


**half-point differences are meaningful at this scale.**



![1](https://user-images.githubusercontent.com/4319522/85814710-938e9980-b734-11ea-8f7a-f5539cb05f46.gif)


Discussion / hints:
Fractional point sizes are sufficiently rare in the wild that I’ll have to ask:
Why?
Vs Code permits fractional sizing, because the jump between `8` and `9` is quite drastic, especially on some fonts.
**half-point differences are meaningful at this scale.**

For example, Cascadia Code looks terrible at size 8
![image](https://user-images.githubusercontent.com/4319522/85762072-5d73fa00-b6e1-11ea-9465-4034bffc9511.png)

At size 9 it looks much better, but takes up too much space

![image](https://user-images.githubusercontent.com/4319522/85762117-68c72580-b6e1-11ea-98de-d93ffd0d6963.png)





Alright, sure, I'll throw this on the backlog. This will require a good amount of renderer changes, as that's a shared component with conhost and we've always only ever supported integral sizes.

A font's presentation should not vary so wildly between 8.5 and 9 (which, I might add, *is only 1/144 of an inch of difference* [1]). What you're probably seeing is a difference in _hinting_. If the font is hinted at 8 and hinted differently at 9, 8.5 is probably totally unhinted and you're getting raw geometries?

[1] Given that 1pt is 1/72", 0.5pt is 1/144". That is imperceptibly small. Imperceptibly!
Honestly, it might be easier to add a setting to turn off hinting. That would get you the 8.5 behavior at 8 or at 9.
@DHowett Most likely @musm's setup (aka DPI, scaling factor, rasterization) is such that switching from 8pt to 9pt causes the renderer to round up versus round down, thus making everything larger.

To be honest, I don't know if adding fractional point sizes will help. Ultimately the rasterizer is still going to try and lock the glyphs to a whole pixel, so it'll just guess up or down. As you posited, disabling hinting might be the easier fix as I expect the 9pt wouldn't jump up quite so significantly. 

However, it comes at the cost of blurrier text, so it'd definitely be a "use at your own risk" sort of thing!
@aaronbell Interesting theory. Do you why this would only apply to Cascadia Code and not other fonts? Personally I'd love to use it but I'm stuck in a gray zone where size 8 is too small and size 9 is way too large.

DPI: Well I'm running 100% no scaling at all. 


@musm Out of interest, do you happen to have a 72 DPI screen? I suddenly remembered something :)

In Cascadia Code, there is what's called a GASP table which tells the rasterizer when to turn on / off hinting, and what kind of rasterization approach to use. Right now the GASP table instructions are set to turn on hinting at 9ppem (which equated to 9pt on a 72DPI screen) and above. This setting is following the recommendation of the font rasterization experts at Microsoft. 

So what could be happening is that when you switch over to 9pt, the hinting is kicking in to help the font render more sharply and it is making the letters bigger. This may not happen for other fonts because their GASP tables are set differently. 

According to https://dpi.lv/

![image](https://user-images.githubusercontent.com/4319522/88883041-499c4600-d201-11ea-9631-f9a782ce05f8.png)

🤔 
I'm still puzzled by the drastic jump in font  size  between size `8` and `7`. Especially compared to, say, VS Code. 



![1](https://user-images.githubusercontent.com/4319522/98452100-542c7c80-211a-11eb-9277-633fe535877f.gif)


I'm on the same boat. Something is off with the font rendering and I often enough wished that I could have the font size that is just in-between 10 and 11, or 11 and 12.
I too have used Consolas at size 16 on classic console. ConEmu also calculated the font size differently to the classic console, but there the developer considered UX and decided that a font size of 14 would render identically to the classic console, which was also set as the default in that app. I'm using a 1920x1200 screen and classic terminal's consolas font at 16 is just perfect.

In Windows Terminal the font is either too small (at size 10) or too large (size 11). Being able to specify and render at a fractional size would help me get the optimal compromise between screen real estate used and being able to easily read the console text.
Same issue here. I'm using a Windows surface and Hack font. The font size is either too large (10) or too small (9). I'm looking for a solution to this issue. Thanks!
Any chance this could get triaged? The number of users reporting running into the same issue  suggests this is indeed something that needs to be looked into. 
This _has_ been triaged: it's P3, on the backlog, and if somebody wants to have a look at implementing it they are very welcome to :smile:
This would definitely be appreciated - it seems like the font sizes (at least for Consolas) are _exactly_ two-thirds in Windows Terminal as they are in the old terminal, which means it's currently impossible to make the text size the same in both unless it's a multiple of three. In the old console, Consolas at 16px looked perfect, but now I'm stuck with 10pt (15px) or 11pt (16.5px), the latter of which looks weirdly stretched horizontally (the vertical bar of a `+` is twice as thick as the horizontal bar, etc).
I would also love this, no matter what i do or what font i use it's always blurry like it's got the wrong size and it's resizing it afterwards.
It's just hard to read, and consolas at 16px as stated by others looks great, but you sadly can't get it pixel-perfect in windows terminal as far as i can tell because of the integer size steps.
> This would definitely be appreciated - it seems like the font sizes (at least for Consolas) are _exactly_ two-thirds in Windows Terminal as they are in the old terminal, which means it's currently impossible to make the text size the same in both unless it's a multiple of three. In the old console, Consolas at 16px looked perfect, but now I'm stuck with 10pt (15px) or 11pt (16.5px), the latter of which looks weirdly stretched horizontally (the vertical bar of a `+` is twice as thick as the horizontal bar, etc).

Right, this makes it a little frustrating especially for those that prefer very small font sizes.
I don't know anything about how you guys do rendering, but I use DPI scaling and when I'm tweaking font sizes in CSS for a browser I can make adjustments even in hundreds of a rem and they do make a difference.
Also I wanted to ask here if anyone has any ideas about how to turn off DPI scaling for this app. I tried the normal way of turning it off for every `.exe` file, but that has no effect.
I don't understand almost anything about font rendering, for me it's a bit confusing. For example using Sublime Text setting the font to size 10 is the same as size 16 in Windows command prompt 😄

Basically if an improvement is possible, I would like the Windows Terminal fonts to be rendered the same way as the command prompt, powershell or cmder.
The fonts from these terminals I mentioned seem to be a little sharper and a little thinner (the inner outline of the fonts looks better). I for example could not make the font size of Windows Terminal equal to the command prompt. It must be what I mentioned about the contour being a little different (maybe I'm talking about antializing).
Here in the documentation there is even an example, the letter "e" the inner outline almost closes the letter.
https://docs.microsoft.com/en-us/windows/terminal/customize-settings/profile-advanced

I'm starting to use Windows Terminal and I'm really enjoying it. This was really missing for Windows.
If you have any tips I appreciate it.

Fix patch:
diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json
index e60b1151268..19742372e2d 100644
--- a/doc/cascadia/profiles.schema.json
+++ b/doc/cascadia/profiles.schema.json
@@ -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": {
diff --git a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp
index 373e9c55046..7514bcc426f 100644
--- a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp
+++ b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp
@@ -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
diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp
index 2ca286f4a81..7fa53304299 100644
--- a/src/cascadia/TerminalControl/ControlCore.cpp
+++ b/src/cascadia/TerminalControl/ControlCore.cpp
@@ -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
diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h
index 07b9b46228b..d2649b53a67 100644
--- a/src/cascadia/TerminalControl/ControlCore.h
+++ b/src/cascadia/TerminalControl/ControlCore.h
@@ -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();
diff --git a/src/cascadia/TerminalControl/ControlCore.idl b/src/cascadia/TerminalControl/ControlCore.idl
index 200258fae01..a65384e2bc2 100644
--- a/src/cascadia/TerminalControl/ControlCore.idl
+++ b/src/cascadia/TerminalControl/ControlCore.idl
@@ -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);
 
diff --git a/src/cascadia/TerminalControl/ControlInteractivity.cpp b/src/cascadia/TerminalControl/ControlInteractivity.cpp
index 75b8cf5b614..25508db5631 100644
--- a/src/cascadia/TerminalControl/ControlInteractivity.cpp
+++ b/src/cascadia/TerminalControl/ControlInteractivity.cpp
@@ -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)
     {
diff --git a/src/cascadia/TerminalControl/ControlInteractivity.h b/src/cascadia/TerminalControl/ControlInteractivity.h
index 3d47ad7c0c9..4025e765425 100644
--- a/src/cascadia/TerminalControl/ControlInteractivity.h
+++ b/src/cascadia/TerminalControl/ControlInteractivity.h
@@ -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);
 
diff --git a/src/cascadia/TerminalControl/IControlSettings.idl b/src/cascadia/TerminalControl/IControlSettings.idl
index 66ea5a33625..a7bfcf255a3 100644
--- a/src/cascadia/TerminalControl/IControlSettings.idl
+++ b/src/cascadia/TerminalControl/IControlSettings.idl
@@ -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; };
diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp
index 5d4061ee4a3..a965f35ff8c 100644
--- a/src/cascadia/TerminalControl/TermControl.cpp
+++ b/src/cascadia/TerminalControl/TermControl.cpp
@@ -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
diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h
index cfa0265adf9..afa134dbef3 100644
--- a/src/cascadia/TerminalControl/TermControl.h
+++ b/src/cascadia/TerminalControl/TermControl.h
@@ -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;
 
diff --git a/src/cascadia/TerminalControl/TermControl.idl b/src/cascadia/TerminalControl/TermControl.idl
index 745e3d55664..29080e6b8de 100644
--- a/src/cascadia/TerminalControl/TermControl.idl
+++ b/src/cascadia/TerminalControl/TermControl.idl
@@ -71,7 +71,7 @@ namespace Microsoft.Terminal.Control
 
         void SearchMatch(Boolean goForward);
 
-        void AdjustFontSize(Int32 fontSizeDelta);
+        void AdjustFontSize(Single fontSizeDelta);
         void ResetFontSize();
 
         void ToggleShaderEffects();
diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.idl b/src/cascadia/TerminalSettingsEditor/Appearances.idl
index 7963a59e8a7..39068ee8254 100644
--- a/src/cascadia/TerminalSettingsEditor/Appearances.idl
+++ b/src/cascadia/TerminalSettingsEditor/Appearances.idl
@@ -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);
diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h
index 7dc91ac32e6..62fd9f9a085 100644
--- a/src/cascadia/TerminalSettingsModel/ActionArgs.h
+++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h
@@ -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) \
diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl
index dba7587a69d..d24322072b6 100644
--- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl
+++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl
@@ -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
diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp
index f65f1884e99..0c6cf503092 100644
--- a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp
+++ b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp
@@ -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()) };
diff --git a/src/cascadia/TerminalSettingsModel/FontConfig.idl b/src/cascadia/TerminalSettingsModel/FontConfig.idl
index 37d2aeb8050..174a6ff74b0 100644
--- a/src/cascadia/TerminalSettingsModel/FontConfig.idl
+++ b/src/cascadia/TerminalSettingsModel/FontConfig.idl
@@ -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);
diff --git a/src/cascadia/TerminalSettingsModel/MTSMSettings.h b/src/cascadia/TerminalSettingsModel/MTSMSettings.h
index 27897ecb60e..3cae1919883 100644
--- a/src/cascadia/TerminalSettingsModel/MTSMSettings.h
+++ b/src/cascadia/TerminalSettingsModel/MTSMSettings.h
@@ -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")
diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.h b/src/cascadia/TerminalSettingsModel/TerminalSettings.h
index 7647cd477ea..0dd65cdfbb7 100644
--- a/src/cascadia/TerminalSettingsModel/TerminalSettings.h
+++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.h
@@ -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);
diff --git a/src/cascadia/inc/ControlProperties.h b/src/cascadia/inc/ControlProperties.h
index 8c0468b2018..5911fa26183 100644
--- a/src/cascadia/inc/ControlProperties.h
+++ b/src/cascadia/inc/ControlProperties.h
@@ -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)                                                                                                                            \
diff --git a/src/renderer/atlas/AtlasEngine.api.cpp b/src/renderer/atlas/AtlasEngine.api.cpp
index 8861704b5f6..a6c44e2a881 100644
--- a/src/renderer/atlas/AtlasEngine.api.cpp
+++ b/src/renderer/atlas/AtlasEngine.api.cpp
@@ -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;
@@ -659,7 +661,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);
 
     {
@@ -672,8 +674,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);
diff --git a/src/renderer/base/FontInfoDesired.cpp b/src/renderer/base/FontInfoDesired.cpp
index aa6648d0dbe..8340aeab12b 100644
--- a/src/renderer/base/FontInfoDesired.cpp
+++ b/src/renderer/base/FontInfoDesired.cpp
@@ -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
diff --git a/src/renderer/inc/FontInfoDesired.hpp b/src/renderer/inc/FontInfoDesired.hpp
index f4085629202..5e77e466f9c 100644
--- a/src/renderer/inc/FontInfoDesired.hpp
+++ b/src/renderer/inc/FontInfoDesired.hpp
@@ -27,15 +27,17 @@ class FontInfoDesired : public FontInfoBase
     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;
 };


Test patch: