Skip to content

Commit

Permalink
AtlasEngine: Fix bugs around bitmap font rendering (#14014)
Browse files Browse the repository at this point in the history
This commit fixes several issues:
* Some fonts set a line-gap even though they behave as if they
  don't want any line-gaps. Since Terminals don't really have
  any gaps anyways, it'll now not be taken into account anymore.
* Center alignment breaks bitmap glyphs which expect left-alignment.
* Automatic "opsz" axis makes Terminus TTF's italic glyphs look quite
  weird. I disabled this feature as we might not need it anyways.

A complete fix depends on #14013
Closes #14006

## Validation Steps Performed
* Use Terminus TTF at 13.5pt
* Print UTF-8-demo.txt
* No gaps between block characters ✅
  • Loading branch information
lhecker authored Sep 16, 2022
1 parent 81e2bc9 commit bea13bd
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 9 deletions.
11 changes: 7 additions & 4 deletions src/renderer/atlas/AtlasEngine.api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -620,17 +620,20 @@ 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;
const auto strikethroughThickness = static_cast<float>(metrics.strikethroughThickness) * designUnitsPerPx;

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);
Expand Down
14 changes: 9 additions & 5 deletions src/renderer/atlas/AtlasEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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;
Expand Down

0 comments on commit bea13bd

Please sign in to comment.