-
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 all 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,31 @@ 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 | ||
// Since we use GDI pen for drawing, the underline offset should point to | ||
// the center of the underline. | ||
const auto underlineHalfWidth = gsl::narrow_cast<int>(std::floor(_lineMetrics.underlineWidth / 2.0f)); | ||
_lineMetrics.underlineOffset += underlineHalfWidth; | ||
_lineMetrics.underlineOffset2 += underlineHalfWidth; | ||
|
||
// Curlyline is drawn with a desired height relative to the font size. The | ||
// baseline of curlyline is at the middle of singly underline. When there's | ||
// limited space to draw a curlyline, we 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) | ||
// initialize curlyline peak height to a desired value. Clamp it to at | ||
// least 1. | ||
constexpr auto curlyLinePeakHeightEm = 0.075f; | ||
_lineMetrics.curlylinePeakHeight = gsl::narrow_cast<int>(std::max(1L, std::lround(curlyLinePeakHeightEm * fontSize))); | ||
|
||
// calc the limit we need to apply | ||
const auto maxDrawableCurlyLinePeakHeight = Font.GetSize().height - _lineMetrics.underlineOffset - _lineMetrics.underlineWidth; | ||
|
||
// if the limit is <= 0 (no height at all), stick with the desired height. | ||
// This is how we force a curlyline even when there's no space, though it | ||
// might be clipped at the bottom. | ||
if (maxDrawableCurlyLinePeakHeight > 0.0f) | ||
{ | ||
curlyLinePeakHeight = 0.0f; | ||
_lineMetrics.curlylinePeakHeight = std::min(_lineMetrics.curlylinePeakHeight, maxDrawableCurlyLinePeakHeight); | ||
} | ||
Comment on lines
+421
to
424
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 found that this behavior can look somewhat unpleasant when Ctrl+scrolling up and down when using Consolas, because it'll jump in between very squiggly lines and barely squiggly lines all the time. Additionally, and unrelated to your PR, I'm having trouble ever getting the double-underline to separate into two distinct lines. So, I'm currently doing a couple modifications to this function to bring it closer to the corresponding AtlasEngine code: Using floats throughout the function, unless rounding is needed (= for instance, right before calculating the thin line width) and I'm porting Word's double underline algorithm over. My hope is that all this will allow me to better understand how your current code works and to come up with an idea for making the transition between curly and less-curly lines "smoother". (I'll submit the above changes in a different PR after this one merges.) Personally speaking I don't agree with this:
I think discontinuous lines are better, if it avoids clipping. But I also get that discontinuous lines are kind of weird too. 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.
That sounds good to me. I have a few ideas that I'll just share here:
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.
j4james briefly mentioned it in his comment in the original PR that brought doubly underlined rendering support:
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've just had a chat with Dustin, and we compared different approaches. Word's double-underline algorithm does look fairly well at small and big font sizes and works better with Consolas. Using the I'll approve this PR because it puts this code in a fantastic state to do further "fine tuning" on it. Thank you so much for working on this! I also didn't want to ask you to make any more changes, since I don't want to put any more unnecessary burden on you. I'll link the follow-up PR here and post screenshots there to compare the changes. 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. Done: #16475 |
||
_lineMetrics.curlylinePeakHeight = gsl::narrow_cast<int>(std::floor(curlyLinePeakHeight)); | ||
} | ||
|
||
// 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.)