Text between box drawing characters is rendered aliased (???) #9009

Closed
opened 2026-01-31 01:43:38 +00:00 by claunia · 10 comments
Owner

Originally created by @DHowett on GitHub (Jun 13, 2020).

Originally assigned to: @miniksa on GitHub.

When I run this in PowerShell (7),

"`e[30;47m`u{2500} What `u{2500}`e[m"

the text comes out without antialiasing. It looks like it's being drawn with FillGeometry just like a box drawing glyph.

image

If I flip the colors, it comes out antialiased.

image

To verify my theory that What was becoming part of the box drawing run, I put together a debug tool that turns glyph runs into graphviz documents.

image

Unfortunately, it doesn't look like it's so simple.

Originally created by @DHowett on GitHub (Jun 13, 2020). Originally assigned to: @miniksa on GitHub. When I run this in PowerShell (7), ``` "`e[30;47m`u{2500} What `u{2500}`e[m" ``` the text comes out without antialiasing. It looks like it's being drawn with FillGeometry just like a box drawing glyph. ![image](https://user-images.githubusercontent.com/189190/84561566-4e18a800-ad02-11ea-89b8-fe4cc58127bb.png) If I flip the colors, it comes out antialiased. ![image](https://user-images.githubusercontent.com/189190/84561569-58d33d00-ad02-11ea-83c0-56b763950ae4.png) To verify my theory that `What` was becoming part of the box drawing run, I put together a debug tool that turns glyph runs into graphviz documents. ![image](https://user-images.githubusercontent.com/189190/84561756-ff6c0d80-ad03-11ea-8e76-447cafa1dc83.png) Unfortunately, it doesn't look like it's so simple.
Author
Owner

@DHowett commented on GitHub (Jun 13, 2020):

It doesn't happen with midnight commander, which uses a lot of box drawing glyphs... because however MC is rendering, they get broken into different CustomTextLayouts.

image

image

@DHowett commented on GitHub (Jun 13, 2020): It _doesn't_ happen with midnight commander, which uses a lot of box drawing glyphs... because however MC is rendering, they get broken into _different CustomTextLayouts_. ![image](https://user-images.githubusercontent.com/189190/84561813-68538580-ad04-11ea-84d0-56147a81a335.png) ![image](https://user-images.githubusercontent.com/189190/84561816-6f7a9380-ad04-11ea-8cc4-b047c2c21478.png)
Author
Owner

@miniksa commented on GitHub (Jun 15, 2020):

what the what.

@miniksa commented on GitHub (Jun 15, 2020): what the what.
Author
Owner

@wackoisgod commented on GitHub (Jun 21, 2020):

Should be noted that i have the same issue in #6603 and when I run the same text posted above in 1.0 it renders correctly for me but in 1.1 it renders incorrectly as show by @DHowett

@wackoisgod commented on GitHub (Jun 21, 2020): Should be noted that i have the same issue in #6603 and when I run the same text posted above in 1.0 it renders correctly for me but in 1.1 it renders incorrectly as show by @DHowett
Author
Owner

@DHowett commented on GitHub (Jun 21, 2020):

@skyline75489 looks like this regressed with 94eab6e39, but I can't figure out why (since box drawing detection happens after the analysis code you changed!)

@DHowett commented on GitHub (Jun 21, 2020): @skyline75489 looks like this regressed with 94eab6e39, but I can't figure out why (since box drawing detection happens after the analysis code you changed!)
Author
Owner

@DHowett commented on GitHub (Jun 21, 2020):

Okay, this is because we're not populating _glyphClusters when text is "simple". When we go to split the run later (we split runs for things other than text analysis!), we try to remap the glyph clusters around the split.

Inevitably, we end up falling into DrawGlyphRun with run.glyphCount = 0 because _SplitCurrentRun stomped the glyphCount because there was no glyph cluster mapping.

Somehow magically we end up doing a "get raw geometry, draw" for the entire string which very handily hides the glyph clustering bug!

This fix works but I do not believe it is correct:

diff --git a/src/renderer/dx/CustomTextLayout.cpp b/src/renderer/dx/CustomTextLayout.cpp
index d19d2d0c3..395a58224 100644
--- a/src/renderer/dx/CustomTextLayout.cpp
+++ b/src/renderer/dx/CustomTextLayout.cpp
@@ -336,6 +336,7 @@ CustomTextLayout::CustomTextLayout(gsl::not_null<IDWriteFactory1*> const factory
             for (size_t i = glyphStart; i < _glyphAdvances.size(); i++)
             {
                 _glyphAdvances.at(i) = (float)_glyphDesignUnitAdvances.at(i) / designUnitsPerEm * _format->GetFontSize() * run.fontScale;
+                _glyphClusters.at(i) = static_cast<UINT16>(i);
             }

             run.glyphCount = textLength;

I'm worried about that "magical" rendering fallthrough. With this fix, are we striking the text twice -- once as a geometry and once as a glyph run?

(I commented out the glyph run drawing, and I think the answer is no.)

@DHowett commented on GitHub (Jun 21, 2020): Okay, this is because we're not populating `_glyphClusters` when text is "simple". When we go to split the run later (**we split runs for things other than text analysis!**), we try to remap the glyph clusters around the split. Inevitably, we end up falling into DrawGlyphRun with `run.glyphCount` = 0 because `_SplitCurrentRun` stomped the glyphCount because there was no glyph cluster mapping. Somehow *magically* we end up doing a "get raw geometry, draw" for the entire string which very handily hides the glyph clustering bug! This fix _works_ but I do not believe it is correct: ```diff diff --git a/src/renderer/dx/CustomTextLayout.cpp b/src/renderer/dx/CustomTextLayout.cpp index d19d2d0c3..395a58224 100644 --- a/src/renderer/dx/CustomTextLayout.cpp +++ b/src/renderer/dx/CustomTextLayout.cpp @@ -336,6 +336,7 @@ CustomTextLayout::CustomTextLayout(gsl::not_null<IDWriteFactory1*> const factory for (size_t i = glyphStart; i < _glyphAdvances.size(); i++) { _glyphAdvances.at(i) = (float)_glyphDesignUnitAdvances.at(i) / designUnitsPerEm * _format->GetFontSize() * run.fontScale; + _glyphClusters.at(i) = static_cast<UINT16>(i); } run.glyphCount = textLength; ``` I'm worried about that "magical" rendering fallthrough. With this fix, are we striking the text twice -- once as a geometry and once as a glyph run? (I commented out the glyph run drawing, and I think the answer is _no_.)
Author
Owner

@skyline75489 commented on GitHub (Jun 23, 2020):

I don't think this is correct, either. But right now I can not think of a better fix for this.

I kinda hate the fact that "we split runs for things other than text analysis". Is this a final thing or we are gonna change that in the future.

@skyline75489 commented on GitHub (Jun 23, 2020): I don't think this is correct, either. But right now I can not think of a better fix for this. I kinda hate the fact that "we split runs for things other than text analysis". Is this a final thing or we are gonna change that in the future.
Author
Owner

@skyline75489 commented on GitHub (Jun 23, 2020):

Per communication with @reli-msft I suggest fixing it by considering all runs containing box-drawing chars as complex. It's a quick fix. It should work as expected, with reasonable performance penalty.

@DHowett

@skyline75489 commented on GitHub (Jun 23, 2020): Per communication with @reli-msft I suggest fixing it by considering all runs containing box-drawing chars as complex. It's a quick fix. It should work as expected, with reasonable performance penalty. @DHowett
Author
Owner

@reli-msft commented on GitHub (Jun 23, 2020):

A proper fix should change _isEntireTextSimple into an enum to indicate how complex the text run is, and use that to determine the itemize passes to be enabled and whether we need "glyphing". For now, @skyline75489's fix would work and won't cause a lot of performance lost, since the frequency of box-drawing characters is low.

@reli-msft commented on GitHub (Jun 23, 2020): A proper fix should change `_isEntireTextSimple` into an enum to indicate _how complex_ the text run is, and use that to determine the itemize passes to be enabled and whether we need "glyphing". For now, @skyline75489's fix would work and won't cause a lot of performance lost, since the frequency of box-drawing characters is low.
Author
Owner

@DHowett commented on GitHub (Jun 24, 2020):

So, thinking a bit more about this.

I'm going to revert this in the 1.1 and master, so that we can bring it in correctly later. Folks have reported some crashes, and I'd prefer an expedient patch fix for servicing, and a fully-baked solution later 😄

@DHowett commented on GitHub (Jun 24, 2020): So, thinking a bit more about this. I'm going to revert this in the 1.1 and master, so that we can bring it in correctly later. Folks have reported some crashes, and I'd prefer an expedient patch fix for servicing, and a fully-baked solution later :smile:
Author
Owner

@ghost commented on GitHub (Jun 30, 2020):

:tada:This issue was addressed in #6665, which has now been successfully released as Windows Terminal Preview v1.1.1812.0.🎉

Handy links:

@ghost commented on GitHub (Jun 30, 2020): :tada:This issue was addressed in #6665, which has now been successfully released as `Windows Terminal Preview v1.1.1812.0`.:tada: Handy links: * [Release Notes](https://github.com/microsoft/terminal/releases/tag/v1.1.1812.0) * [Store Download](https://www.microsoft.com/store/apps/9n8g5rfz9xk3?cid=storebadge&ocid=badge)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#9009