Move the common render settings into a shared class#12127
Conversation
| SetColorAliasIndex(ColorAlias::DefaultForeground, TextColor::DARK_WHITE); | ||
| SetColorAliasIndex(ColorAlias::DefaultBackground, TextColor::DARK_BLACK); |
There was a problem hiding this comment.
color aliases are clever as. Thanks
| // Now load complex properties | ||
| // Some properties shouldn't be filled by the registry if a copy already exists from the process start information. | ||
| DWORD dwValue; | ||
| const auto loadDWORD = [=](const auto valueName) { |
There was a problem hiding this comment.
Well I love it. But I do wonder if we should just be making it into a first-class function or template citizen instead of just a lambda. It sure cleans up the below calls.
There was a problem hiding this comment.
Yeah, I did consider this, but pulling it out into a first-class function means you need to pass additional parameters that you get for free with the lambda, so it's not quite as clean. I do think perhaps there's potential for a nicer registry encapsulation class here that could clean up more of the code, but I didn't want to get too sidetracked in this PR, and the lambda at least doesn't make things a whole lot worse.
There was a problem hiding this comment.
I almost broke down and worked on better-encapsulating the registry code some time a few years back when I first saw this file . . . so yeah, I get that for sure :D
| if (const auto codePage = loadDWORD(CONSOLE_REGISTRY_CODEPAGE)) | ||
| { | ||
| _pSettings->SetCodePage(dwValue); | ||
| _pSettings->SetCodePage(codePage.value()); |
There was a problem hiding this comment.
I was going to say "what about the exception" but I guess the if has got you covered on that as it will test false. Nice.
| { _RegPropertyType::Boolean, CONSOLE_REGISTRY_TERMINALSCROLLING, SET_FIELD_AND_SIZE(_TerminalScrolling) }, | ||
| { _RegPropertyType::Dword, CONSOLE_REGISTRY_USEDX, SET_FIELD_AND_SIZE(_fUseDx) }, | ||
| { _RegPropertyType::Boolean, CONSOLE_REGISTRY_COPYCOLOR, SET_FIELD_AND_SIZE(_fCopyColor) }, | ||
| { _RegPropertyType::Dword, CONSOLE_REGISTRY_DEFAULTFOREGROUND, SET_FIELD_AND_SIZE(_colorTable[TextColor::DEFAULT_FOREGROUND]) }, |
There was a problem hiding this comment.
Perhaps leave a comment that some of these have disappeared as the model has changed as I think this table was a semi-definitive list of what we were messing with in terms of values under HKCU\Console
There was a problem hiding this comment.
OK, I've added a comment at the bottom of the list noting all the settings that are not included. There was already also a comment at the top noting that the list is incomplete.
lhecker
left a comment
There was a problem hiding this comment.
I have slightly mixed feelings about this PR. I can't quite put my finger on it, but I feel like there's some way to make our entire color handling a lot simpler and involve less classes. We have quite a lot of code to represent colors and metadata don't we? 😅
However this PR seems like the absolutely right approach anyways because it simplifies and "unifies" a ton of code. Nice! I left some thoughts you can consider before we merge this later.
Yeah, I feel the same way. I know this is far from perfect but I'm hoping it's at least moving us in the right direction, and we'll still be able to improve things over time. I should add that my initial plan was to try add these properties directly to the renderer, so there wouldn't have been a need for another class, but that ended up being unworkable without essentially rewriting everything everywhere. So this was a bit of a compromise, which is not as neat as I would liked, but still achieved most of my goals. |
|
FYI, I've merged my local branch with main to resolve the conflicts, but there are some tests that are failing now, and I'm still trying to establish the cause. |
|
I think the merge is good. Test failures were the result of a previous commit. I've raised another issue for that (#12158). |
|
Hello @lhecker! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
| // color pair to the adjusted foreground for that color pair | ||
| void RenderSettings::MakeAdjustedColorArray() noexcept | ||
| { | ||
| // The color table has 16 colors, but the adjusted color table needs to be 18 |
There was a problem hiding this comment.
FWIW I believe that we now calculate this for everyone, even if the feature isn't being used -- that might have a cost in conhost that we don't want to take on, right?
There was a problem hiding this comment.
There was a problem hiding this comment.
I've tested this PR locally before approving it. I found no regressions. Binary size (without PGO) only increased ever so slightly (~500 Byte).
DHowett
left a comment
There was a problem hiding this comment.
(Post-merge review: I love it! I'm v. happy with this. Thank you!)
|
🎉 Handy links: |
Summary of the Pull Request
This PR moves the color table and related render settings, which are common to both conhost and Windows Terminal, into a shared class that can be accessed directly from the renderer. This avoids the overhead of having to look up these properties via the
IRenderDatainterface, which relies on inefficient virtual function calls.This also introduces the concept of color aliases, which determine the position in the color table that colors like the default foreground and background are stored. This allows the option of mapping them to one of the standard 16 colors, or to have their own separate table entries.
References
This is a continuation of the color table refactoring started in #11602 and #11784. The color alias functionality is a prerequisite for supporting a default bold color as proposed in #11939. The color aliases could also be a way for us to replace the PowerShell color quirk for #6807.
PR Checklist
Detailed Description of the Pull Request / Additional comments
In addition to the color table, this new
RenderSettingsclass manages the blinking state, the code for adjusting indistinguishable colors, and various boolean properties used in the color calculations. These boolean properties are now stored in atil::enumsetso they can all be managed through a singleSetRenderModeAPI, and easily extended with additional modes that we're likely to need in the future.In Windows Terminal we have an instance of
RenderSettingsstored in theTerminalclass, and in conhost it's stored in theSettingsclass. In both cases, a reference to this class is passed to theRendererconstructor, so it now has direct access to that data. The renderer can then pass that reference to the render engines where it's needed in theUpdateDrawingBrushesmethod.This means the renderer no longer needs the
IRenderDatainterface to access theGetAttributeColors,GetCursorColor, orIsScreenReversedmethods, so those have now been removed. We still need access toGetAttributeColorsin certain accessibility code, though, so I've kept that method in theIUIADatainterface, but the implementation just forwards to theRenderSettingsclass.The implementation of the
RenderSettings::GetAttributeColorsmethod is loosely based on the originalTerminalcode, only theCalculateRgbColorscall has now been incorporated directly into the code. This let us deduplicate some bits that were previously repeated in the section for adjusting indistinguishable colors. The last steps, where we calculate the alpha components, have now been split in to a separateGetAttributeColorsWithAlphamethod, since that's typically not needed.Validation Steps Performed
There were quite a lot changes needed in the unit tests, but they're mostly straightforward replacements of one method call with another.
In the
TextAttributeTests, where we were previously testing theCalculateRgbColorsmethod, we're now running those tests thoughRenderSettings::GetAttributeColors, which incorporates the same functionality. The only complication is when testing theIntenseIsBrightoption, that needs to be set with an additionalSetRenderModecall where previously it was just a parameter onCalculateRgbColors.In the
ScreenBufferTestsandTextBufferTests, calls toLookupAttributeColorshave again been replaced by theRenderSettings::GetAttributeColorsmethod, which serves the same purpose, and calls toIsScreenReversedhave been replaced with an appropriateGetRenderModecall. In theVtRendererTests, all the calls toUpdateDrawingBrushesnow just need to be passed a reference to aRenderSettingsinstance.