From 2d040cae734fcc5f4c8c03b06b9427d677b75012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Tue, 12 May 2015 02:43:53 +0200 Subject: [PATCH] degesch: color cleanup --- degesch.c | 142 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 79 insertions(+), 63 deletions(-) diff --git a/degesch.c b/degesch.c index 501b63e..a4dbb3e 100644 --- a/degesch.c +++ b/degesch.c @@ -1563,40 +1563,6 @@ free_terminal (void) del_curterm (cur_term); } -// NOTE: commonly terminals have 8 colors (worst), 16 colors (allows brightness -// without the bold/blink attributes), 88 colors (the same plus a 4^3 RGB cube -// and a few shades of gray), or 256 colors (best) - -static int -index_to_terminal_palette (int color) -{ - hard_assert (color >= 0 && color < 256); - - // No conversion - if (max_colors == 256) - return color; - // These colours are the same everywhere - if (color < 16 && max_colors > color) - return color; - - // Outside the 16-color range, we only support the 88-color palette, - // which we can interpolate to from the 256-color one on input - if (max_colors != 88) - return -1; - - // 24 -> 8 extra shades of gray - if (color >= 232) - return 80 + (color - 232) / 3; - - // 6 * 6 * 6 cube -> 4 * 4 * 4 cube - int x[6] = { 0, 1, 1, 2, 2, 3 }; - int index = color - 16; - return 16 + - ( x[ index / 36 ] << 8 - | x[(index / 6) % 6 ] << 4 - | x[(index % 6) ] ); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - typedef int (*terminal_printer_fn) (int); @@ -1726,7 +1692,8 @@ enum ATTRIBUTE_BOLD = 1 << 0, ATTRIBUTE_ITALIC = 1 << 1, ATTRIBUTE_UNDERLINE = 1 << 2, - ATTRIBUTE_INVERSE = 1 << 3 + ATTRIBUTE_INVERSE = 1 << 3, + ATTRIBUTE_BLINK = 1 << 4 }; struct attribute_printer @@ -1773,50 +1740,94 @@ attribute_printer_apply (struct attribute_printer *self, int attribute) } } -// TODO: 256-color output -// - 8 color -> maybe bold, maybe inverse (should text be bold now?) -// - 16 color -> just use the fallback color -// - 88 color -> use the 256color value if available -// - 256 color -> use the 256color value if available +// NOTE: commonly terminals have: +// 8 colors (worst, bright fg with BOLD, bg sometimes with BLINK) +// 16 colors (okayish, we have the full basic range guaranteed) +// 88 colors (the same plus a 4^3 RGB cube and a few shades of gray) +// 256 colors (best, like above but with a larger cube and more gray) + +/// Interpolate from the 256-color palette to the 88-color one +static int +attribute_printer_256_to_88 (int color) +{ + // These colours are the same everywhere + if (color < 16) + return color; + + // 24 -> 8 extra shades of gray + if (color >= 232) + return 80 + (color - 232) / 3; + + // 6 * 6 * 6 cube -> 4 * 4 * 4 cube + int x[6] = { 0, 1, 1, 2, 2, 3 }; + int index = color - 16; + return 16 + + ( x[ index / 36 ] << 8 + | x[(index / 6) % 6 ] << 4 + | x[(index % 6) ] ); +} + +static int +attribute_printer_decode_color (int color, bool *is_bright) +{ + int16_t c16 = color; hard_assert (c16 < 16); + int16_t c256 = color >> 16; hard_assert (c256 < 256); + + *is_bright = false; + switch (max_colors) + { + case 8: + if (c16 >= 8) + { + c16 -= 8; + *is_bright = true; + } + case 16: + return c16; + + case 88: + return c256 <= 0 ? c16 : attribute_printer_256_to_88 (c256); + case 256: + return c256 <= 0 ? c16 : c256; + + default: + // Unsupported palette + return -1; + } +} static void attribute_printer_update (struct attribute_printer *self) { - int fg = 0; - if ((int16_t) (self->want_foreground >> 16) > 0) - fg = index_to_terminal_palette ((int16_t) (self->want_foreground >> 16)); - int bg = 0; - if ((int16_t) (self->want_background >> 16) > 0) - bg = index_to_terminal_palette ((int16_t) (self->want_background >> 16)); - if (fg <= 0) fg = (int16_t) (self->want_foreground); - if (bg <= 0) bg = (int16_t) (self->want_background); + bool fg_is_bright; + int fg = attribute_printer_decode_color + (self->want_foreground, &fg_is_bright); + bool bg_is_bright; + int bg = attribute_printer_decode_color + (self->want_background, &bg_is_bright); + // TODO: (INVERSE | BOLD) should be used for bright backgrounds + // when possible, i.e. when the foreground shouldn't be bright as well + // and when the BOLD attribute hasn't already been set int attributes = self->want; - if (max_colors == 8) + if (attributes & ATTRIBUTE_INVERSE) { - if (fg >= 8) - { - attributes |= ATTRIBUTE_BOLD; - fg -= 8; - } - if (bg >= 8) - { - attributes |= ATTRIBUTE_BOLD; - bg -= 8; - } + bool tmp = fg_is_bright; + fg_is_bright = bg_is_bright; + bg_is_bright = tmp; } - attribute_printer_reset (self); + if (fg_is_bright) attributes |= ATTRIBUTE_BOLD; + if (bg_is_bright) attributes |= ATTRIBUTE_BLINK; - if (fg >= 0) tputs (g_terminal.color_set_fg[fg], 1, self->printer); - if (bg >= 0) tputs (g_terminal.color_set_bg[bg], 1, self->printer); + attribute_printer_reset (self); if (attributes) tputs (tparm (set_attributes, 0, // standout attributes & ATTRIBUTE_UNDERLINE, attributes & ATTRIBUTE_INVERSE, - 0, // blink + attributes & ATTRIBUTE_BLINK, 0, // dim attributes & ATTRIBUTE_BOLD, 0, // blank @@ -1824,6 +1835,11 @@ attribute_printer_update (struct attribute_printer *self) 0) // acs , 1, self->printer); + if (fg >= 0) + tputs (g_terminal.color_set_fg[fg], 1, self->printer); + if (bg >= 0) + tputs (g_terminal.color_set_bg[bg], 1, self->printer); + self->dirty = true; }