Skip to content
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

Support rendering of underline style and color #16097

Merged
merged 24 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d2bea4c
initial commit for underline style and color
tusharsnx Oct 3, 2023
d341402
add new underline styles in UIA
tusharsnx Oct 9, 2023
a042401
draw curly line from the shader
tusharsnx Oct 12, 2023
e16055c
revert D2D antialias mode
tusharsnx Oct 12, 2023
1df5894
fix gridlines being drawn with underline color
tusharsnx Oct 14, 2023
0bdeb1a
add dotted underline to BackendD2D and Dx renderers
tusharsnx Oct 14, 2023
c179041
fix ScrollTest's MockScrollRenderEngine wasn't updated to receive und…
tusharsnx Oct 14, 2023
8684de8
make sine wave start with a crest
tusharsnx Oct 16, 2023
dc986c1
fix strikethrough being drawn with underline color
tusharsnx Oct 16, 2023
bea07a5
add support for underline styles in gdi renderer
tusharsnx Oct 24, 2023
4f13a3c
add spellings
tusharsnx Oct 24, 2023
1f3e535
fix signed/unsigned mismatch
tusharsnx Oct 25, 2023
2babe7b
make small improvements to Atlas curlyline rendering
tusharsnx Oct 25, 2023
e31d0fb
AtlasEngine: use cellBottomGap as the peak height for curly line
tusharsnx Oct 27, 2023
63ae6ce
GDIRenderer: use cellBottomGap as the peak height for curly line
tusharsnx Oct 27, 2023
b5574d0
initialize _curlyLineDrawPeakHeight
tusharsnx Oct 27, 2023
b8d3caa
send line rendition scale using texcoord
tusharsnx Oct 28, 2023
a2c4a36
underlines are mutually exclusive
tusharsnx Oct 28, 2023
6e4c65a
revert underline thickness scaling
tusharsnx Oct 28, 2023
b0be8b6
move curlyline peak height constants into the function
tusharsnx Nov 2, 2023
1ba1782
fix curlyline equation that was making a negative peak at the start
tusharsnx Nov 2, 2023
4f7ba10
BackendD2D: use `else if`
tusharsnx Nov 2, 2023
c7a8a55
shrink QuadInstance::ShadingType and add renditionScale member
tusharsnx Nov 3, 2023
3923fde
replace SelectObject with wil::SelectObject
tusharsnx Nov 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/actions/spelling/expect/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ CTRLVOLUME
Ctxt
CUF
cupxy
curlyline
CURRENTFONT
currentmode
CURRENTPAGE
Expand Down Expand Up @@ -578,6 +579,7 @@ elems
emacs
EMPTYBOX
enabledelayedexpansion
ENDCAP
endptr
endregion
ENTIREBUFFER
Expand Down Expand Up @@ -826,6 +828,7 @@ hostlib
HPA
hpcon
HPCON
hpen
hpj
HPR
HProvider
Expand Down Expand Up @@ -1010,6 +1013,7 @@ LOBYTE
localappdata
locsrc
Loewen
LOGBRUSH
LOGFONT
LOGFONTA
LOGFONTW
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/UnitTests_TerminalCore/ScrollTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace
HRESULT InvalidateCircling(_Out_ bool* /*pForcePaint*/) noexcept { return S_OK; }
HRESULT PaintBackground() noexcept { return S_OK; }
HRESULT PaintBufferLine(std::span<const Cluster> /*clusters*/, til::point /*coord*/, bool /*fTrimLeft*/, bool /*lineWrapped*/) noexcept { return S_OK; }
HRESULT PaintBufferGridLines(GridLineSet /*lines*/, COLORREF /*color*/, size_t /*cchLine*/, til::point /*coordTarget*/) noexcept { return S_OK; }
HRESULT PaintBufferGridLines(GridLineSet /*lines*/, COLORREF /*gridlineColor*/, COLORREF /*underlineColor*/, size_t /*cchLine*/, til::point /*coordTarget*/) noexcept { return S_OK; }
HRESULT PaintSelection(const til::rect& /*rect*/) noexcept { return S_OK; }
HRESULT PaintCursor(const CursorOptions& /*options*/) noexcept { return S_OK; }
HRESULT UpdateDrawingBrushes(const TextAttribute& /*textAttributes*/, const RenderSettings& /*renderSettings*/, gsl::not_null<IRenderData*> /*pData*/, bool /*usingSoftFont*/, bool /*isSettingDefaultBrushes*/) noexcept { return S_OK; }
Expand Down
7 changes: 4 additions & 3 deletions src/interactivity/onecore/BgfxEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,10 @@ CATCH_RETURN()
CATCH_RETURN()
}

[[nodiscard]] HRESULT BgfxEngine::PaintBufferGridLines(GridLineSet const /*lines*/,
COLORREF const /*color*/,
size_t const /*cchLine*/,
[[nodiscard]] HRESULT BgfxEngine::PaintBufferGridLines(const GridLineSet /*lines*/,
const COLORREF /*gridlineColor*/,
const COLORREF /*underlineColor*/,
const size_t /*cchLine*/,
const til::point /*coordTarget*/) noexcept
{
return S_OK;
Expand Down
2 changes: 1 addition & 1 deletion src/interactivity/onecore/BgfxEngine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ namespace Microsoft::Console::Render
const til::point coord,
const bool trimLeft,
const bool lineWrapped) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(GridLineSet const lines, COLORREF const color, size_t const cchLine, til::point const coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(const GridLineSet lines, const COLORREF gridlineColor, const COLORREF underlineColor, const size_t cchLine, const til::point coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintSelection(const til::rect& rect) noexcept override;

[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;
Expand Down
7 changes: 4 additions & 3 deletions src/renderer/atlas/AtlasEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,16 +375,17 @@ try
}
CATCH_RETURN()

[[nodiscard]] HRESULT AtlasEngine::PaintBufferGridLines(const GridLineSet lines, const COLORREF color, const size_t cchLine, const til::point coordTarget) noexcept
[[nodiscard]] HRESULT AtlasEngine::PaintBufferGridLines(const GridLineSet lines, const COLORREF gridlineColor, const COLORREF underlineColor, const size_t cchLine, const til::point coordTarget) noexcept
try
{
const auto shift = gsl::narrow_cast<u8>(_api.lineRendition != LineRendition::SingleWidth);
const auto x = std::max(0, coordTarget.x - (_p.s->viewportOffset.x >> shift));
const auto y = gsl::narrow_cast<u16>(clamp<til::CoordType>(coordTarget.y, 0, _p.s->viewportCellCount.y));
const auto from = gsl::narrow_cast<u16>(clamp<til::CoordType>(x << shift, 0, _p.s->viewportCellCount.x - 1));
const auto to = gsl::narrow_cast<u16>(clamp<size_t>((x + cchLine) << shift, from, _p.s->viewportCellCount.x));
const auto fg = gsl::narrow_cast<u32>(color) | 0xff000000;
_p.rows[y]->gridLineRanges.emplace_back(lines, fg, from, to);
const auto glColor = gsl::narrow_cast<u32>(gridlineColor) | 0xff000000;
const auto ulColor = gsl::narrow_cast<u32>(underlineColor) | 0xff000000;
_p.rows[y]->gridLineRanges.emplace_back(lines, glColor, ulColor, from, to);
return S_OK;
}
CATCH_RETURN()
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/atlas/AtlasEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ namespace Microsoft::Console::Render::Atlas
[[nodiscard]] HRESULT PrepareLineTransform(LineRendition lineRendition, til::CoordType targetRow, til::CoordType viewportLeft) noexcept override;
[[nodiscard]] HRESULT PaintBackground() noexcept override;
[[nodiscard]] HRESULT PaintBufferLine(std::span<const Cluster> clusters, til::point coord, bool fTrimLeft, bool lineWrapped) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(GridLineSet lines, COLORREF color, size_t cchLine, til::point coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(const GridLineSet lines, const COLORREF gridlineColor, const COLORREF underlineColor, const size_t cchLine, const til::point coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintSelection(const til::rect& rect) noexcept override;
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;
[[nodiscard]] HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes, const RenderSettings& renderSettings, gsl::not_null<IRenderData*> pData, bool usingSoftFont, bool isSettingDefaultBrushes) noexcept override;
Expand Down
26 changes: 13 additions & 13 deletions src/renderer/atlas/BackendD2D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ void BackendD2D::_drawGridlineRow(const RenderingPayload& p, const ShapedRow* ro

D2D1_POINT_2F point0{ 0, static_cast<f32>(textCellCenter) };
D2D1_POINT_2F point1{ 0, static_cast<f32>(textCellCenter + cellSize.y) };
const auto brush = _brushWithColor(r.color);
const auto brush = _brushWithColor(r.gridlineColor);
const f32 w = pos.height;
const f32 hw = w * 0.5f;

Expand All @@ -421,11 +421,11 @@ void BackendD2D::_drawGridlineRow(const RenderingPayload& p, const ShapedRow* ro
_renderTarget->DrawLine(point0, point1, brush, w, nullptr);
}
};
const auto appendHorizontalLine = [&](const GridLineRange& r, FontDecorationPosition pos, ID2D1StrokeStyle* strokeStyle) {
const auto appendHorizontalLine = [&](const GridLineRange& r, FontDecorationPosition pos, ID2D1StrokeStyle* strokeStyle, const u32 color) {
const auto from = r.from >> widthShift;
const auto to = r.to >> widthShift;

const auto brush = _brushWithColor(r.color);
const auto brush = _brushWithColor(color);
const f32 w = pos.height;
const f32 centerY = textCellCenter + pos.position + w * 0.5f;
const D2D1_POINT_2F point0{ static_cast<f32>(from * cellSize.x), centerY };
Expand All @@ -448,32 +448,32 @@ void BackendD2D::_drawGridlineRow(const RenderingPayload& p, const ShapedRow* ro
}
if (r.lines.test(GridLines::Top))
{
appendHorizontalLine(r, p.s->font->gridTop, nullptr);
appendHorizontalLine(r, p.s->font->gridTop, nullptr, r.gridlineColor);
}
if (r.lines.test(GridLines::Bottom))
{
appendHorizontalLine(r, p.s->font->gridBottom, nullptr);
appendHorizontalLine(r, p.s->font->gridBottom, nullptr, r.gridlineColor);
}
if (r.lines.test(GridLines::Strikethrough))
{
appendHorizontalLine(r, p.s->font->strikethrough, nullptr, r.gridlineColor);
}

if (r.lines.test(GridLines::Underline))
{
appendHorizontalLine(r, p.s->font->underline, nullptr);
appendHorizontalLine(r, p.s->font->underline, nullptr, r.underlineColor);
}
if (r.lines.test(GridLines::HyperlinkUnderline))
if (r.lines.any(GridLines::DottedUnderline, GridLines::HyperlinkUnderline))
{
appendHorizontalLine(r, p.s->font->underline, _dottedStrokeStyle.get());
appendHorizontalLine(r, p.s->font->underline, _dottedStrokeStyle.get(), r.underlineColor);
}
if (r.lines.test(GridLines::DoubleUnderline))
{
for (const auto pos : p.s->font->doubleUnderline)
{
appendHorizontalLine(r, pos, nullptr);
appendHorizontalLine(r, pos, nullptr, r.underlineColor);
}
}
if (r.lines.test(GridLines::Strikethrough))
{
appendHorizontalLine(r, p.s->font->strikethrough, nullptr);
}
}
}

Expand Down
91 changes: 71 additions & 20 deletions src/renderer/atlas/BackendD3D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ TIL_FAST_MATH_BEGIN

using namespace Microsoft::Console::Render::Atlas;

namespace
{

// The max height of Curly line peak in `em` units.
constexpr auto MaxCurlyLinePeakHeightEm = 0.075f;

// We aim for atleast 1px height, but since we draw 1px smaller curly line,
// we aim for 2px height as a result.
constexpr auto MinCurlyLinePeakHeight = 2.0f;

}
tusharsnx marked this conversation as resolved.
Show resolved Hide resolved

template<>
struct std::hash<u16>
{
Expand Down Expand Up @@ -305,6 +317,31 @@ void BackendD3D::_updateFontDependents(const RenderingPayload& p)
{
const auto& font = *p.s->font;

// 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 = font.underline.height / 2.0f;
const auto underlineMidY = font.underline.position + strokeHalfWidth;
const auto cellBottomGap = font.cellSize.y - underlineMidY - strokeHalfWidth;
const auto maxCurlyLinePeakHeight = MaxCurlyLinePeakHeightEm * font.fontSize;
auto curlyLinePeakHeight = std::min(cellBottomGap, maxCurlyLinePeakHeight);

// When it's too small to be curly, make it straight.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clever!

Copy link
Contributor

@alabuzhev alabuzhev Nov 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi guys,

Something isn't right here: I can't see curly underlines until I change font size to at least 35 in conhost or 20 in WT, which is huge even on a full HD screen:

Conhost (20) | WT (12.8107)
image

It's definitely not too small to be curly yet:
wezterm (8.0)
image

Technically it's not too small if the wave height is at least 2 pixels:
image

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be the case for me too when using a 1440p monitor.

Copy link
Contributor Author

@tusharsnx tusharsnx Nov 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curly line is only drawn when there's enough space for it 1 - space between (singly) underline and Cell bottom. If we don't do this, the curly line will always be rendered, but it would be clipped, which wouldn't look nice (or correct) 😅

For example, when using Courier New (font):

When WT draws Curlyline:

image

When it doesn't:

Screenshot 2023-11-10 204936

I'd love to help you guys 😀, but can you file an issue for this? We can discuss in detail what might be causing this issue at those font sizes. Also, make sure to add font name (and other details that might be helpful) for repro.

Footnotes

  1. To get a rough idea of how much space is available between cell bottom and underlines is to select the cell where the underline is drawn. Cell area is highlighted by the selection, and you can see how much space is available between cell bottom and underline baseline. This works on Conhost too (even better since you can scroll to increase fontsize, and the selection is preserved).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you file an issue for this?

Sure, #16288

if (curlyLinePeakHeight < MinCurlyLinePeakHeight)
{
curlyLinePeakHeight = 0;
}

// We draw a smaller curly line (-1px) to avoid clipping due to the rounding.
_curlyLineDrawPeakHeight = std::max(0.0f, curlyLinePeakHeight - 1.0f);

const auto curlyUnderlinePos = font.underline.position - curlyLinePeakHeight;
const auto curlyUnderlineWidth = 2.0f * (curlyLinePeakHeight + strokeHalfWidth);
const auto curlyUnderlinePosU16 = gsl::narrow_cast<u16>(lrintf(curlyUnderlinePos));
const auto curlyUnderlineWidthU16 = gsl::narrow_cast<u16>(lrintf(curlyUnderlineWidth));
_curlyUnderline = { curlyUnderlinePosU16, curlyUnderlineWidthU16 };

DWrite_GetRenderParams(p.dwriteFactory.get(), &_gamma, &_cleartypeEnhancedContrast, &_grayscaleEnhancedContrast, _textRenderingParams.put());
// Clearing the atlas requires BeginDraw(), which is expensive. Defer this until we need Direct2D anyways.
_fontChangedResetGlyphAtlas = true;
Expand Down Expand Up @@ -539,6 +576,9 @@ void BackendD3D::_recreateConstBuffer(const RenderingPayload& p) const
DWrite_GetGammaRatios(_gamma, data.gammaRatios);
data.enhancedContrast = p.s->font->antialiasingMode == AntialiasingMode::ClearType ? _cleartypeEnhancedContrast : _grayscaleEnhancedContrast;
data.underlineWidth = p.s->font->underline.height;
data.curlyLineWaveFreq = 2.0f * 3.14f / p.s->font->cellSize.x;
lhecker marked this conversation as resolved.
Show resolved Hide resolved
data.curlyLinePeakHeight = _curlyLineDrawPeakHeight;
data.curlyLineCellOffset = p.s->font->underline.position + p.s->font->underline.height / 2.0f;
p.deviceContext->UpdateSubresource(_psConstantBuffer.get(), 0, nullptr, &data, 0, 0);
}
}
Expand Down Expand Up @@ -1643,8 +1683,6 @@ void BackendD3D::_drawGridlines(const RenderingPayload& p, u16 y)
const auto verticalShift = static_cast<u8>(row->lineRendition >= LineRendition::DoubleHeightTop);

const auto cellSize = p.s->font->cellSize;
const auto dottedLineType = horizontalShift ? ShadingType::DottedLineWide : ShadingType::DottedLine;

const auto rowTop = static_cast<i16>(cellSize.y * y);
const auto rowBottom = static_cast<i16>(rowTop + cellSize.y);

Expand All @@ -1671,11 +1709,11 @@ void BackendD3D::_drawGridlines(const RenderingPayload& p, u16 y)
.shadingType = ShadingType::SolidLine,
.position = { static_cast<i16>(posX), rowTop },
.size = { width, p.s->font->cellSize.y },
.color = r.color,
.color = r.gridlineColor,
};
}
};
const auto appendHorizontalLine = [&](const GridLineRange& r, FontDecorationPosition pos, ShadingType shadingType) {
const auto appendHorizontalLine = [&](const GridLineRange& r, FontDecorationPosition pos, ShadingType shadingType, const u32 color) {
const auto offset = pos.position << verticalShift;
const auto height = static_cast<u16>(pos.height << verticalShift);

Expand All @@ -1693,7 +1731,8 @@ void BackendD3D::_drawGridlines(const RenderingPayload& p, u16 y)
.shadingType = shadingType,
.position = { left, static_cast<i16>(rt) },
.size = { width, static_cast<u16>(rb - rt) },
.color = r.color,
.texcoord = { static_cast<u16>(1 << horizontalShift), static_cast<u16>(1 << verticalShift) },
.color = color,
};
}
};
Expand All @@ -1713,32 +1752,40 @@ void BackendD3D::_drawGridlines(const RenderingPayload& p, u16 y)
}
if (r.lines.test(GridLines::Top))
{
appendHorizontalLine(r, p.s->font->gridTop, ShadingType::SolidLine);
appendHorizontalLine(r, p.s->font->gridTop, ShadingType::SolidLine, r.gridlineColor);
}
if (r.lines.test(GridLines::Bottom))
{
appendHorizontalLine(r, p.s->font->gridBottom, ShadingType::SolidLine);
appendHorizontalLine(r, p.s->font->gridBottom, ShadingType::SolidLine, r.gridlineColor);
}
if (r.lines.test(GridLines::Strikethrough))
{
appendHorizontalLine(r, p.s->font->strikethrough, ShadingType::SolidLine, r.gridlineColor);
}

if (r.lines.test(GridLines::Underline))
{
appendHorizontalLine(r, p.s->font->underline, ShadingType::SolidLine);
appendHorizontalLine(r, p.s->font->underline, ShadingType::SolidLine, r.underlineColor);
}
else if (r.lines.any(GridLines::DottedUnderline, GridLines::HyperlinkUnderline))
{
appendHorizontalLine(r, p.s->font->underline, ShadingType::DottedLine, r.underlineColor);
}
if (r.lines.test(GridLines::HyperlinkUnderline))
else if (r.lines.test(GridLines::DashedUnderline))
{
appendHorizontalLine(r, p.s->font->underline, dottedLineType);
appendHorizontalLine(r, p.s->font->underline, ShadingType::DashedLine, r.underlineColor);
}
if (r.lines.test(GridLines::DoubleUnderline))
else if (r.lines.test(GridLines::CurlyUnderline))
{
appendHorizontalLine(r, _curlyUnderline, ShadingType::CurlyLine, r.underlineColor);
}
else if (r.lines.test(GridLines::DoubleUnderline))
tusharsnx marked this conversation as resolved.
Show resolved Hide resolved
{
for (const auto pos : p.s->font->doubleUnderline)
{
appendHorizontalLine(r, pos, ShadingType::SolidLine);
appendHorizontalLine(r, pos, ShadingType::SolidLine, r.underlineColor);
}
}
if (r.lines.test(GridLines::Strikethrough))
{
appendHorizontalLine(r, p.s->font->strikethrough, ShadingType::SolidLine);
}
}
}

Expand Down Expand Up @@ -1963,6 +2010,10 @@ size_t BackendD3D::_drawCursorForegroundSlowPath(const CursorRect& c, size_t off
return 0;
}

// Line drawing primitives requires texcoord to remain the same. Using this
// flag, we'll also avoid the need for branching in the calculations below.
lhecker marked this conversation as resolved.
Show resolved Hide resolved
const auto isStyledLineDrawing = static_cast<u8>(it.shadingType >= ShadingType::StyledLineDrawingFirst && it.shadingType <= ShadingType::StyledLineDrawingLast);

const int cursorL = c.position.x;
const int cursorT = c.position.y;
const int cursorR = cursorL + c.size.x;
Expand Down Expand Up @@ -2042,8 +2093,8 @@ size_t BackendD3D::_drawCursorForegroundSlowPath(const CursorRect& c, size_t off
target.position.y = static_cast<i16>(cutout.top);
target.size.x = static_cast<u16>(cutout.right - cutout.left);
target.size.y = static_cast<u16>(cutout.bottom - cutout.top);
target.texcoord.x = static_cast<u16>(it.texcoord.x + cutout.left - instanceL);
target.texcoord.y = static_cast<u16>(it.texcoord.y + cutout.top - instanceT);
target.texcoord.x = static_cast<u16>(it.texcoord.x + !isStyledLineDrawing * (cutout.left - instanceL));
target.texcoord.y = static_cast<u16>(it.texcoord.y + !isStyledLineDrawing * (cutout.top - instanceT));
target.color = it.color;
}

Expand All @@ -2059,8 +2110,8 @@ size_t BackendD3D::_drawCursorForegroundSlowPath(const CursorRect& c, size_t off
target.position.y = static_cast<i16>(intersectionT);
target.size.x = static_cast<u16>(intersectionR - intersectionL);
target.size.y = static_cast<u16>(intersectionB - intersectionT);
target.texcoord.x = static_cast<u16>(it.texcoord.x + intersectionL - instanceL);
target.texcoord.y = static_cast<u16>(it.texcoord.y + intersectionT - instanceT);
target.texcoord.x = static_cast<u16>(it.texcoord.x + !isStyledLineDrawing * (intersectionL - instanceL));
target.texcoord.y = static_cast<u16>(it.texcoord.y + !isStyledLineDrawing * (intersectionT - instanceT));
target.color = color;

return addedInstances;
Expand Down
18 changes: 14 additions & 4 deletions src/renderer/atlas/BackendD3D.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ namespace Microsoft::Console::Render::Atlas
alignas(sizeof(f32x4)) f32 gammaRatios[4]{};
alignas(sizeof(f32)) f32 enhancedContrast = 0;
alignas(sizeof(f32)) f32 underlineWidth = 0;
alignas(sizeof(f32)) f32 curlyLinePeakHeight = 0;
alignas(sizeof(f32)) f32 curlyLineWaveFreq = 0;
alignas(sizeof(f32)) f32 curlyLineCellOffset = 0;
#pragma warning(suppress : 4324) // 'PSConstBuffer': structure was padded due to alignment specifier
};

Expand All @@ -65,16 +68,20 @@ namespace Microsoft::Console::Render::Atlas
TextGrayscale = 1,
TextClearType = 2,
TextPassthrough = 3,
// Keep all styled line drawing primitives together.
DottedLine = 4,
DottedLineWide = 5,
DashedLine = 5,
CurlyLine = 6,
// All items starting here will be drawing as a solid RGBA color
SolidLine = 6,
SolidLine = 7,

Cursor = 7,
Selection = 8,
Cursor = 8,
Selection = 9,

TextDrawingFirst = TextGrayscale,
TextDrawingLast = SolidLine,
StyledLineDrawingFirst = DottedLine,
StyledLineDrawingLast = CurlyLine
};

// NOTE: Don't initialize any members in this struct. This ensures that no
Expand Down Expand Up @@ -291,6 +298,9 @@ namespace Microsoft::Console::Render::Atlas
// The bounding rect of _cursorRects in pixels.
til::rect _cursorPosition;

f32 _curlyLineDrawPeakHeight = 0;
FontDecorationPosition _curlyUnderline;

bool _requiresContinuousRedraw = false;

#if ATLAS_DEBUG_SHOW_DIRTY
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/atlas/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,8 @@ namespace Microsoft::Console::Render::Atlas
struct GridLineRange
{
GridLineSet lines;
u32 color = 0;
u32 gridlineColor = 0;
u32 underlineColor = 0;
u16 from = 0;
u16 to = 0;
};
Expand Down
Loading