Repository: microsoft/terminal (language: cpp)

Issue:
Terminus TTF Font not rendering properly at certain sizes
### Windows Terminal version

1.16.2523.0

### Windows build number

10.0.19044.1826

### Other Software

Terminus TTF font installed from https://files.ax86.net/terminus-ttf/

WSL, running Ubuntu 20.04.1 LTS, SSHing into an Arch Linux machine

### Steps to reproduce

In the Font configuration menu, select "Terminus (TTF) for Windows"
Select a font size that doesn't correspond to a native bitmap size (eg. 14 pt)

### Expected Behavior

Terminus TTF Font renders as it does at a size corresponding to a native bitmap size

See example from Windows Terminal 1.14.2281.0
![terminus_14pt_1 14](https://user-images.githubusercontent.com/1494294/190281968-5fb90a45-4cca-4c90-95a1-cea31ddd8df2.png)


### Actual Behavior

Font renders with visible artifacting
![terminus_14pt_1 16](https://user-images.githubusercontent.com/1494294/190282018-922ad24f-0974-4806-b0ce-354ca35f3c41.png)



Discussion / hints:
@fizz125 the latest terminal release has the `AtlasEngine` enabled by default. If you turn if off `Terminus` will look better.

Size 14 with AtlasEngine on:

![atlas_engine_on_terminus](https://user-images.githubusercontent.com/3933920/190317316-b696367b-f004-4eb8-b21a-2f1f2dfecb11.png)

and with AtlasEngine off:

![atlas_engine_off_terminus](https://user-images.githubusercontent.com/3933920/190317377-81ac0240-cc59-455c-afa6-575d1047e888.png)

I'm noticing similarly weird rendering with CaskaydiaCove Nerd Font. 

New engine: 
![image](https://user-images.githubusercontent.com/21368066/190403747-04ee36a8-56eb-4b47-8e50-897a64e064b1.png)

Old engine:
![image](https://user-images.githubusercontent.com/21368066/190403981-334f8f68-4907-4d48-82bb-51260082b274.png)

The old engine makes the letters look rounder, fuller.
@elsaco Thanks for the comparison!

The old text renderer rounds the font size to match the column width in pixel which appears to just so happened to have worked with Terminus TTF. The new text renderer doesn't do that anymore - if you specify 14pt you'll get _exactly_ 14pt. But Terminus TTF doesn't support 14pt. It only supports 13.5pt.

As such the solution to me seems like we should simply allow users to specify fractional font sizes. To test this idea I ran AtlasEngine with Terminus TTF at 13pt and 100% display scale. Then I replaced the `requestedSize.Y` with the fractional font size `13.5f` here:
https://github.com/microsoft/terminal/blob/e2b2d9b92cf75d7841c80b222be9100eabe093ac/src/renderer/atlas/AtlasEngine.api.cpp#L617-L618

Et voilà (`Old` = Windows Terminal 1.16, `New` = patched AtlasEngine)!

![fractional_font_size](https://user-images.githubusercontent.com/2256941/190433927-22517e3d-9a8c-481c-bea9-73f858374b71.gif)

---

@jedieaston I'm not convinced that the old version is better (`Old` = Windows Terminal 1.15, `New` = 1.16):

![CaskaydiaCove_AtlasEngine_comparison](https://user-images.githubusercontent.com/2256941/190409404-abd9657b-b90b-4cfa-bb53-aec6b5790f6b.gif)

@elsaco Sure, that's the obvious workaround. But since this behavior isn't the same in the old engine, I wasn't sure if this was a regression or not.

@lhecker The documentation for the TTF font calls out that there may be issues with using the font at sizes for which there aren't bitmaps available, so if the answer is "Don't use Terminus TTF at non-bitmap-available sizes" then that's fine with me and this bug can be closed. But I wanted to make sure it wasn't a regression or an issue with the new engine

Thanks!
FWIW #6678 does have a lot of traction, so if it's "trivial" to just fix that, then maybe we should.
> I wasn't sure if this was a regression or not.

I personally would consider it a regression, because even if it just randomly happened to have worked before, it definitely doesn't work now. I'm currently finishing a PR that will close #6678. Additionally it'll also fix some other issues in respect to your issue which will then definitely remove those gaps and draw pixel-perfect bitmap line drawings.

Fix patch:
diff --git a/src/renderer/atlas/AtlasEngine.api.cpp b/src/renderer/atlas/AtlasEngine.api.cpp
index 8861704b5f6..81c8e7bf349 100644
--- a/src/renderer/atlas/AtlasEngine.api.cpp
+++ b/src/renderer/atlas/AtlasEngine.api.cpp
@@ -620,7 +620,6 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
     const auto designUnitsPerPx = fontSizeInPx / static_cast<float>(metrics.designUnitsPerEm);
     const auto ascent = static_cast<float>(metrics.ascent) * designUnitsPerPx;
     const auto descent = static_cast<float>(metrics.descent) * designUnitsPerPx;
-    const auto lineGap = static_cast<float>(metrics.lineGap) * designUnitsPerPx;
     const auto underlinePosition = static_cast<float>(-metrics.underlinePosition) * designUnitsPerPx;
     const auto underlineThickness = static_cast<float>(metrics.underlineThickness) * designUnitsPerPx;
     const auto strikethroughPosition = static_cast<float>(-metrics.strikethroughPosition) * designUnitsPerPx;
@@ -628,9 +627,13 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
 
     const auto advanceWidth = static_cast<float>(glyphMetrics.advanceWidth) * designUnitsPerPx;
 
-    const auto halfGap = lineGap / 2.0f;
-    const auto baseline = std::roundf(ascent + halfGap);
-    const auto lineHeight = std::roundf(baseline + descent + halfGap);
+    // NOTE: Line-gaps shouldn't be taken into account for lineHeight calculations.
+    // Terminals don't really have "gaps" between lines and instead the expectation
+    // is that two full block characters above each other don't leave any gaps
+    // between the lines. "Terminus TTF" for instance sets a line-gap of 90 units
+    // even though its font bitmap only covers the ascend/descend height.
+    const auto baseline = std::roundf(ascent);
+    const auto lineHeight = std::roundf(baseline + descent);
     const auto underlinePos = std::roundf(baseline + underlinePosition);
     const auto underlineWidth = std::max(1.0f, std::roundf(underlineThickness));
     const auto strikethroughPos = std::roundf(baseline + strikethroughPosition);
diff --git a/src/renderer/atlas/AtlasEngine.cpp b/src/renderer/atlas/AtlasEngine.cpp
index 4bdde3da691..ae4b1f8e2ed 100644
--- a/src/renderer/atlas/AtlasEngine.cpp
+++ b/src/renderer/atlas/AtlasEngine.cpp
@@ -1102,7 +1102,6 @@ void AtlasEngine::_recreateFontDependentResources()
                 auto& textFormat = _r.textFormats[italic][bold];
 
                 THROW_IF_FAILED(_sr.dwriteFactory->CreateTextFormat(_api.fontMetrics.fontName.c_str(), _api.fontMetrics.fontCollection.get(), fontWeight, fontStyle, DWRITE_FONT_STRETCH_NORMAL, _api.fontMetrics.fontSizeInDIP, L"", textFormat.put()));
-                THROW_IF_FAILED(textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
                 THROW_IF_FAILED(textFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP));
 
                 // DWRITE_LINE_SPACING_METHOD_UNIFORM:
@@ -1111,11 +1110,16 @@ void AtlasEngine::_recreateFontDependentResources()
                 // We want that. Otherwise fallback fonts might be rendered with an incorrect baseline and get cut off vertically.
                 THROW_IF_FAILED(textFormat->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, _r.cellSizeDIP.y, _api.fontMetrics.baselineInDIP));
 
-                if (const auto textFormat3 = textFormat.try_query<IDWriteTextFormat3>())
-                {
-                    THROW_IF_FAILED(textFormat3->SetAutomaticFontAxes(DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE));
+                // NOTE: SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER) breaks certain
+                // bitmap fonts which expect glyphs to be laid out left-aligned.
+
+                // NOTE: SetAutomaticFontAxes(DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE) breaks certain
+                // fonts making them look fairly unslightly. With no option to easily disable this
+                // feature in Windows Terminal, it's better left disabled by default.
 
-                    if (!_api.fontAxisValues.empty())
+                if (!_api.fontAxisValues.empty())
+                {
+                    if (const auto textFormat3 = textFormat.try_query<IDWriteTextFormat3>())
                     {
                         // The wght axis defaults to the font weight.
                         _api.fontAxisValues[0].value = bold || standardAxes[0].value == -1.0f ? static_cast<float>(fontWeight) : standardAxes[0].value;


Test patch: