terminal/src
James Holderness ccea66710c
Improve the legacy color conversions (#6358)
This PR provides a faster algorithm for converting 8-bit and 24-bit
colors into the 4-bit legacy values that are required by the Win32
console APIs. It also fixes areas of the code that were incorrectly
using a simple 16-color conversion that didn't handle 8-bit and 24-bit
values.

The faster conversion algorithm should be an improvement for issues #783
and #3950.

One of the main points of this PR was to fix the
`ReadConsoleOutputAttribute` API, which was using a simplified legacy
color conversion (the original `TextAttribute:GetLegacyAttributes`
method), which could only handle values from the 16-color table. RGB
values, and colors from the 256-color table, would be mapped to
completely nonsensical values. This API has now been updated to use the
more correct `Settings::GenerateLegacyAttributes` method.

But there were also a couple of other places in the code that were using
`GetLegacyAttributes` when they really had no reason to be working with
legacy attributes at all. This could result in colors being downgraded
to 4-bit values (often badly, as explained above), when the code was
already perfectly capable of displaying the full 24-bits.

This included the fill colors in the IME composer (in `ConsoleImeInfo`),
and the construction of the highlighting colors in the color
search/selection handler (`Selection::_HandleColorSelection`). I also
got rid of some legacy attribute code in the `Popup` class, which was
originally intended to update colors below the popup when the settings
changed, but actually caused more problems than it solved.

The other major goal of this PR was to improve the performance of the
`GenerateLegacyAttributes` method, since the existing implementation
could be quite slow when dealing with RGB values.

The simple cases are handled much the same as they were before. For an
`IsDefault` color, we get the default index from the
`Settings::_wFillAttribute` field. For an `IsIndex16` color, the index
can just be returned as is.

For an `IsRgb` color, the RGB components are compressed down to 8 bits
(3 red, 3 green, 2 blue), simply by dropping the least significant bits.
This 8-bit value is then used to lookup a representative 16-color value
from a hard-coded table. An `IsIndex256` color is also converted with a
lookup table, just using the existing 8-bit index.

The RGB mapping table was calculated by taking each compressed 8-bit
color, and picking a entry from the _Campbell_ palette that best
approximated that color. This was done by looking at a range of 24-bit
colors that mapped to the 8-bit value, finding the best _Campbell_ match
for each of them (using a [CIEDE2000] color difference calculation), and
then the most common match became the index that the 8-bit value would
map to.

The 256-color table was just a simpler version of this process. For each
entry in the table, we take the default RGB palette value, and find it's
closest match in the _Campbell_ palette.

Because these tables are hard-coded, the results won't adjust to changes
in the palette. However, they should still produce reasonable results
for palettes that follow the standard ANSI color range. And since
they're only a very loose approximation of the colors anyway, the exact
value really isn't that important.

That said, I have tried to make sure that if you take an RGB value for a
particular index in a reasonable color scheme, then the legacy color
mapped from that value should ideally match the same index. This will
never be possible for all color schemes, but I have tweaked a few of the
table entries to improve the results for some of the common schemes.

One other point worth making regarding the hard-coded tables: even if we
wanted to take the active palette into account, that wouldn't actually
be possible over a conpty connection, because we can't easily know what
color scheme the client application is using. At least this way the
results in conhost are guaranteed to be the same as in the Windows
Terminal.

[CIEDE2000]: https://en.wikipedia.org/wiki/Color_difference#CIEDE2000

## Validation Steps Performed

This code still passes the `TextAttributeTests` that check the basic
`GetLegacyAttribute` behaviour and verify the all legacy attributes
roundtrip correctly. However, some of the values in the `RgbColorTests`
had to be updated, since we're now intentionally returning different
values as a result of the changes to the RGB conversion algorithm.

I haven't added additional unit tests, but I have done a lot of manual
testing to see how well the new algorithm works with a range of colors
and a variety of different color schemes. It's not perfect in every
situation, but I think it works well enough for the purpose it serves.

I've also confirmed that the issues reported in #5940 and #6247 are now
fixed by these changes. 

Closes #5940 
Closes #6247
2020-06-08 19:05:06 +00:00
..
buffer Improve the legacy color conversions (#6358) 2020-06-08 19:05:06 +00:00
cascadia Update the tab's close button color to match the tab text color (#5789) 2020-06-05 19:12:28 +00:00
dep build: move oss required to build conhost out of dep/ (#5451) 2020-04-21 14:43:09 -07:00
host Improve the legacy color conversions (#6358) 2020-06-08 19:05:06 +00:00
inc Fix SGR indexed colors to distinguish Indexed256 color (and more) (#5834) 2020-05-27 22:34:45 +00:00
interactivity Make the conversion from WORD to TextAttribute explicit (#6380) 2020-06-05 23:20:32 +00:00
internal Merged PR 4271163: [Git2Git] Remove use of private theme APIs 2020-02-03 23:13:31 +00:00
propsheet Find icon from shortcut target if shortcut doesn't specify it (#6277) 2020-06-01 17:19:05 +00:00
propslib Find icon from shortcut target if shortcut doesn't specify it (#6277) 2020-06-01 17:19:05 +00:00
renderer Reflect OS build fixes on 7b489128ac back to inbox 2020-06-04 22:09:17 +00:00
server Implement a pair of shims for cls, Clear-Host in conpty mode (#5627) 2020-04-30 21:53:31 +00:00
terminal Make the conversion from WORD to TextAttribute explicit (#6380) 2020-06-05 23:20:32 +00:00
testlist inbox: Merge accumulated build fixes from RS_ONECORE_DEP_ACIOSS (#1002) 2019-05-24 12:28:30 -07:00
til Switch the Cascadia projects to til::color where it's easily possible to do so (#5847) 2020-05-15 22:43:00 +00:00
tools Add stdexcept header explicitly to u8u16test tool (#6226) 2020-05-27 12:06:35 -07:00
tsf ci: run spell check in CI, fix remaining issues (#4799) 2020-03-25 11:02:53 -07:00
types Allow the default profile to be specified by name (#5706) 2020-06-01 20:26:00 +00:00
winconpty Change NULL to nullptr since they are pointers (#4960) 2020-03-20 20:35:12 +00:00
common.build.post.props Add experimental retro terminal effects (#3468) 2019-12-12 13:44:01 +00:00
common.build.pre.props Enable Control Flow Guard in the common build props (#5453) 2020-04-22 11:30:13 -07:00
common.build.tests.props Move ConPTY to use til::bitmap (#5024) 2020-03-23 15:57:54 +00:00
ConsolePerf.regions.xml Tab to spaces (#578) 2019-05-13 18:06:36 -07:00
ConsolePerf.wprp Fix the WPR profile (#4007) 2019-12-17 17:14:15 -08:00
cppwinrt.build.post.props deps: upgrade CppWinRT to 2.0.200316.3, gsl to v2.1.0 (#4536) 2020-03-23 17:15:24 +00:00
cppwinrt.build.pre.props deps: upgrade CppWinRT to 2.0.200316.3, gsl to v2.1.0 (#4536) 2020-03-23 17:15:24 +00:00
dirs build: move oss required to build conhost out of dep/ (#5451) 2020-04-21 14:43:09 -07:00
project.inc build: move oss required to build conhost out of dep/ (#5451) 2020-04-21 14:43:09 -07:00
project.unittest.inc inbox: merge refactoring payload from FI 2019-06-11 17:01:26 -07:00
StaticAnalysis.ruleset Combined changes to make the build work again (see inside) (#2945) 2019-09-30 10:39:55 -07:00
unit.tests.x64.runsettings Initial release of the Windows Terminal source code 2019-05-02 15:29:04 -07:00
unit.tests.x86.runsettings Initial release of the Windows Terminal source code 2019-05-02 15:29:04 -07:00
wap-common.build.post.props Initial release of the Windows Terminal source code 2019-05-02 15:29:04 -07:00
wap-common.build.pre.props Initial release of the Windows Terminal source code 2019-05-02 15:29:04 -07:00