microsoft / terminal

The new Windows Terminal and the original Windows console host, all in the same place!
MIT License
95.38k stars 8.3k forks source link

Investigate alternative ways to handle box drawing/block elements #5897

Closed DHowett-MSFT closed 8 months ago

DHowett-MSFT commented 4 years ago

There've been some concerns about how we scale glyphs in the Box Drawing character block.

Other terminal emulators do interesting things:

We chose not to do these things for v1.0 because we learned that certain fonts (monofur is a good one) have their own unique styles for box drawing and block elements that we wanted to preserve.

Proposed solution

Links

benc-uk commented 4 years ago

The shaded/hatched boxes now look really bad since the last update.
A lot of themes like Powerlevel10k use these

This is my prompt now in Windows Terminal image

This is what it should look like (In VS Code) image

DHowett-MSFT commented 4 years ago

yikes.

DHowett-MSFT commented 4 years ago

Though, that looks like Cascadia Code. The version released yesterday with the new metrics works properly with Terminal. You may need to update.

benc-uk commented 4 years ago

Hi, I just updated to CascadiaCode_2004.30, and I didn't see any difference :( image

Weirdly if I set my font size to 15, the shading disappears altogether, and at font size 19 it looks perfect, but that's just too huge to use!

benc-uk commented 4 years ago

Some further tests with Cascadia Code.

At font size 14 the line elements are super thin and the curved corner lacks any antialiasing/smoothing image

At font size 13 they look much better image

mdtauk commented 4 years ago

I think if this is added, it should be behind a setting. Something like

ā˜‘ Let Windows Terminal handle block character drawing

Cascadia code has an interesting approach to the character of some of it's Block Characters, and other fonts will also. That character is lost by Terminal doing it itself - so it should be optional IMO

ionut-botizan commented 4 years ago

I'd really love to see those "rect-filling primitives with opacity" make it into the Windows Terminal:

  1. top left - Windows Terminal with Fira Code 12px
  2. bottom left - Windows Terminal with Fira Code 15 px
  3. top right - [Other popular terminal] with Fira Code 12px

(the filling char I'm using is $([char]0x2592) or "ā–‘")

image

Obviously, the best looking one is the one on the right and the second best one is the one with the 15px font size. Sadly, 15px is way too big, so I'm stuck with the ugly looking one for now. šŸ™‚

DHowett commented 4 years ago

(that's a nice prompt line)

j4james commented 4 years ago

Obviously, the best looking one is the one on the right and the second best one is the one with the 15px font size. Sadly, 15px is way too big, so I'm stuck with the ugly looking one for now. šŸ™‚

I understand the desire for a better rendering of theses characters, but the terminal on the right is just displaying a solid block in a different color as far I can see. If that's what you want, you should really be using U+2588. U+2591 to U+2593 are distinct characters where the cell is filled with a pattern to produce a degree of shading. The latest version of Unicode has even added an inverse version of U+2592. That would be impossible to distinguish from U+2592 if you're just renderning them as solid blocks.

egmontkob commented 4 years ago

the terminal on the right is just displaying a solid block in a different color

This is what VTE does, too. It's a heavily debated feature/bug: https://bugzilla.gnome.org/show_bug.cgi?id=778122.

j4james commented 4 years ago

I can understand choosing to render those characters with a solid block as a compromise solution if that's the best we can do - it's probably better than the scaling artifacts. But it is a compromise - it's not what we should be aiming for as the ideal solution.

For me the ideal would be appropriately designed fill patterns, possibly scaled to account for the DPI (as long as the pattern can be retained). Those fill patterns would then be rendered to align with the coordinate system, rather than the character boundaries, so they can repeat perfectly across a range of cells.

It's possible something like that just isn't feasible for performance reasons, or API limitations, but I think we should at least consider ways to do this correctly before resorting to a compromise solution.

Edit: I've just read the whole VTE thread and I see you were proposing the same sort of thing there.

egmontkob commented 4 years ago

Yup this also occurred to us at VTE, but this method also has a drawback: as these glyphs scroll, the pattern changes. This is again hardly the expected user behavior.

This is clearly a field with contradicting requirements, and thus no single perfect solution. A compromise has to be made somewhere. It's really hard to decide or argue which solution is better or worse.

PhMajerus commented 4 years ago

There seems to be something wrong with both how Windows Terminal 1.0.1401.0 scales glyphs for shading blocks and how these glyphs appear in Cascadia Code 2005.15.

And because I know you like nice test files, here's a new one for this issue (I probably spent way too long on this one) : https://github.com/PhMajerus/ANSI-art/blob/master/Sonic%20Green%20Hill%20Zone.ans (Edit: Added a 256 colors one so you don't have to stare at the base 16 colors all the time : https://github.com/PhMajerus/ANSI-art/blob/master/Sonic%20Green%20Hill%20Zone%20(256%20colors).ans )

Windows Terminal seems to scale shading blocks without anti-aliasing, to me it looks like a nearest neighbor that loses some pixels in pattern that depend on single pixel regularity:

Windows Terminal with Consolas, see the irregular patterns in the clouds: image

Windows Terminal with Cascadia Code, see how shading blocks do not fill their cells heights (clouds and waterfall): image

It seems that the issue is only at some font sizes, as if the terminal is zoomed a bit, the shading blocks are then rendered properly (I believe this is equivalent to fontSize:13): image

Conhost with Cascadia Code, see how all block drawing and shading blocks heights are wrong: image

And same file in conhost with Consolas as a reference of how it is supposed to look: image

mdtauk commented 4 years ago

What would the consensus be with the halftone filled shapes? Should they be rendered with some kind of crosshatching like with fonts, or just an opacity fill?

This is if Terminal was to offer the ability to "handle" or "override" the box drawing.

j4james commented 4 years ago

What would the consensus be with the halftone filled shapes? Should they be rendered with some kind of crosshatching like with fonts, or just an opacity fill?

I don't understand why anyone would ask for the patterned characters to rendered with an opacity fill, unless there was no other option. You can already get an opacity effect - with much finer control - just using the existing block characters with appropriate colors. All you'd be doing is preventing other people from using patterns, which seems a spiteful sort of thing to want.

I could understand if the current rendering was the best we could achieve, and the question was do you prefer that or an opacity fill. But we haven't even tried other rendering techniques yet.

mdtauk commented 4 years ago

What would the consensus be with the halftone filled shapes? Should they be rendered with some kind of crosshatching like with fonts, or just an opacity fill?

I don't understand why anyone would ask for the patterned characters to rendered with an opacity fill, unless there was no other option. You can already get an opacity effect - with much finer control - just using the existing block characters with appropriate colors. All you'd be doing is preventing other people from using patterns, which seems a spiteful sort of thing to want.

I could understand if the current rendering was the best we could achieve, and the question was do you prefer that or an opacity fill. But we haven't even tried other rendering techniques yet.

My thinking is that the intention behind those characters would originally have substituted for a gradient or semi-transparent element. Back with 16 colours or monochrome terminals.

Some fonts use half-tone dots/squares, others (like Cascadia) use a diagonal hatching getting progressively heavier/darker.

If Windows Terminal is going to include an option to override the font's characters, and to get proper horizontal, vertical, and diagonal connecting glyphs - as well as rounded corners etc - there should perhaps be a neutral design approach, so they don't stand out as odd amongst different fonts.

So do you go for the intent behind the characters, a simulation of different shades - by actually using shades of the glyph colour - or pick a particular approach and run with it?

PhMajerus commented 4 years ago

I guess it started as a way to do intermediate colors and gradients, but over the years shading blocks got used for their texturing features as well. Now that we can use 256 and RGB colors, the pattern they provide is more interesting than the color mix. I might agree that for a built-in rendering of blocks and lines not based on a font, a pure color mix could work as a default, but it is critical to get the ability to use patterns provided by fonts. And once fonts with blocks work correctly, why would you want to return to a built-in rendering?

Even if some fonts work properly and other don't, the ability to configure a set of fonts for different blocks of Unicode characters, which will probably be required to properly handle a mix of latin, asian (CJK) and technical characters (Math, powerline, nerd font,...), would make it possible to simply specify a font that works for the block and line characters while using other fonts for everything else, so no other fallback required. See my suggestion at https://github.com/microsoft/terminal/issues/455#issuecomment-621735991

j4james commented 4 years ago

I guess it started as a way to do intermediate colors and gradients

Did it though? I haven't seen any evidence to suggest that was the only intended usage. People use patterned fills in graphing all the time, both with and without the availability of RGB colors. It's just as reasonable to suppose that these patterned characters were intended to be used as actual patterns. Emulating gradients is just one of the things you could do with those patterns.

And note that the comments on U+2592 in the Unicode standard actually includes the description "speckles fill, dotted fill". The reference glyphs, while not prescriptive, are clearly rendered with patterned fills.

Even ignoring all of the above, I've yet to hear anyone explain how they would render U+1FB90 with an opacity fill. It's the exact same shade as U+2592, only the pixels are "inverted". How do we achieve that with a solid block?

simply specify a font that works for the block and line characters while using other fonts for everything else, so no other fallback required.

In theory I like this idea, but that assumes there are fonts capable of rendering all of these patterns and things like diagonals (e.g. see #6161) while still lining up perfectly with different font sizes and DPI scaling. However, if it could be achieved with a well-designed font, that would be preferable I think.

egmontkob commented 4 years ago

I've yet to hear anyone explain how they would render U+1FB90 with an opacity fill. It's the exact same shade as U+2592, only the pixels are "inverted". How do we achieve that with a solid block?

In VTE these two are manually rendered as exactly the same solid blocks.

I'm not saying it's great, nor that it's my preferred approach, nor that this is what WT should do. But these are not the first pair of homoglyphs, so I don't think this approach is inherently wrong either.

mdtauk commented 4 years ago

Even if some fonts work properly and other don't, the ability to configure a set of fonts for different blocks of Unicode characters, which will probably be required to properly handle a mix of latin, asian (CJK) and technical characters (Math, powerline, nerd font,...), would make it possible to simply specify a font that works for the block and line characters while using other fonts for everything else, so no other fallback required.

Sure you could include a font specific for the block drawing elements, but that leaves the same problem when elements like Linespacing is added. Which would break any font's approach to block drawing.

As linespacing is increased, Terminal drawn block elements, could still be flush so as not to break UIs

ionut-botizan commented 4 years ago

I guess it started as a way to do intermediate colors and gradients

Did it though?

Yes, it did.

A number of existing national and vendors standards, including IBM PC Code Page 437, contain a number of characters intended to enable a simple kind of character cell graphic by filling some fraction of each cell, or by filling each character cell by some degree of shading. [...] Also included are a series of shades based on one-quarter shadings.

^ _Page 92 in "The Unicode Standard, Version 1", published in 1991 (page 19 in the online PDF)._


The only reason they appear as they do are technological limitations of the past, where the number of colors you could use was limited so font designers had to resort to even older artistic techniques (some of them centuries old) to emulate shadows, such as:

image


And note that the comments on U+2592 in the Unicode standard actually includes the description "speckles fill, dotted fill".

Funny that you mention that, because the very same comments are very clear about the names of the character (they are spelled in caps - very hard to miss) and the percentage of shading each represents:


Lastly, since you're so fond of the 1FB90 character, how would you see it rendered? Because, simply inverting the pixels obviously wouldn't work and here are a couple examples why:

So, how would you define that character in such a way that it would convey the same idea across a huge variety of fonts?

P.S.: I am in favor of having both implementations because, even though I mostly prefer the solid block with alpha mixing approach, there are exceptions where I might use the other such as if I were to use a font like Source Code Pro which has a beautiful halftone implementation of these characters.

P.S. 2: Your suggestion to use a solid block with a custom color is not valid as, in the vast majority of the cases, the user does not control the output of 3rd party programs/scripts.

j4james commented 4 years ago

A number of existing national and vendors standards, including IBM PC Code Page 437, contain a number of characters intended to enable a simple kind of character cell graphic by filling some fraction of each cell, or by filling each character cell by some degree of shading.

I'm not sure how you're reading that to mean the characters were intended to be used for gradients? The intent was "a simple kind of character cell graphic". The method that was used to achieve that was "by filling each character cell by some degree of shading". If you want to know what "some degree of shading" means in that context, you simply have to look at the glyphs as they were rendered at the time, which funnily enough is exactly what the reference glyphs in the Unicode standard look like.

Lastly, since you're so fond of the 1FB90 character, how would you see it rendered? Because, simply inverting the pixels obviously wouldn't work and here are a couple examples why:

If it doesn't work with a particular font, that's simply because the font is incorrect. By definition, if the pattern the font was rendering produced a 50% shade, then the inverse of that pattern would still produce a 50% shade.

If you want an example of how those characters could be rendered, again you can simply look at the reference glyphs in the Unicode standard.

image

Side by side, those two pattern produce the effect of subtle dividing line where they meet, I'm not saying it's a huge loss if we couldn't render them differently. The point I was making was that the standard clearly intended them to be different, and a solid block can't possibly achieve that.

But as I've said before, if that's the best we can do, then that's fine. I just don't think it's ideal.

mdtauk commented 4 years ago

So instead of using a pattern to simulate a shade of the glyph's colour - just change the opacity of the glyph/cell itself

image

reli-msft commented 4 years ago

Could we just measure the line height from the box-drawing characters? An idea may be rasterize the U+2588 FULL BLOCK character and use the pixel rows that have pure black pixels to determine the height of cells. Using this way can be used to handle fonts that is either hinted or unhinted.

oising commented 4 years ago

Reminder that we already have a good alignment/render test file in the repo:

https://github.com/microsoft/terminal/blob/master/doc/reference/UTF8-torture-test.txt

image

(font: Fira Code)

tycho commented 4 years ago

So instead of using a pattern to simulate a shade of the glyph's colour - just change the opacity of the glyph/cell itself

image

I really like the third row in this image. It matches the behavior of MinTTY:

mintty_dbZEXIglNI

rbeesley commented 4 years ago

I'm glad I found this issue. I've been trying to track down how to describe the problem I'm seeing and I think this is it.

image

At first I had characters I was using for box art to disappear on only some rows, so I tried to write a script to isolate that. I thought it was maybe related to the ANSI ESC sequence I was using, so I experimented with that, but the test script was failing in different ways. I thought maybe the problem was the font, so I changed the font in conhost.exe by opening cmd.exe, and it worked there.

In summary, Lucida Console on both conhost.exe and Windows Terminal works. Cascadia Code on conhost.exe works. Cascadia Code on Windows Terminal sometimes doesn't draw, sometimes. I actually had for awhile where Medium Shade \u2592 was sometimes drawing on consecutive lines, would not draw for one, and then would resume drawing on another. Trying to isolate that specific case in another script, it stopped reproducing and instead only Dark Shade \u2593 was drawing.

Frustrating to chase down.

rbeesley commented 4 years ago

Side by side, those two pattern produce the effect of subtle dividing line where they meet, I'm not saying it's a huge loss if we couldn't render them differently. The point I was making was that the standard clearly intended them to be different, and a solid block can't possibly achieve that.

I don't think you should count out that there could still be a seam created when certain characters are rendered next to each other. It'd take a little work to achieve the right result, but at least for horizontal alignment couldn't this be handled with a ligature? W3C is looking at how to handle vertical text alignment in Unicode, so presumably there will also be a need for vertical ligatures.

Qix- commented 3 years ago

For the box drawing characters, I see this too.

This is what it's supposed to look like (captured from Asciiflow):

image

but depending on the zoom level, either the horizontal lines are missing, the vertical lines or missing, or the horizontal lines have noticeable gaps between them.

image

image

image

The font has to be considerably larger (too large for me to comfortably work with) in order to see all of them properly, and even then the horizontal lines have gaps.

image

rbeesley commented 3 years ago

Strangely I stumbled into this defect again. Earlier in this thread I mentioned that Windows Terminal was sometimes not rendering glyphs, but I now have additional details. New information for repro, which might not matter when this defect is addressed, I'm seeing the missing glyphs at specific font sizes; 1, 2, 3, and 15. The glyphs have rendering problems at other font sizes as well, but it seems like the shade boxes aren't shown at 15 and might have been a condition when I ran into this 9 months ago.

felipecrs commented 2 years ago

I would report the following:

image

But I'm a little confused whether it's covered by this issue already or not. Any clue?

DHowett commented 2 years ago

@felipecrs what you're reporting seems to be another case of #6864, the cause of which is explained in https://github.com/microsoft/terminal/issues/6864#issuecomment-659544490. :)

he3als commented 2 years ago

Are there any ways to fix this issue at the moment? I am using the default font.

jaminthorns commented 1 year ago

I'd really love to see this implemented as it can provide a much nicer TUI experience. If this ends up happening, it'd be great if the Powerline symbols were implemented as well (don't forget the slants/triangles!).

Here's some further reading for anyone interested in how some other terminals handle rendering of box drawing characters:

ShelpAm commented 10 months ago

So, if there is any solution to the problem? There are annoying gaps between characters.

Mystic8b commented 8 months ago

Well, #16664 was closed, so I'm writing here. I and tens of thousands of other people use zsh + p10k. And AtlasEngine breaks the prompt in p10k by cutting off the bottom pixel or something like that. In the last release you enabled Atlas by default, which means you are sure there are no problems, but this is not the case! This is a huge problem. Pay attention to this. Thank you!

Old engine: image

New engine: image

And no, it's not a font problem, I've tried every variation of Nerd Fonts. I asked the developer of p10k, he also said that it was a terminal problem.


zadjii-msft commented 8 months ago

To loop back on this: I've updated the OP with our plan-of-record. Adding a setting to force Terminal to draw pixel-perfect glyphs seems like the right plan. It'll be a setting, so users can always feel free to opt-out if they want the glyph from their font instead.

Adding the setting itself is trivial. Figuring out how to get the renderer to draw each of those shapes: that's a little more work. Hence why we've tried to group them by priority.

We'd probably appreciate help here, if someone's willing to figure out the glyph drawing šŸ˜‰

lhecker commented 8 months ago

Box drawing and block element glyphs are done: image

Powerline glyphs are much more difficult to do, because a user's font may not have powerline glyphs in the first place and so there's nothing to MapCharacters to. This made me realize that I need to do my own MapCharacters in addition to what DWrite is doing and that will take some time because it requires additional work on the text renderer - work that isn't trivial unfortunately since DWrite is a little unwieldy.