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

Add support for Underlined independent of LVB_UNDERSCORE #2915

Closed
1 task
zadjii-msft opened this issue Sep 26, 2019 · 6 comments · Fixed by #7148
Closed
1 task

Add support for Underlined independent of LVB_UNDERSCORE #2915

zadjii-msft opened this issue Sep 26, 2019 · 6 comments · Fixed by #7148
Labels
Area-VT Virtual Terminal sequence support Issue-Task It's a feature request, but it doesn't really need a major design. Product-Conhost For issues in the Console codebase Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release.
Milestone

Comments

@zadjii-msft
Copy link
Member

Discussed with @DHowett-MSFT, as a follow up of #2554.

We've been using LVB_UNDERSCORE for underlines in the console since Windows 10 was released. However, LVB_UNDERSCORE is more of a box-drawing feature, it draws the underline fully under the text.

We should more correctly have a separate Underline state, that draws the underline at the baseline of the text, not just under it.

In VT, underline is in a trinary state: [No Underline, Underlined, Doubly Underlined]. We should make sure to store this in the buffer appropriately.

Technically, we believe characters could have both Underlined and LVB_UNDERSCORE.

Open Questions:

  • should Underline be read from the API as LVB_UNDERSCORE? Currently it is, but I think that it shouldn't. If you round-trip the attributes, then that would pollute the state.
@zadjii-msft zadjii-msft added Product-Conhost For issues in the Console codebase Area-VT Virtual Terminal sequence support Issue-Task It's a feature request, but it doesn't really need a major design. labels Sep 26, 2019
@zadjii-msft zadjii-msft added this to the 21H1 milestone Sep 26, 2019
@ghost ghost added the Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting label Sep 26, 2019
@DHowett-MSFT DHowett-MSFT removed the Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting label Sep 26, 2019
zadjii-msft added a commit that referenced this issue Oct 4, 2019
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.

We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.

Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.

## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.

## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated


<hr>

* store text with extended attributes too

* Plumb attributes through all the renderers

* parse extended attrs, though we're not renderering them right

* Render these states correctly

* Add a very extensive test

* Cleanup for PR

* a block of PR feedback

* add 512 test cases

* Fix the build

* Fix @carlos-zamora's suggestions

* @miniksa's PR feedback
DHowett-MSFT pushed a commit that referenced this issue Oct 17, 2019
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.

We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.

Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.

## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.

## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated

<hr>

* store text with extended attributes too

* Plumb attributes through all the renderers

* parse extended attrs, though we're not renderering them right

* Render these states correctly

* Add a very extensive test

* Cleanup for PR

* a block of PR feedback

* add 512 test cases

* Fix the build

* Fix @carlos-zamora's suggestions

* @miniksa's PR feedback

(cherry picked from commit dec5c11)
ghost pushed a commit that referenced this issue Jul 30, 2020
This is a refactoring of the grid line renderers, adjusting the line
widths to scale with the font size, and optimising the implementation to
cut down on the number of draw calls. It also extends the supported grid
line types to include true underlines and strike-through lines in the
style of the active font.

The main gist of the optimisation was to render the horizontal lines
with a single draw call, instead of a loop with lots of little strokes
joined together. In the case of the vertical lines, which still needed
to be handled in a loop, I've tried to move the majority of static
calculations outside the loop, so there is bit of optimisation there
too.

At the same time this code was updated to support a variable stroke
width for the lines, instead of having them hardcoded to 1 pixel. The
width is now calculated as a fraction of the font size (0.025 "em"),
which is still going to be 1 pixel wide in most typical usage, but will
scale up appropriately if you zoom in far enough.

And in preparation for supporting the SGR strike-through attribute, and
true underlines, I've extended the grid line renders with options for
handling those line types as well. The offset and thickness of the lines
is obtained from the font metrics (rounded to a pixel width, with a
minimum of one pixel), so they match the style of the font.

VALIDATION

For now we're still only rendering grid lines, and only the top and
bottom lines in the case of the DirectX renderer in Windows Terminal. So
to test, I hacked in some code to force the renderer to use all the
different options, confirming that they were working in both the GDI and
DirectX renderers.

I've tested the output with a number of different fonts, comparing it
with the same text rendered in WordPad. For the most part they match
exactly, but there can be slight differences when we adjust the font
size for grid alignment. And in the case of the GDI renderer, where
we're working with pixel heights rather than points, it's difficult to
match the sizes exactly.

This is a first step towards supporting the strike-through attribute
(#6205) and true underlines (#2915).

Closes #6911
@DHowett
Copy link
Member

DHowett commented Aug 1, 2020

The diff to do this directly is pretty minimal (and it looks nicer now that @j4james has done #7107).

Should underline read back as LVB_UNDERSCORE

Nope, for the exact reason you mentioned.

Trinary

There was an open discussion about how underline types stack in #2916.

James asserts, about double/single underline being a trinary state,

Yes and no. There aren't many terminals that support double-underline for real (most treat it as a synonym for single underline) so there's no obvious consensus. In VTE it's a trinary state, where the last choice (single or double) takes precedence. However in XTerm, underline and double-underline are actually separate attributes, and double-underline takes precedence when both are set, regardless of the order they were applied.

I'm not sure it matters that much, but I'd probably be inclined to follow the XTerm approach.

I'm inclined to agree with this.

If we don't have to worry about making underlined/doubly underlined trinary, we can close 2915 with 2 files changed, 7 insertions(+), 4 deletions(-).

@DHowett
Copy link
Member

DHowett commented Aug 1, 2020

Before

image

After

image

@j4james
Copy link
Collaborator

j4james commented Aug 1, 2020

@DHowett I was just putting together a PR for this, but it looks like you've done it already. Should I leave this with you?

As for the doubly underlined attribute, I was going to suggest we simply render that as a single underline for now, since that's what many some other terminals seem to do. We should still parse and store it separately, though, so we can pass on the correct SGR value to the conpty pipe for clients that do actually render it differently.

Edit: I've just done some retesting, and there aren't as many terminals treating single and double underlines the same as I thought. It's not always obvious that a double underline is being used (at least on a hidpi screen) until you zoom in. I still think it might be a reasonable temporary solution, though.

@DHowett
Copy link
Member

DHowett commented Aug 1, 2020

I wasn’t going to do the Doubly Underlined bits, so I imagine you’re farther along than I am :) I’ll leave it to you

Agree on equating doubly with singly during render for now

Thanks!

@ghost ghost added the In-PR This issue has a related PR label Aug 1, 2020
@j4james
Copy link
Collaborator

j4james commented Aug 1, 2020

OK so I started with rendering the doubly underlined attribute as a simple alias for the single underline, but it occurred to me that it might not be that difficult to add a proper renderer for it with the framework we now have in place. And you can see below some examples of what I've got so far.

I'm still tweaking the look, and there are some issues with the conpty pass-through that I'm not completely happy with, so in the meantime I thought it would be best if I just submit a PR with the basic underline functionality to start with. Then we can continue the doubly-underline discussion in #2916 and add a separate PR for that later.

image

@ghost ghost closed this as completed in #7148 Aug 3, 2020
@ghost ghost added Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release. and removed In-PR This issue has a related PR labels Aug 3, 2020
ghost pushed a commit that referenced this issue Aug 3, 2020
This PR updates the rendering of the _underlined_ graphic rendition
attribute, using the style specified in the active font, instead of just
reusing the grid line at the bottom of the character cell.

* Support for drawing the correct underline effect in the grid line
  renderer was added in #7107.

There was already an `ExtendedAttributes` flag defined for the
underlined state, but I needed to update the `SetUnderlined` and
`IsUnderlined` methods in the `TextAttribute`  class to use that flag
now in place of the legacy `LVB_UNDERSCORE` attribute. This enables
underlines set via a VT sequence to be tracked separately from
`LVB_UNDERSCORE` grid lines set via the console API.

I then needed to update the `Renderer::s_GetGridlines` method to
activate the `GridLines::Underline` style when the `Underlined`
attribute was set. The `GridLines::Bottom` style is still triggered by
the `LVB_UNDERSCORE` attribute to produce the bottom grid line effect.

Validation
----------

Because this is a change from the existing behaviour, certain unit tests
that were expecting the `LVB_UNDERSCORE` to be toggled by `SGR 4` and
`SGR 24` have now had to be updated to check the `Underlined` flag
instead.

There were also some UI Automation tests that were checking for `SGR 4`
mapping to `LVB_UNDERSCORE` attribute, which I've now substituted with a
test of the `SGR 53` overline attribute mapping to
`LVB_GRID_HORIZONTAL`. These tests only work with legacy attributes, so
they can't access the extended underline state, and I thought a
replacement test that covered similar ground would be better than
dropping the tests altogether.

As far as the visual rendering is concerned, I've manually confirmed
that the VT underline sequences now draw the underline in the correct
position and style, while grid lines output via the console API are
still displayed in their original form.

Closes #2915
@ghost
Copy link

ghost commented Aug 26, 2020

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

Handy links:

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-VT Virtual Terminal sequence support Issue-Task It's a feature request, but it doesn't really need a major design. Product-Conhost For issues in the Console codebase Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants