-
Notifications
You must be signed in to change notification settings - Fork 8.4k
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
Remember to have block and line drawing characters fill their cells properly #455
Comments
You know, I coulda swore @miniksa had a PR for this just last week, but I dunno what happened to it... |
Some more examples, comparing mlterm (running in Ubuntu on WSL with X410) with Windows Terminal See it exhibits not only the block and line characters alignments and joints issues, but also identical colors rendering as different colors (the whole ANSI-art is using only the 16 palettized VT colors). You can get the test file from the following repository : https://github.com/PhMajerus/ANSI-art/blob/master/TestPattern%20ANSI.ans |
I just tested it and it looks like the colors are now matching correctly. So, this is gonna be fixed in #688. |
I did find another bug though, look at how some characters get rendered incorrectly if I didn't execute another command before showing the test pattern. One more thing, try zooming in (Ctrl mwheel) and at the right level of magnification the output looks perfectly fine. |
@ghosty141 thanks for fixing and testing it, that's one thing out of the way. What you're observing are the two other issues I described in the first message. The terminal cells and the size of the block drawing characters do not match at all zoom levels, making them overlap or not fill their cell, creating visual horizontal lines. The last issue with the � characters appearing a bit randomly seems like a bug in Terminal itself, and is probably in the rendering engine as it depends on the zoom level and at the same time seems to always appear at the exact same place for the exact same buffer to render. |
@PhMajerus, I'm aware of the randomish U+FFFD issue. I have an outstanding task to try to debug why that's happening. I'll get to it eventually. |
F7 is implemented in the |
OK, so, the line gap thing isn't really working. So now I'm going crazy in Excel finding something that I can use to adjust the baseline, the overall height, or whatnot either for the entire font or for the glyphs only in the U+2500-U+259F range (with the ascenderOffset flag inside the |
Another note: Anonymous Pro has line drawing chars but no box drawing chars, so that's a fallback and probably why it's looking extra weird. |
@miniksa This is amazing compared to the previous rendering, great work! The problem is the original EGA/VGA font (8x14 font in ROM on old graphic cards) had the pattern perfect for alignment, but even the CGA (8x8) was somewhat off for the dark shade block. If I remember correctly, the default font used in Win95 console needed an alternate of shaded blocks to fit properly side by side (as in, inverting the foreground and background colors and using the opposite shading block to make their joins merge correctly using an invisible checkerboard pattern). So I wouldn't worry too much about it for v1, the result you got already seems on par with other mature terminal emulators. I find the colors narrowing a bigger problem for ANSI-art and Text UI, especially the convertion of black background to transparent background when they were explicitly black instead of CSI 49m. Can you include the following in your tests ? |
That might actually be #2661 |
@zadjii-msft I just want to make sure you have a test case where the background color of a cell happens to be the exact same color as the default background color as seen by legacy conhost concepts, but needs to stay solid opaque, while CSI 49m gives acrylic transparency. Thanks for all the work on fixing VT edge cases, It is looking great so far. |
OK I spent all day fiddling around. I have the math that matches the results from the states above. Unfortunately I put the "with gap correction" to the left of "w/o gap correction"... but it goes as follows. If there are 3 green boxes next to each other for that font... it's going to look fine in the Terminal. The left most one is green if the designed height of the █ glyph is tall enough to fit the cell space we've given it after we've ceiling'd the baseline so it lands on a solid pixel and ceiling'd out the cell as a whole to an integer height. (We integer-ify the baseline to ensure that the bottom of characters sits nice and crisply on a pixel. We integer-ify the cell height out to a perfect integer to enable scrolling offload.) The middle column is green if the top of the █ glyph will touch or stretch outside the top of the cell after it's been drawn at the modified baseline. There were 4 triple-greens in the old algorithm (which aligned with the specific fonts in the test data). And there are 3 triple-greens in the linegap-adjust algorithm (also aligning with the specific fonts in the test data.) I believe there's two steps to success here:
Beyond that, I've written some code today that:
My goal for Friday will be:
And the backup plan is:
Either the main or backup plan solution should eliminate all gapping in both the X and Y dimensions for all of these glyphs no matter what font is used and no matter if that font implements all of these glyphs or not. |
That’s a lot of work to work around font rendering issues. It seems that having a lot of complicated mitigation code might make it more difficult for font designers to test their fonts, as they might be tinkering with their design to try to make something that looks good in a few test apps, and the different heuristics used by the code might appear random from the font designer point of view. I believe we need a switch to explicitly turn off all mitigation code paths so they can test their fonts against the more predictable optimized renderer and try to build a font that doesn’t rely on fallback paths. That would be both in settings.json and at the renderer XAML control level for other apps hosting the Terminal. About using the font glyphs versus a fixed set of block elements and line drawing glyphs, I agree using the font to allow fonts to have their own identities. For that idea, I have a suggestion that I believe would provide added value to the Windows Terminal in general and provide a fallback mechanism for our current issue when needed. |
Thanks for your response, @PhMajerus. I still believe it's up to me to fix it in a complex way because I'm the one breaking it in the first place for many of these fonts. I'm the one adding additional vertical line padding in some cases and throwing off the prescribed dimensions of the fonts. I do it in order to use the scrolling mechanisms of Present1, maintain the integer-pixel cell dimensions that most of our code and client applications rely on, and to try to preserve the crispness of the glyphs through these adjustments. I know the "just don't mess with it" solution would probably resolve this on its own, but then I'd have to give back all the performance I got from differential drawing and Present1 and I'd have a new host of problems with hit testing and line wrapping and API-mapping. I do believe in adding a fallback mechanism including being able to specify which ranges it applies to, but that's definitely going to come after 1.0 with the complexity of the settings configuration required. Such a thing will also still require me to adjust the analysis steps to further parse and identify the ranges to apply each font to, so that would have to be done for either path. Finally... I think adding a setting to turn it off might be advisable and possible. |
OK as of this (fe4e1c7), here's what we have: Test fonts: Screenshots
|
## Summary of the Pull Request Identifies and scales glyphs in the box and line drawing ranges U+2500-U+259F to fit their cells. ## PR Checklist * [x] Closes #455 * [x] I work here. * [x] Manual tests. This is all graphical. * [x] Metric ton of comments * [x] Math spreadsheet included in PR. * [x] Double check RTL glyphs. * [x] Why is there the extra pixel? * [x] Scrolling the mouse wheel check is done. * [x] Not drawing outline? * [x] Am core contributor. Roar. * [x] Try suppressing negative scale factors and see if that gets rid of weird shading. ## Detailed Description of the Pull Request / Additional comments ### Background - We want the Terminal to be fast at drawing. To be fast at drawing, we perform differential drawing, or only drawing what is different from the previous frame. We use DXGI's `Present1` method to help us with this as it helps us compose only the deltas onto the previous frame at drawing time and assists us in scrolling regions from the previous frame without intervention. However, it only works on strictly integer pixel row heights. - Most of the hit testing and size-calculation logic in both the `conhost` and the Terminal products are based on the size of an individual cell. Historically, a cell was always dictated in a `COORD` structure, or two `SHORT` values... which are integers. As such, when we specify the space for any individual glyph to be displayed inside our terminal drawing region, we want it to fall perfectly inside of an integer box to ensure all these other algorithms work correctly and continue to do so. - Finally, we want the Terminal to have font fallback and locate glyphs that aren't in the primary selected font from any other font it can find on the system that contains the glyph, per DirectWrite's font fallback mechanisms. These glyphs won't necessarily have the same font or glyph metrics as the base font, but we need them to fit inside the same cell dimensions as if they did because the hit testing and other algorithms aren't aware of which particular font is sourcing each glyph, just the dimensions of the bounding box per cell. ### How does Terminal deal with this? - When we select a font, we perform some calculations using the design metrics of the font and glyphs to determine how we could fit them inside a cell with integer dimensions. Our process here is that we take the requested font size (which is generally a proxy for height), find the matching glyph width for that height then round it to an integer. We back convert from that now integer width to a height value which is almost certainly now a floating point number. But because we need an integer box value, we add line padding above and below the glyphs to ensure that the height is an integer as well as the width. Finally, we don't add the padding strictly equally. We attempt to align the English baseline of the glyph box directly onto an integer pixel multiple so most characters sit crisply on a line when displayed. - Note that fonts and their glyphs have a prescribed baseline, line gap, and advance values. We use those as guidelines to get us started, but then to meet our requirements, we pad out from those. This results in fonts that should be properly authored showing gaps. It also results in fonts that are improperly authored looking even worse than they normally would. ### Now how does block and line drawing come in? - Block and Line drawing glyphs are generally authored so they will look fine when the font and glyph metrics are followed exactly as prescribed by the font. (For some fonts, this still isn't true and we want them to look fine anyway.) - When we add additional padding or rounding to make glyphs fit inside of a cell, we can be adding more space than was prescribed around these glyphs. This can cause a gap to be visible. - Additionally, when we move things like baselines to land on a perfect integer pixel, we may be drawing a glyph lower in the bounding box than was prescribed originally. ### And how do we solve it? - We identify all glyphs in the line and block drawing ranges. - We find the bounding boxes of both the cell and the glyph. - We compare the height of the glyph to the height of the cell to see if we need to scale. We prescribe a scale transform if the glyph wouldn't be tall enough to fit the box. (We leave it alone otherwise as some glyphs intentionally overscan the box and scaling them can cause banding effects.) - We inspect the overhang/underhang above and below the boxes and translate transform them (slide them) so they cover the entire cell area. - We repeat the previous two steps but in the horizontal direction. ## Validation Steps Performed - See these commments: - #455 (comment) - #455 (comment) - #455 (comment) Also see the below one with more screenshots: - #5743 (comment)
## Summary of the Pull Request Identifies and scales glyphs in the box and line drawing ranges U+2500-U+259F to fit their cells. ## PR Checklist * [x] Closes #455 * [x] I work here. * [x] Manual tests. This is all graphical. * [x] Metric ton of comments * [x] Math spreadsheet included in PR. * [x] Double check RTL glyphs. * [x] Why is there the extra pixel? * [x] Scrolling the mouse wheel check is done. * [x] Not drawing outline? * [x] Am core contributor. Roar. * [x] Try suppressing negative scale factors and see if that gets rid of weird shading. ## Detailed Description of the Pull Request / Additional comments ### Background - We want the Terminal to be fast at drawing. To be fast at drawing, we perform differential drawing, or only drawing what is different from the previous frame. We use DXGI's `Present1` method to help us with this as it helps us compose only the deltas onto the previous frame at drawing time and assists us in scrolling regions from the previous frame without intervention. However, it only works on strictly integer pixel row heights. - Most of the hit testing and size-calculation logic in both the `conhost` and the Terminal products are based on the size of an individual cell. Historically, a cell was always dictated in a `COORD` structure, or two `SHORT` values... which are integers. As such, when we specify the space for any individual glyph to be displayed inside our terminal drawing region, we want it to fall perfectly inside of an integer box to ensure all these other algorithms work correctly and continue to do so. - Finally, we want the Terminal to have font fallback and locate glyphs that aren't in the primary selected font from any other font it can find on the system that contains the glyph, per DirectWrite's font fallback mechanisms. These glyphs won't necessarily have the same font or glyph metrics as the base font, but we need them to fit inside the same cell dimensions as if they did because the hit testing and other algorithms aren't aware of which particular font is sourcing each glyph, just the dimensions of the bounding box per cell. ### How does Terminal deal with this? - When we select a font, we perform some calculations using the design metrics of the font and glyphs to determine how we could fit them inside a cell with integer dimensions. Our process here is that we take the requested font size (which is generally a proxy for height), find the matching glyph width for that height then round it to an integer. We back convert from that now integer width to a height value which is almost certainly now a floating point number. But because we need an integer box value, we add line padding above and below the glyphs to ensure that the height is an integer as well as the width. Finally, we don't add the padding strictly equally. We attempt to align the English baseline of the glyph box directly onto an integer pixel multiple so most characters sit crisply on a line when displayed. - Note that fonts and their glyphs have a prescribed baseline, line gap, and advance values. We use those as guidelines to get us started, but then to meet our requirements, we pad out from those. This results in fonts that should be properly authored showing gaps. It also results in fonts that are improperly authored looking even worse than they normally would. ### Now how does block and line drawing come in? - Block and Line drawing glyphs are generally authored so they will look fine when the font and glyph metrics are followed exactly as prescribed by the font. (For some fonts, this still isn't true and we want them to look fine anyway.) - When we add additional padding or rounding to make glyphs fit inside of a cell, we can be adding more space than was prescribed around these glyphs. This can cause a gap to be visible. - Additionally, when we move things like baselines to land on a perfect integer pixel, we may be drawing a glyph lower in the bounding box than was prescribed originally. ### And how do we solve it? - We identify all glyphs in the line and block drawing ranges. - We find the bounding boxes of both the cell and the glyph. - We compare the height of the glyph to the height of the cell to see if we need to scale. We prescribe a scale transform if the glyph wouldn't be tall enough to fit the box. (We leave it alone otherwise as some glyphs intentionally overscan the box and scaling them can cause banding effects.) - We inspect the overhang/underhang above and below the boxes and translate transform them (slide them) so they cover the entire cell area. - We repeat the previous two steps but in the horizontal direction. ## Validation Steps Performed - See these commments: - #455 (comment) - #455 (comment) - #455 (comment) Also see the below one with more screenshots: - #5743 (comment) (cherry picked from commit 70867df)
🎉This issue was addressed in #5743, which has now been successfully released as Handy links: |
## Summary of the Pull Request Identifies and scales glyphs in the box and line drawing ranges U+2500-U+259F to fit their cells. ## PR Checklist * [x] Closes microsoft#455 * [x] I work here. * [x] Manual tests. This is all graphical. * [x] Metric ton of comments * [x] Math spreadsheet included in PR. * [x] Double check RTL glyphs. * [x] Why is there the extra pixel? * [x] Scrolling the mouse wheel check is done. * [x] Not drawing outline? * [x] Am core contributor. Roar. * [x] Try suppressing negative scale factors and see if that gets rid of weird shading. ## Detailed Description of the Pull Request / Additional comments ### Background - We want the Terminal to be fast at drawing. To be fast at drawing, we perform differential drawing, or only drawing what is different from the previous frame. We use DXGI's `Present1` method to help us with this as it helps us compose only the deltas onto the previous frame at drawing time and assists us in scrolling regions from the previous frame without intervention. However, it only works on strictly integer pixel row heights. - Most of the hit testing and size-calculation logic in both the `conhost` and the Terminal products are based on the size of an individual cell. Historically, a cell was always dictated in a `COORD` structure, or two `SHORT` values... which are integers. As such, when we specify the space for any individual glyph to be displayed inside our terminal drawing region, we want it to fall perfectly inside of an integer box to ensure all these other algorithms work correctly and continue to do so. - Finally, we want the Terminal to have font fallback and locate glyphs that aren't in the primary selected font from any other font it can find on the system that contains the glyph, per DirectWrite's font fallback mechanisms. These glyphs won't necessarily have the same font or glyph metrics as the base font, but we need them to fit inside the same cell dimensions as if they did because the hit testing and other algorithms aren't aware of which particular font is sourcing each glyph, just the dimensions of the bounding box per cell. ### How does Terminal deal with this? - When we select a font, we perform some calculations using the design metrics of the font and glyphs to determine how we could fit them inside a cell with integer dimensions. Our process here is that we take the requested font size (which is generally a proxy for height), find the matching glyph width for that height then round it to an integer. We back convert from that now integer width to a height value which is almost certainly now a floating point number. But because we need an integer box value, we add line padding above and below the glyphs to ensure that the height is an integer as well as the width. Finally, we don't add the padding strictly equally. We attempt to align the English baseline of the glyph box directly onto an integer pixel multiple so most characters sit crisply on a line when displayed. - Note that fonts and their glyphs have a prescribed baseline, line gap, and advance values. We use those as guidelines to get us started, but then to meet our requirements, we pad out from those. This results in fonts that should be properly authored showing gaps. It also results in fonts that are improperly authored looking even worse than they normally would. ### Now how does block and line drawing come in? - Block and Line drawing glyphs are generally authored so they will look fine when the font and glyph metrics are followed exactly as prescribed by the font. (For some fonts, this still isn't true and we want them to look fine anyway.) - When we add additional padding or rounding to make glyphs fit inside of a cell, we can be adding more space than was prescribed around these glyphs. This can cause a gap to be visible. - Additionally, when we move things like baselines to land on a perfect integer pixel, we may be drawing a glyph lower in the bounding box than was prescribed originally. ### And how do we solve it? - We identify all glyphs in the line and block drawing ranges. - We find the bounding boxes of both the cell and the glyph. - We compare the height of the glyph to the height of the cell to see if we need to scale. We prescribe a scale transform if the glyph wouldn't be tall enough to fit the box. (We leave it alone otherwise as some glyphs intentionally overscan the box and scaling them can cause banding effects.) - We inspect the overhang/underhang above and below the boxes and translate transform them (slide them) so they cover the entire cell area. - We repeat the previous two steps but in the horizontal direction. ## Validation Steps Performed - See these commments: - microsoft#455 (comment) - microsoft#455 (comment) - microsoft#455 (comment) Also see the below one with more screenshots: - microsoft#5743 (comment)
## Summary of the Pull Request Identifies and scales glyphs in the box and line drawing ranges U+2500-U+259F to fit their cells. ## PR Checklist * [x] Closes #455 * [x] I work here. * [x] Manual tests. This is all graphical. * [x] Metric ton of comments * [x] Math spreadsheet included in PR. * [x] Double check RTL glyphs. * [x] Why is there the extra pixel? * [x] Scrolling the mouse wheel check is done. * [x] Not drawing outline? * [x] Am core contributor. Roar. * [x] Try suppressing negative scale factors and see if that gets rid of weird shading. ## Detailed Description of the Pull Request / Additional comments ### Background - We want the Terminal to be fast at drawing. To be fast at drawing, we perform differential drawing, or only drawing what is different from the previous frame. We use DXGI's `Present1` method to help us with this as it helps us compose only the deltas onto the previous frame at drawing time and assists us in scrolling regions from the previous frame without intervention. However, it only works on strictly integer pixel row heights. - Most of the hit testing and size-calculation logic in both the `conhost` and the Terminal products are based on the size of an individual cell. Historically, a cell was always dictated in a `COORD` structure, or two `SHORT` values... which are integers. As such, when we specify the space for any individual glyph to be displayed inside our terminal drawing region, we want it to fall perfectly inside of an integer box to ensure all these other algorithms work correctly and continue to do so. - Finally, we want the Terminal to have font fallback and locate glyphs that aren't in the primary selected font from any other font it can find on the system that contains the glyph, per DirectWrite's font fallback mechanisms. These glyphs won't necessarily have the same font or glyph metrics as the base font, but we need them to fit inside the same cell dimensions as if they did because the hit testing and other algorithms aren't aware of which particular font is sourcing each glyph, just the dimensions of the bounding box per cell. ### How does Terminal deal with this? - When we select a font, we perform some calculations using the design metrics of the font and glyphs to determine how we could fit them inside a cell with integer dimensions. Our process here is that we take the requested font size (which is generally a proxy for height), find the matching glyph width for that height then round it to an integer. We back convert from that now integer width to a height value which is almost certainly now a floating point number. But because we need an integer box value, we add line padding above and below the glyphs to ensure that the height is an integer as well as the width. Finally, we don't add the padding strictly equally. We attempt to align the English baseline of the glyph box directly onto an integer pixel multiple so most characters sit crisply on a line when displayed. - Note that fonts and their glyphs have a prescribed baseline, line gap, and advance values. We use those as guidelines to get us started, but then to meet our requirements, we pad out from those. This results in fonts that should be properly authored showing gaps. It also results in fonts that are improperly authored looking even worse than they normally would. ### Now how does block and line drawing come in? - Block and Line drawing glyphs are generally authored so they will look fine when the font and glyph metrics are followed exactly as prescribed by the font. (For some fonts, this still isn't true and we want them to look fine anyway.) - When we add additional padding or rounding to make glyphs fit inside of a cell, we can be adding more space than was prescribed around these glyphs. This can cause a gap to be visible. - Additionally, when we move things like baselines to land on a perfect integer pixel, we may be drawing a glyph lower in the bounding box than was prescribed originally. ### And how do we solve it? - We identify all glyphs in the line and block drawing ranges. - We find the bounding boxes of both the cell and the glyph. - We compare the height of the glyph to the height of the cell to see if we need to scale. We prescribe a scale transform if the glyph wouldn't be tall enough to fit the box. (We leave it alone otherwise as some glyphs intentionally overscan the box and scaling them can cause banding effects.) - We inspect the overhang/underhang above and below the boxes and translate transform them (slide them) so they cover the entire cell area. - We repeat the previous two steps but in the horizontal direction. ## Validation Steps Performed - See these commments: - microsoft/terminal#455 (comment) - microsoft/terminal#455 (comment) - microsoft/terminal#455 (comment) Also see the below one with more screenshots: - microsoft/terminal#5743 (comment)
Just a reminder for the new Windows Terminal, remember to make sure block and line drawing characters fill their cells properly at all zoom levels.
This is really important for ANSI-art and TUI apps.
See color bleeding and horizontal lines in the larger Windows Terminal tab.
Also, some characters are randomly replaced by � (<?>) characters when changing zoom level or when printing out lot of VT markup.
The text was updated successfully, but these errors were encountered: