diff options
author | eadler <eadler@FreeBSD.org> | 2018-03-14 07:47:26 +0000 |
---|---|---|
committer | eadler <eadler@FreeBSD.org> | 2018-03-14 07:47:26 +0000 |
commit | 042f90b815d6199ba244903ff6f494a833805510 (patch) | |
tree | a34e718033687be4047ae409903b8683ffd72ee0 | |
parent | ddbcc58e74297ff195096bb244f98fa81db2e4fc (diff) | |
download | FreeBSD-src-042f90b815d6199ba244903ff6f494a833805510.zip FreeBSD-src-042f90b815d6199ba244903ff6f494a833805510.tar.gz |
MFC r315418,r315480,r316019:
Add teken_256to16() to convert xterm-256 256-color codes to xterm 16-color
codes. This will be used to fix bright colors.
Improve teken_256to8(). Use a lookup table instead of calculations. The
calculations were inaccurate since they used indexes into the xterm-256
6x6x6 color map instead of actual xterm colors. Also, change the threshold
for converting to a primary color: require the primary's component to be
2 or more higher instead of just higher. This affects about 1/5 of the
table entries and gives uniformly distributed colors in the 6x6x6 submap
except for greys (35 entries each for red, green, blue, cyan, brown and
magenta, instead of approx. only 15 each for the mixed colors). Even
more mixed colors would be better for matching colors, but uniform
distribution is best for preserving contrast.
For teken_256to16(), bright colors are just the ones with luminosity >=
60%. These are actually light colors (more white instead of more
saturation), while xterm bright colors except for white itself are
actually saturated with no white, so have luminosity only 50%.
These functions are layering violations. teken cannot do correct
conversions since it shouldn't know the color maps of anything except
xterm. Translating through xterm-16 colors loses information. This
gives bugs like xterm-256 near-brown -> xterm-16 red -> VGA red.
------------------------------------------------------------------------
r315480 | bde | 2017-03-18 11:13:54 +0000 (Sat, 18 Mar 2017) | 51 lines
Fix bright colors for syscons, and make them work for the first time
for vt. Restore syscons' rendering of background (bg) brightness as
foreground (fg) blinking and vice versa, and add rendering of blinking
as background brightness to vt.
Bright/saturated is conflated with light/white in the implementation
and in this description.
Bright colors were broken in all cases, but appeared to work in the
only case shown by "vidcontrol show". A boldness hack was applied
only in 1 layering-violation place (for some syscons sequences) where
it made some cases seem to work but was undone by clearing bold using
ANSI sequences, and more seriously was not undone when setting
ANSI/xterm dark colors so left them bright. Move this hack to drivers.
The boldness hack is only for fg brightness. Restore/add a similar hack
for bg brightness rendered as fg blinking and vice versa. This works
even better for vt, since vt changes the default text mode to give the
more useful bg brightness instead of fg blinking.
The brightness bit in colors was unnecessarily removed by the boldness
hack. In other cases, it was lost later by teken_256to8(). Use
teken_256to16() to not lose it. teken_256to8() was intended to be
used for bg colors to allow finer or bg-specific control for the more
difficult reduction to 8; however, since 16 bg colors actually work
on VGA except in syscons text mode and the conversion isn't subtle
enough to significantly in that mode, teken_256to8() is not used now.
There are still bugs, especially in vidcontrol, if bright/blinking
background colors are set.
Restore XOR logic for bold/bright fg in syscons (don't change OR
logic for vt). Remove broken ifdef on FG_UNDERLINE and its wrong
or missing bit and restore the correct hard-coded bit. FG_UNDERLINE
is only for mono mode which is not really supported.
Restore XOR logic for blinking/bright bg in syscons (in vt, add
OR logic and render as bright bg). Remove related broken ifdef
on BG_BLINKING and its missing bit and restore the correct
hard-coded bit. The same bit means blinking or bright bg depending
on the mode, and we want to ignore the difference everywhere.
Simplify conversions of attributes in syscons. Don't pretend to
support bold fonts. Don't support unusual encodings of brightness.
It is as good as possible to map 16 VGA colors to 16 xterm-16
colors. E.g., VGA brown -> xterm-16 Olive will be converted back
to VGA brown, so we don't need to convert to xterm-256 Brown. Teken
cons25 compatibility code already does the same, and duplicates some
small tables. This is mostly for the sc -> te direction. The other
direction uses teken_256to16() which is too generic.
------------------------------------------------------------------------
r316019 | bde | 2017-03-27 10:48:28 +0000 (Mon, 27 Mar 2017) | 30 lines
Oops, my fix for bright colors broke bright black some more (in cases
that used to work via the bold hack).
Fix the table entry for bright black. Fix spelling of plain black in
nearby table entries (use the macro for black everywhere everywhere).
Fix the currently-unused non-bright color table to not have bright
colors in entries 9-15.
Improve nearby comments. Start converting to the xterm terminology
and default rendering of "bright" instead of "light" for bright
colors.
Syscons wasn't affected by the bug since I optimized it a little by
converting colors 0-15 directly. This also fixes the layering of
the conversion for these colors.
Apply the same optimization to vt (actually the layer above it). This
also moves the conversion 1 closer to the correct layer for colors
0-15.
The optimization of just avoiding 2 calls to a trivial function is worth
about 10% for simple output to the virtual buffer with occasional
rendering. The optimization is so large because the 2 calls are done
on every character, so although there are too many other calls and
other instructions per character, there are only about 10 times as
many. Old versions of syscons were about 10 times faster for simple
output, by using a fast path with about 12 instructions per character.
Rendering to even slow hardware takes relatively little time provided
it is rarely actually done.
-rw-r--r-- | sys/dev/syscons/scterm-teken.c | 89 | ||||
-rw-r--r-- | sys/dev/vt/vt_core.c | 2 | ||||
-rw-r--r-- | sys/kern/subr_terminal.c | 29 | ||||
-rw-r--r-- | sys/teken/libteken/teken.3 | 22 | ||||
-rw-r--r-- | sys/teken/teken.c | 238 | ||||
-rw-r--r-- | sys/teken/teken.h | 2 | ||||
-rw-r--r-- | sys/teken/teken_subr_compat.h | 15 |
7 files changed, 275 insertions, 122 deletions
diff --git a/sys/dev/syscons/scterm-teken.c b/sys/dev/syscons/scterm-teken.c index 211cb4e..d5c357f 100644 --- a/sys/dev/syscons/scterm-teken.c +++ b/sys/dev/syscons/scterm-teken.c @@ -317,88 +317,57 @@ scteken_nop(void) * libteken routines. */ -static const unsigned char fgcolors_normal[TC_NCOLORS] = { - FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, - FG_BLUE, FG_MAGENTA, FG_CYAN, FG_LIGHTGREY, +static const teken_color_t sc_to_te_color[] = { + TC_BLACK, TC_BLUE, TC_GREEN, TC_CYAN, + TC_RED, TC_MAGENTA, TC_BROWN, TC_WHITE, }; -static const unsigned char fgcolors_bold[TC_NCOLORS] = { - FG_DARKGREY, FG_LIGHTRED, FG_LIGHTGREEN, FG_YELLOW, - FG_LIGHTBLUE, FG_LIGHTMAGENTA, FG_LIGHTCYAN, FG_WHITE, -}; - -static const unsigned char bgcolors[TC_NCOLORS] = { - BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, - BG_BLUE, BG_MAGENTA, BG_CYAN, BG_LIGHTGREY, +static const unsigned char te_to_sc_color[] = { + FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, + FG_BLUE, FG_MAGENTA, FG_CYAN, FG_LIGHTGREY, }; static void scteken_sc_to_te_attr(unsigned char color, teken_attr_t *a) { - teken_color_t fg, bg; /* - * XXX: Reverse conversion of syscons to teken attributes. Not - * realiable. Maybe we should turn it into a 1:1 mapping one of - * these days? + * Conversions of attrs are not reversible. Since sc attrs are + * pure colors in the simplest mode (16-color graphics) and the + * API is too deficient to tell us the mode, always convert to + * pure colors. The conversion is essentially the identity except + * for reordering the non-brightness bits in the 2 color numbers. */ - a->ta_format = 0; - a->ta_fgcolor = TC_WHITE; - a->ta_bgcolor = TC_BLACK; - -#ifdef FG_BLINK - if (color & FG_BLINK) { - a->ta_format |= TF_BLINK; - color &= ~FG_BLINK; - } -#endif /* FG_BLINK */ - - for (fg = 0; fg < TC_NCOLORS; fg++) { - for (bg = 0; bg < TC_NCOLORS; bg++) { - if ((fgcolors_normal[fg] | bgcolors[bg]) == color) { - a->ta_fgcolor = fg; - a->ta_bgcolor = bg; - return; - } - - if ((fgcolors_bold[fg] | bgcolors[bg]) == color) { - a->ta_fgcolor = fg; - a->ta_bgcolor = bg; - a->ta_format |= TF_BOLD; - return; - } - } - } + a->ta_fgcolor = sc_to_te_color[color & 7] | (color & 8); + a->ta_bgcolor = sc_to_te_color[(color >> 4) & 7] | ((color >> 4) & 8); } static int scteken_te_to_sc_attr(const teken_attr_t *a) { - int attr = 0; + int attr; teken_color_t fg, bg; if (a->ta_format & TF_REVERSE) { - fg = teken_256to8(a->ta_bgcolor); - bg = teken_256to8(a->ta_fgcolor); + fg = a->ta_bgcolor; + bg = a->ta_fgcolor; } else { - fg = teken_256to8(a->ta_fgcolor); - bg = teken_256to8(a->ta_bgcolor); + fg = a->ta_fgcolor; + bg = a->ta_bgcolor; } - if (a->ta_format & TF_BOLD) - attr |= fgcolors_bold[fg]; - else - attr |= fgcolors_normal[fg]; - attr |= bgcolors[bg]; - -#ifdef FG_UNDERLINE - if (a->ta_format & TF_UNDERLINE) - attr |= FG_UNDERLINE; -#endif /* FG_UNDERLINE */ -#ifdef FG_BLINK + if (fg >= 16) + fg = teken_256to16(fg); + if (bg >= 16) + bg = teken_256to16(bg); + attr = te_to_sc_color[fg & 7] | (fg & 8) | + ((te_to_sc_color[bg & 7] | (bg & 8)) << 4); + + /* XXX: underline mapping for Hercules adapter can be better. */ + if (a->ta_format & (TF_BOLD | TF_UNDERLINE)) + attr ^= 8; if (a->ta_format & TF_BLINK) - attr |= FG_BLINK; -#endif /* FG_BLINK */ + attr ^= 0x80; return (attr); } diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c index 5bd88b7..87dcd49 100644 --- a/sys/dev/vt/vt_core.c +++ b/sys/dev/vt/vt_core.c @@ -1077,6 +1077,8 @@ vt_determine_colors(term_char_t c, int cursor, if (TCHAR_FORMAT(c) & TF_BOLD) *fg = TCOLOR_LIGHT(*fg); *bg = TCHAR_BGCOLOR(c); + if (TCHAR_FORMAT(c) & TF_BLINK) + *bg = TCOLOR_LIGHT(*bg); if (TCHAR_FORMAT(c) & TF_REVERSE) invert ^= 1; diff --git a/sys/kern/subr_terminal.c b/sys/kern/subr_terminal.c index 76c6cfb..db42d38 100644 --- a/sys/kern/subr_terminal.c +++ b/sys/kern/subr_terminal.c @@ -130,9 +130,34 @@ static const teken_attr_t default_message = { .ta_format = TCHAR_FORMAT(TERMINAL_NORM_ATTR) }; +/* Fudge fg brightness as TF_BOLD (shifted). */ +#define TCOLOR_FG_FUDGED(color) __extension__ ({ \ + teken_color_t _c; \ + \ + _c = (color); \ + TCOLOR_FG(_c & 7) | ((_c & 8) << 18); \ +}) + +/* Fudge bg brightness as TF_BLINK (shifted). */ +#define TCOLOR_BG_FUDGED(color) __extension__ ({ \ + teken_color_t _c; \ + \ + _c = (color); \ + TCOLOR_BG(_c & 7) | ((_c & 8) << 20); \ +}) + +#define TCOLOR_256TO16(color) __extension__ ({ \ + teken_color_t _c; \ + \ + _c = (color); \ + if (_c >= 16) \ + _c = teken_256to16(_c); \ + _c; \ +}) + #define TCHAR_CREATE(c, a) ((c) | TFORMAT((a)->ta_format) | \ - TCOLOR_FG(teken_256to8((a)->ta_fgcolor)) | \ - TCOLOR_BG(teken_256to8((a)->ta_bgcolor))) + TCOLOR_FG_FUDGED(TCOLOR_256TO16((a)->ta_fgcolor)) | \ + TCOLOR_BG_FUDGED(TCOLOR_256TO16((a)->ta_bgcolor))) static void terminal_init(struct terminal *tm) diff --git a/sys/teken/libteken/teken.3 b/sys/teken/libteken/teken.3 index 70bed07..b42405f 100644 --- a/sys/teken/libteken/teken.3 +++ b/sys/teken/libteken/teken.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 9, 2011 +.Dd Mar 13, 2017 .Dt TEKEN 3 .Os .Sh NAME @@ -57,6 +57,8 @@ .Ft const char * .Fn teken_get_sequence "teken_t *t" "unsigned int id" .Ft teken_color_t +.Fn teken_256to16 "teken_color_t color" +.Ft teken_color_t .Fn teken_256to8 "teken_color_t color" .Ft void .Fn teken_get_defattr_cons25 "teken_t *t" "int *fg" "int *bg" @@ -163,10 +165,22 @@ This library also provides a set of functions that shouldn't be used in any modern applications. .Pp The +.Fn teken_256to16 +function converts an xterm-256 256-color code to an xterm 16-color code +whose color with default palettes is as similar as possible (not very +similar). +The lower 3 bits of the result are the ANSI color and the next lowest +bit is brightness. +Other layers (hardare and software) that only support 16 colors can use +this to avoid knowing the details of 256-color codes. +.Pp +The .Fn teken_256to8 -function converts a color code to one of the 8 primary colors, allowing -the terminal to be rendered on graphics hardware that only supports 8 or -16 colors (e.g. VGA). +function is similar to +.Fn teken_256to16 +except it converts to an ANSI 8-color code. +This is more accurate than discarding the brigtness bit in the result of +.Fn teken_256to16 . .Pp The .Fn teken_get_defattr_cons25 diff --git a/sys/teken/teken.c b/sys/teken/teken.c index 8834390..5a81777 100644 --- a/sys/teken/teken.c +++ b/sys/teken/teken.c @@ -452,55 +452,203 @@ teken_state_numbers(teken_t *t, teken_char_t c) return (0); } +#define k TC_BLACK +#define b TC_BLUE +#define y TC_BROWN +#define c TC_CYAN +#define g TC_GREEN +#define m TC_MAGENTA +#define r TC_RED +#define w TC_WHITE +#define K (TC_BLACK | TC_LIGHT) +#define B (TC_BLUE | TC_LIGHT) +#define Y (TC_BROWN | TC_LIGHT) +#define C (TC_CYAN | TC_LIGHT) +#define G (TC_GREEN | TC_LIGHT) +#define M (TC_MAGENTA | TC_LIGHT) +#define R (TC_RED | TC_LIGHT) +#define W (TC_WHITE | TC_LIGHT) + +/** + * The xterm-256 color map has steps of 0x28 (in the range 0-0xff), except + * for the first step which is 0x5f. Scale to the range 0-6 by dividing + * by 0x28 and rounding down. The range of 0-5 cannot represent the + * larger first step. + * + * This table is generated by the follow rules: + * - if all components are equal, the result is black for (0, 0, 0) and + * (2, 2, 2), else white; otherwise: + * - subtract the smallest component from all components + * - if this gives only one nonzero component, then that is the color + * - else if one component is 2 or more larger than the other nonzero one, + * then that component gives the color + * - else there are 2 nonzero components. The color is that of a small + * equal mixture of these components (cyan, yellow or magenta). E.g., + * (0, 5, 6) (Turquoise2) is a much purer cyan than (0, 2, 3) + * (DeepSkyBlue4), but we map both to cyan since we can't represent + * delicate shades of either blue or cyan and blue would be worse. + * Here it is important that components of 1 never occur. Blue would + * be twice as large as green in (0, 1, 2). + */ +static const teken_color_t teken_256to8tab[] = { + /* xterm normal colors: */ + k, r, g, y, b, m, c, w, + + /* xterm bright colors: */ + k, r, g, y, b, m, c, w, + + /* Red0 submap. */ + k, b, b, b, b, b, + g, c, c, b, b, b, + g, c, c, c, b, b, + g, g, c, c, c, b, + g, g, g, c, c, c, + g, g, g, g, c, c, + + /* Red2 submap. */ + r, m, m, b, b, b, + y, k, b, b, b, b, + y, g, c, c, b, b, + g, g, c, c, c, b, + g, g, g, c, c, c, + g, g, g, g, c, c, + + /* Red3 submap. */ + r, m, m, m, b, b, + y, r, m, m, b, b, + y, y, w, b, b, b, + y, y, g, c, c, b, + g, g, g, c, c, c, + g, g, g, g, c, c, + + /* Red4 submap. */ + r, r, m, m, m, b, + r, r, m, m, m, b, + y, y, r, m, m, b, + y, y, y, w, b, b, + y, y, y, g, c, c, + g, g, g, g, c, c, + + /* Red5 submap. */ + r, r, r, m, m, m, + r, r, r, m, m, m, + r, r, r, m, m, m, + y, y, y, r, m, m, + y, y, y, y, w, b, + y, y, y, y, g, c, + + /* Red6 submap. */ + r, r, r, r, m, m, + r, r, r, r, m, m, + r, r, r, r, m, m, + r, r, r, r, m, m, + y, y, y, y, r, m, + y, y, y, y, y, w, + + /* Grey submap. */ + k, k, k, k, k, k, + k, k, k, k, k, k, + w, w, w, w, w, w, + w, w, w, w, w, w, +}; + +/* + * This table is generated from the previous one by setting TC_LIGHT for + * entries whose luminosity in the xterm256 color map is 60% or larger. + * Thus the previous table is currently not really needed. It will be + * used for different fine tuning of the tables. + */ +static const teken_color_t teken_256to16tab[] = { + /* xterm normal colors: */ + k, r, g, y, b, m, c, w, + + /* xterm bright colors: */ + K, R, G, Y, B, M, C, W, + + /* Red0 submap. */ + k, b, b, b, b, b, + g, c, c, b, b, b, + g, c, c, c, b, b, + g, g, c, c, c, b, + g, g, g, c, c, c, + g, g, g, g, c, c, + + /* Red2 submap. */ + r, m, m, b, b, b, + y, K, b, b, B, B, + y, g, c, c, B, B, + g, g, c, c, C, B, + g, G, G, C, C, C, + g, G, G, G, C, C, + + /* Red3 submap. */ + r, m, m, m, b, b, + y, r, m, m, B, B, + y, y, w, B, B, B, + y, y, G, C, C, B, + g, G, G, C, C, C, + g, G, G, G, C, C, + + /* Red4 submap. */ + r, r, m, m, m, b, + r, r, m, m, M, B, + y, y, R, M, M, B, + y, y, Y, W, B, B, + y, Y, Y, G, C, C, + g, G, G, G, C, C, + + /* Red5 submap. */ + r, r, r, m, m, m, + r, R, R, M, M, M, + r, R, R, M, M, M, + y, Y, Y, R, M, M, + y, Y, Y, Y, W, B, + y, Y, Y, Y, G, C, + + /* Red6 submap. */ + r, r, r, r, m, m, + r, R, R, R, M, M, + r, R, R, R, M, M, + r, R, R, R, M, M, + y, Y, Y, Y, R, M, + y, Y, Y, Y, Y, W, + + /* Grey submap. */ + k, k, k, k, k, k, + K, K, K, K, K, K, + w, w, w, w, w, w, + W, W, W, W, W, W, +}; + +#undef k +#undef b +#undef y +#undef c +#undef g +#undef m +#undef r +#undef w +#undef K +#undef B +#undef Y +#undef C +#undef G +#undef M +#undef R +#undef W + teken_color_t teken_256to8(teken_color_t c) { - unsigned int r, g, b; - - if (c < 16) { - /* Traditional color indices. */ - return (c % 8); - } else if (c >= 244) { - /* Upper grayscale colors. */ - return (TC_WHITE); - } else if (c >= 232) { - /* Lower grayscale colors. */ - return (TC_BLACK); - } - /* Convert to RGB. */ - c -= 16; - b = c % 6; - g = (c / 6) % 6; - r = c / 36; - - if (r < g) { - /* Possibly green. */ - if (g < b) - return (TC_BLUE); - else if (g > b) - return (TC_GREEN); - else - return (TC_CYAN); - } else if (r > g) { - /* Possibly red. */ - if (r < b) - return (TC_BLUE); - else if (r > b) - return (TC_RED); - else - return (TC_MAGENTA); - } else { - /* Possibly brown. */ - if (g < b) - return (TC_BLUE); - else if (g > b) - return (TC_BROWN); - else if (r < 3) - return (TC_BLACK); - else - return (TC_WHITE); - } + return (teken_256to8tab[c % 256]); +} + +teken_color_t +teken_256to16(teken_color_t c) +{ + + return (teken_256to16tab[c % 256]); } static const char * const special_strings_cons25[] = { diff --git a/sys/teken/teken.h b/sys/teken/teken.h index 27d1ce4..7e3716b 100644 --- a/sys/teken/teken.h +++ b/sys/teken/teken.h @@ -56,6 +56,7 @@ typedef unsigned char teken_color_t; #define TC_CYAN 6 #define TC_WHITE 7 #define TC_NCOLORS 8 +#define TC_LIGHT 8 /* ORed with the others. */ typedef struct { teken_unit_t tp_row; @@ -203,6 +204,7 @@ void teken_set_8bit(teken_t *); void teken_set_cons25(teken_t *); /* Color conversion. */ +teken_color_t teken_256to16(teken_color_t); teken_color_t teken_256to8(teken_color_t); #endif /* !_TEKEN_H_ */ diff --git a/sys/teken/teken_subr_compat.h b/sys/teken/teken_subr_compat.h index a79cdfb..22dc126 100644 --- a/sys/teken/teken_subr_compat.h +++ b/sys/teken/teken_subr_compat.h @@ -40,23 +40,16 @@ static void teken_subr_cons25_set_adapter_background(teken_t *t, unsigned int c) { - t->t_defattr.ta_bgcolor = cons25_colors[c % 8]; - t->t_curattr.ta_bgcolor = cons25_colors[c % 8]; + t->t_defattr.ta_bgcolor = cons25_colors[c % 8] | (c & 8); + t->t_curattr.ta_bgcolor = cons25_colors[c % 8] | (c & 8); } static void teken_subr_cons25_set_adapter_foreground(teken_t *t, unsigned int c) { - t->t_defattr.ta_fgcolor = cons25_colors[c % 8]; - t->t_curattr.ta_fgcolor = cons25_colors[c % 8]; - if (c >= 8) { - t->t_defattr.ta_format |= TF_BOLD; - t->t_curattr.ta_format |= TF_BOLD; - } else { - t->t_defattr.ta_format &= ~TF_BOLD; - t->t_curattr.ta_format &= ~TF_BOLD; - } + t->t_defattr.ta_fgcolor = cons25_colors[c % 8] | (c & 8); + t->t_curattr.ta_fgcolor = cons25_colors[c % 8] | (c & 8); } static const teken_color_t cons25_revcolors[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; |