render: defer conversion of TextColor into COLORREF until actual rendering time (avoid ConPTY narrowing bugs) #3744

Open
opened 2026-01-30 23:28:59 +00:00 by claunia · 0 comments
Owner

Originally created by @DHowett-MSFT on GitHub (Sep 5, 2019).

Originally assigned to: @j4james on GitHub.

Right now, every time Renderer needs to switch the brush colors, it does the following:

  1. get the TextColor from the attribute run
  2. get the RGB value of the color from the color table
  3. pass that to Engine::UpdateDrawingBrushes

Step 2 is lossy, and is the source of a class of bugs I'll call "ConPTY narrowing" bugs. In addition, there's a step where VtEngine needs to know the color table to do a translation from RGB back into indexed color.

"narrowing" bugs

application output conpty sends why
\e[38;2;22;198;12m \e[92m RGB(22, 198, 12) matches color index 10 in Campbell
\e[38;5;127m \e[38;2;175;0;175m the xterm-256color color palette gets translated into RGB because Campbell only covers 0-16
\e[38;2;12;12;12m \e[30m RGB(12, 12, 12) matches index 0 in Campbell and index 0 is the default color (#293)

If Renderer passed the TextColor directly to the Engine, Xterm256Engine could pass through all indexed colors unchanged, and XtermEngine and WinTelnetEngine could flatten to the 16-color space.

  • #3076 is caused by us doing early unpacking of colors and boldness; deferring until later will yield an improvement in preservation of underline status.
Originally created by @DHowett-MSFT on GitHub (Sep 5, 2019). Originally assigned to: @j4james on GitHub. Right now, every time Renderer needs to switch the brush colors, it does the following: 1. get the `TextColor` from the attribute run 1. get the RGB value of the color from the color table 1. pass that to `Engine::UpdateDrawingBrushes` Step 2 is lossy, and is the source of a class of bugs I'll call "ConPTY narrowing" bugs. In addition, there's a step where `VtEngine` needs to _know the color table_ to do a translation from RGB back into indexed color. **"narrowing" bugs** |application output|conpty sends|why| |-|-|-| |`\e[38;2;22;198;12m`|`\e[92m`|RGB(22, 198, 12) matches color index 10 in Campbell| |`\e[38;5;127m`|`\e[38;2;175;0;175m`|the xterm-256color color palette gets translated into RGB because Campbell only covers 0-16| |`\e[38;2;12;12;12m`|`\e[30m`|RGB(12, 12, 12) matches index 0 in Campbell _and index 0 is the default color_ (#293)| If Renderer passed the TextColor directly to the Engine, Xterm256Engine could pass through all indexed colors unchanged, and XtermEngine and WinTelnetEngine could flatten to the 16-color space. * [x] #3076 is caused by us doing early unpacking of colors and boldness; deferring until later will yield an improvement in preservation of underline status.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#3744