-
Notifications
You must be signed in to change notification settings - Fork 8.4k
/
Copy pathRenderSettings.cpp
289 lines (257 loc) · 10.8 KB
/
RenderSettings.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "../inc/RenderSettings.hpp"
#include "../inc/IRenderTarget.hpp"
#include "../../types/inc/ColorFix.hpp"
#include "../../types/inc/colorTable.hpp"
using namespace Microsoft::Console::Render;
using Microsoft::Console::Utils::InitializeColorTable;
static constexpr size_t AdjustedFgIndex{ 16 };
static constexpr size_t AdjustedBgIndex{ 17 };
RenderSettings::RenderSettings() noexcept
{
InitializeColorTable(_colorTable);
SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, INVALID_COLOR);
SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, INVALID_COLOR);
SetColorTableEntry(TextColor::CURSOR_COLOR, INVALID_COLOR);
SetColorAliasIndex(ColorAlias::DefaultForeground, TextColor::DARK_WHITE);
SetColorAliasIndex(ColorAlias::DefaultBackground, TextColor::DARK_BLACK);
}
// Routine Description:
// - Updates the specified render mode.
// Arguments:
// - mode - The render mode to change.
// - enabled - Set to true to enable the mode, false to disable it.
void RenderSettings::SetRenderMode(const Mode mode, const bool enabled) noexcept
{
_renderMode.set(mode, enabled);
// If blinking is disabled, make sure blinking content is not faint.
if (mode == Mode::BlinkAllowed && !enabled)
{
_blinkShouldBeFaint = false;
}
}
// Routine Description:
// - Retrieves the specified render mode.
// Arguments:
// - mode - The render mode to query.
// Return Value:
// - True if the mode is enabled. False if disabled.
bool RenderSettings::GetRenderMode(const Mode mode) const noexcept
{
return _renderMode.test(mode);
}
// Routine Description:
// - Returns a reference to the active color table array.
const std::array<COLORREF, TextColor::TABLE_SIZE>& RenderSettings::GetColorTable() const noexcept
{
return _colorTable;
}
// Routine Description:
// - Resets the first 16 color table entries with default values.
void RenderSettings::ResetColorTable() noexcept
{
InitializeColorTable({ _colorTable.data(), 16 });
}
// Routine Description:
// - Creates the adjusted color array, which contains the possible foreground colors,
// adjusted for perceivability
// - The adjusted color array is 2-d, and effectively maps a background and foreground
// 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
// to include the default background and default foreground colors
std::array<COLORREF, 18> colorTableWithDefaults;
std::copy_n(std::begin(_colorTable), 16, std::begin(colorTableWithDefaults));
colorTableWithDefaults[AdjustedFgIndex] = GetColorAlias(ColorAlias::DefaultForeground);
colorTableWithDefaults[AdjustedBgIndex] = GetColorAlias(ColorAlias::DefaultBackground);
for (auto fgIndex = 0; fgIndex < 18; ++fgIndex)
{
const auto fg = til::at(colorTableWithDefaults, fgIndex);
for (auto bgIndex = 0; bgIndex < 18; ++bgIndex)
{
if (fgIndex == bgIndex)
{
_adjustedForegroundColors[bgIndex][fgIndex] = fg;
}
else
{
const auto bg = til::at(colorTableWithDefaults, bgIndex);
_adjustedForegroundColors[bgIndex][fgIndex] = ColorFix::GetPerceivableColor(fg, bg);
}
}
}
}
// Routine Description:
// - Updates the given index in the color table to a new value.
// Arguments:
// - tableIndex - The index of the color to update.
// - color - The new COLORREF to use as that color table value.
void RenderSettings::SetColorTableEntry(const size_t tableIndex, const COLORREF color)
{
_colorTable.at(tableIndex) = color;
}
// Routine Description:
// - Retrieves the value in the color table at the specified index.
// Arguments:
// - tableIndex - The index of the color to retrieve.
// Return Value:
// - The COLORREF value for the color at that index in the table.
COLORREF RenderSettings::GetColorTableEntry(const size_t tableIndex) const
{
return _colorTable.at(tableIndex);
}
// Routine Description:
// - Sets the position in the color table for the given color alias and updates the color.
// Arguments:
// - alias - The color alias to update.
// - tableIndex - The new position of the alias in the color table.
// - color - The new COLORREF to assign to that alias.
void RenderSettings::SetColorAlias(const ColorAlias alias, const size_t tableIndex, const COLORREF color)
{
SetColorAliasIndex(alias, tableIndex);
SetColorTableEntry(tableIndex, color);
}
// Routine Description:
// - Retrieves the value in the color table of the given color alias.
// Arguments:
// - alias - The color alias to retrieve.
// Return Value:
// - The COLORREF value of the alias.
COLORREF RenderSettings::GetColorAlias(const ColorAlias alias) const
{
return GetColorTableEntry(GetColorAliasIndex(alias));
}
// Routine Description:
// - Sets the position in the color table for the given color alias.
// Arguments:
// - alias - The color alias to update.
// - tableIndex - The new position of the alias in the color table.
void RenderSettings::SetColorAliasIndex(const ColorAlias alias, const size_t tableIndex) noexcept
{
gsl::at(_colorAliasIndices, static_cast<size_t>(alias)) = tableIndex;
}
// Routine Description:
// - Retrieves the position in the color table of the given color alias.
// Arguments:
// - alias - The color alias to retrieve.
// Return Value:
// - The position in the color table where the color is stored.
size_t RenderSettings::GetColorAliasIndex(const ColorAlias alias) const noexcept
{
return gsl::at(_colorAliasIndices, static_cast<size_t>(alias));
}
// Routine Description:
// - Calculates the RGB colors of a given text attribute, using the current
// color table configuration and active render settings.
// Arguments:
// - attr - The TextAttribute to retrieve the colors for.
// Return Value:
// - The color values of the attribute's foreground and background.
std::pair<COLORREF, COLORREF> RenderSettings::GetAttributeColors(const TextAttribute& attr) const noexcept
{
_blinkIsInUse = _blinkIsInUse || attr.IsBlinking();
const auto fgTextColor = attr.GetForeground();
const auto bgTextColor = attr.GetBackground();
const auto defaultFgIndex = GetColorAliasIndex(ColorAlias::DefaultForeground);
const auto defaultBgIndex = GetColorAliasIndex(ColorAlias::DefaultBackground);
const auto brightenFg = attr.IsBold() && GetRenderMode(Mode::IntenseIsBright);
const auto dimFg = attr.IsFaint() || (_blinkShouldBeFaint && attr.IsBlinking());
const auto swapFgAndBg = attr.IsReverseVideo() ^ GetRenderMode(Mode::ScreenReversed);
// We want to nudge the foreground color to make it more perceivable only for the
// default color pairs within the color table
if (GetRenderMode(Mode::DistinguishableColors) &&
!dimFg &&
(fgTextColor.IsDefault() || fgTextColor.IsLegacy()) &&
(bgTextColor.IsDefault() || bgTextColor.IsLegacy()))
{
const auto bgIndex = bgTextColor.IsDefault() ? AdjustedBgIndex : bgTextColor.GetIndex();
auto fgIndex = fgTextColor.IsDefault() ? AdjustedFgIndex : fgTextColor.GetIndex();
if (fgTextColor.IsIndex16() && (fgIndex < 8) && brightenFg)
{
// There is a special case for bold here - we need to get the bright version of the foreground color
fgIndex += 8;
}
if (swapFgAndBg)
{
const auto fg = _adjustedForegroundColors[fgIndex][bgIndex];
const auto bg = fgTextColor.GetColor(_colorTable, defaultFgIndex);
return { fg, bg };
}
else
{
const auto fg = _adjustedForegroundColors[bgIndex][fgIndex];
const auto bg = bgTextColor.GetColor(_colorTable, defaultBgIndex);
return { fg, bg };
}
}
else
{
auto fg = fgTextColor.GetColor(_colorTable, defaultFgIndex, brightenFg);
auto bg = bgTextColor.GetColor(_colorTable, defaultBgIndex);
if (dimFg)
{
fg = (fg >> 1) & 0x7F7F7F; // Divide foreground color components by two.
}
if (swapFgAndBg)
{
std::swap(fg, bg);
}
if (attr.IsInvisible())
{
fg = bg;
}
return { fg, bg };
}
}
// Routine Description:
// - Calculates the RGBA colors of a given text attribute, using the current
// color table configuration and active render settings. This differs from
// GetAttributeColors in that it also sets the alpha color components.
// Arguments:
// - attr - The TextAttribute to retrieve the colors for.
// Return Value:
// - The color values of the attribute's foreground and background.
std::pair<COLORREF, COLORREF> RenderSettings::GetAttributeColorsWithAlpha(const TextAttribute& attr) const noexcept
{
auto [fg, bg] = GetAttributeColors(attr);
fg |= 0xff000000;
// We only care about alpha for the default BG (which enables acrylic)
// If the bg isn't the default bg color, or reverse video is enabled, make it fully opaque.
if (!attr.BackgroundIsDefault() || (attr.IsReverseVideo() ^ GetRenderMode(Mode::ScreenReversed)) || attr.IsInvisible())
{
bg |= 0xff000000;
}
return { fg, bg };
}
// Routine Description:
// - Increments the position in the blink cycle, toggling the blink rendition
// state on every second call, potentially triggering a redraw of the given
// render target if there are blinking cells currently in view.
// Arguments:
// - renderTarget: the render target that will be redrawn.
void RenderSettings::ToggleBlinkRendition(IRenderTarget& renderTarget) noexcept
try
{
if (GetRenderMode(Mode::BlinkAllowed))
{
// This method is called with the frequency of the cursor blink rate,
// but we only want our cells to blink at half that frequency. We thus
// have a blink cycle that loops through four phases...
_blinkCycle = (_blinkCycle + 1) % 4;
// ... and two of those four render the blink attributes as faint.
_blinkShouldBeFaint = _blinkCycle >= 2;
// Every two cycles (when the state changes), we need to trigger a
// redraw, but only if there are actually blink attributes in use.
if (_blinkIsInUse && _blinkCycle % 2 == 0)
{
// We reset the _blinkIsInUse flag before redrawing, so we can
// get a fresh assessment of the current blink attribute usage.
_blinkIsInUse = false;
renderTarget.TriggerRedrawAll();
}
}
}
CATCH_LOG()