Date: Wed, 14 Mar 2018 07:47:26 +0000 (UTC) From: Eitan Adler <eadler@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r330916 - in stable/11/sys: dev/syscons dev/vt kern teken teken/libteken Message-ID: <201803140747.w2E7lQxb072344@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: eadler Date: Wed Mar 14 07:47:26 2018 New Revision: 330916 URL: https://svnweb.freebsd.org/changeset/base/330916 Log: 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. Modified: stable/11/sys/dev/syscons/scterm-teken.c stable/11/sys/dev/vt/vt_core.c stable/11/sys/kern/subr_terminal.c stable/11/sys/teken/libteken/teken.3 stable/11/sys/teken/teken.c stable/11/sys/teken/teken.h stable/11/sys/teken/teken_subr_compat.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/dev/syscons/scterm-teken.c ============================================================================== --- stable/11/sys/dev/syscons/scterm-teken.c Wed Mar 14 07:39:28 2018 (r330915) +++ stable/11/sys/dev/syscons/scterm-teken.c Wed Mar 14 07:47:26 2018 (r330916) @@ -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 te_to_sc_color[] = { + FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, + FG_BLUE, FG_MAGENTA, FG_CYAN, FG_LIGHTGREY, }; -static const unsigned char bgcolors[TC_NCOLORS] = { - BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, - BG_BLUE, BG_MAGENTA, BG_CYAN, BG_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]; + 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); -#ifdef FG_UNDERLINE - if (a->ta_format & TF_UNDERLINE) - attr |= FG_UNDERLINE; -#endif /* FG_UNDERLINE */ -#ifdef FG_BLINK + /* 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); } Modified: stable/11/sys/dev/vt/vt_core.c ============================================================================== --- stable/11/sys/dev/vt/vt_core.c Wed Mar 14 07:39:28 2018 (r330915) +++ stable/11/sys/dev/vt/vt_core.c Wed Mar 14 07:47:26 2018 (r330916) @@ -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; Modified: stable/11/sys/kern/subr_terminal.c ============================================================================== --- stable/11/sys/kern/subr_terminal.c Wed Mar 14 07:39:28 2018 (r330915) +++ stable/11/sys/kern/subr_terminal.c Wed Mar 14 07:47:26 2018 (r330916) @@ -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) Modified: stable/11/sys/teken/libteken/teken.3 ============================================================================== --- stable/11/sys/teken/libteken/teken.3 Wed Mar 14 07:39:28 2018 (r330915) +++ stable/11/sys/teken/libteken/teken.3 Wed Mar 14 07:47:26 2018 (r330916) @@ -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 sho 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 Modified: stable/11/sys/teken/teken.c ============================================================================== --- stable/11/sys/teken/teken.c Wed Mar 14 07:39:28 2018 (r330915) +++ stable/11/sys/teken/teken.c Wed Mar 14 07:47:26 2018 (r330916) @@ -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); - } + return (teken_256to8tab[c % 256]); +} - /* Convert to RGB. */ - c -= 16; - b = c % 6; - g = (c / 6) % 6; - r = c / 36; +teken_color_t +teken_256to16(teken_color_t c) +{ - 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_256to16tab[c % 256]); } static const char * const special_strings_cons25[] = { Modified: stable/11/sys/teken/teken.h ============================================================================== --- stable/11/sys/teken/teken.h Wed Mar 14 07:39:28 2018 (r330915) +++ stable/11/sys/teken/teken.h Wed Mar 14 07:47:26 2018 (r330916) @@ -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_ */ Modified: stable/11/sys/teken/teken_subr_compat.h ============================================================================== --- stable/11/sys/teken/teken_subr_compat.h Wed Mar 14 07:39:28 2018 (r330915) +++ stable/11/sys/teken/teken_subr_compat.h Wed Mar 14 07:47:26 2018 (r330916) @@ -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 };
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201803140747.w2E7lQxb072344>