-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix curlyline rendering in AtlasEngine
and GDIRenderer
#16444
Changes from 3 commits
a501fee
ef8a907
67c87c9
e2ca95f
9fa65f1
7a077ae
0b1ecf3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,15 +11,6 @@ | |
|
||
using namespace Microsoft::Console::Render; | ||
|
||
namespace | ||
{ | ||
// The max height of Curly line peak in `em` units. | ||
constexpr auto MaxCurlyLinePeakHeightEm = 0.075f; | ||
|
||
// The min height of Curly line peak. | ||
constexpr auto MinCurlyLinePeakHeight = 2.0f; | ||
} | ||
|
||
// Routine Description: | ||
// - Creates a new GDI-based rendering engine | ||
// - NOTE: Will throw if initialization failure. Caller must catch. | ||
|
@@ -406,29 +397,30 @@ GdiEngine::~GdiEngine() | |
_lineMetrics.underlineOffset2 = _lineMetrics.underlineOffset - _lineMetrics.gridlineWidth; | ||
} | ||
|
||
// Curly line doesn't render properly below 1px stroke width. Make it a straight line. | ||
if (_lineMetrics.underlineWidth < 1) | ||
{ | ||
_lineMetrics.curlylinePeakHeight = 0; | ||
} | ||
else | ||
const int strokeHalfWidth = std::lround(_lineMetrics.underlineWidth / 2.0); | ||
tusharsnx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Since we use GDI pen for drawing, the underline offset should point to | ||
// the center of the underline. | ||
_lineMetrics.underlineOffset += strokeHalfWidth; | ||
_lineMetrics.underlineOffset2 += strokeHalfWidth; | ||
|
||
// We want the underline to always be visible and remain within the cell | ||
// bottom, so we clamp the offset to fit just inside. | ||
_lineMetrics.underlineOffset = std::min(_lineMetrics.underlineOffset, maxUnderlineOffset); | ||
_lineMetrics.underlineOffset2 = std::min(_lineMetrics.underlineOffset2, maxUnderlineOffset); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This still seems wrong to me. The offsets have already been clamped prior to this, so no additional clamping should have been necessary. The Worst case, if you can't get it to work, at least move the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think another potential problem is that the I'd suggest writing a little test app that renders a bunch of lines of varying widths, using both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately, I'm not well-versed in Windows programming in general, so creating an app from scratch would be a different task for me 😅 However, I did experiment with the idea of comparing With this code: // a fixed offset
const auto cellMidY = std::lround(fontHeight / 2.0f);
// adjust for drawing with DrawStrokedLine()
const auto cellMidYWithHalfStrokeWidth = cellMidY + gsl::narrow_cast<int>(std::floor(_lineMetrics.underlineWidth / 2));
// Select a brush
// draw a line with PatBlt()
RETURN_HR_IF(E_FAIL, !DrawLine(ptTarget.x, ptTarget.y + cellMidY, widthOfAllCells, _lineMetrics.underlineWidth));
// Select the dotted pen
// draw a line with LineTo()
RETURN_HR_IF(E_FAIL, !DrawStrokedLine(ptTarget.x, ptTarget.y + cellMidYWithHalfStrokeWidth, widthOfAllCells)); Result: "`e[4:4m Dotted `e[m" I tried this with other font sizes, and they all show the same result. So, the
Yeah, you're right! It wouldn't have been necessary if I had floored |
||
|
||
// Curlyline uses the gap between cell bottom and singly underline position | ||
// as the height of the wave's peak. The baseline for curly line is at the | ||
// middle of singly underline. The gap could be too big, so we also apply a | ||
// limit on the peak height. | ||
{ | ||
// Curlyline uses the gap between cell bottom and singly underline | ||
// position as the height of the wave's peak. The baseline for curly | ||
// line is at the middle of singly underline. The gap could be too big, | ||
// so we also apply a limit on the peak height. | ||
const auto strokeHalfWidth = _lineMetrics.underlineWidth / 2.0f; | ||
const auto underlineMidY = _lineMetrics.underlineOffset + strokeHalfWidth; | ||
const auto cellBottomGap = Font.GetSize().height - underlineMidY - strokeHalfWidth; | ||
const auto maxCurlyLinePeakHeight = MaxCurlyLinePeakHeightEm * fontSize; | ||
auto curlyLinePeakHeight = std::min(cellBottomGap, maxCurlyLinePeakHeight); | ||
|
||
// When it's too small to be curly, make it a straight line. | ||
if (curlyLinePeakHeight < MinCurlyLinePeakHeight) | ||
{ | ||
curlyLinePeakHeight = 0.0f; | ||
} | ||
_lineMetrics.curlylinePeakHeight = gsl::narrow_cast<int>(std::floor(curlyLinePeakHeight)); | ||
const auto cellBottomGap = std::lround(Font.GetSize().height - _lineMetrics.underlineOffset - strokeHalfWidth); | ||
|
||
// get the max height for curly line peak. Max height is in `em` units. | ||
constexpr auto maxCurlyLinePeakHeightEm = 0.075f; | ||
const auto maxCurlyLinePeakHeight = std::lround(maxCurlyLinePeakHeightEm * fontSize); | ||
|
||
_lineMetrics.curlylinePeakHeight = std::clamp(cellBottomGap, 0L, maxCurlyLinePeakHeight); | ||
} | ||
|
||
// Now find the size of a 0 in this current font and save it for conversions done later. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(FYI: This PR is tiny if you suppress whitespace changes.)