Zbigniew Jędrzejewski-Szmek 62fe94
From 56dec05d29098b151421625c68525c2c3961e574 Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek 62fe94
From: David Herrmann <dh.herrmann@gmail.com>
Zbigniew Jędrzejewski-Szmek 62fe94
Date: Fri, 3 Oct 2014 14:44:41 +0200
Zbigniew Jędrzejewski-Szmek 62fe94
Subject: [PATCH] terminal/screen: add color converter
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
Terminals use pseudo color-codes mixed with 8bit and 24bit colors. Provide
Zbigniew Jędrzejewski-Szmek 62fe94
a color-converter so external renderers only have to deal with ARGB32
Zbigniew Jędrzejewski-Szmek 62fe94
colors.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
This requires a color-palette as input as there's no fixed mapping. We
Zbigniew Jędrzejewski-Szmek 62fe94
provide a default, but maybe we wanna support external palettes in the
Zbigniew Jędrzejewski-Szmek 62fe94
future.
Zbigniew Jędrzejewski-Szmek 62fe94
---
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/term-parser.c | 116 ++++++++++++++++++++++++++++++++++
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/term-screen.c |  26 +-------
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/term.h        |   2 +
Zbigniew Jędrzejewski-Szmek 62fe94
 3 files changed, 120 insertions(+), 24 deletions(-)
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/term-parser.c b/src/libsystemd-terminal/term-parser.c
Zbigniew Jędrzejewski-Szmek 62fe94
index f9326d563a..8ec6345d60 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd-terminal/term-parser.c
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/term-parser.c
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -35,6 +35,122 @@
Zbigniew Jędrzejewski-Szmek 62fe94
 #include "term-internal.h"
Zbigniew Jędrzejewski-Szmek 62fe94
 #include "util.h"
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+static const uint8_t default_palette[18][3] = {
Zbigniew Jędrzejewski-Szmek 62fe94
+        {   0,   0,   0 }, /* black */
Zbigniew Jędrzejewski-Szmek 62fe94
+        { 205,   0,   0 }, /* red */
Zbigniew Jędrzejewski-Szmek 62fe94
+        {   0, 205,   0 }, /* green */
Zbigniew Jędrzejewski-Szmek 62fe94
+        { 205, 205,   0 }, /* yellow */
Zbigniew Jędrzejewski-Szmek 62fe94
+        {   0,   0, 238 }, /* blue */
Zbigniew Jędrzejewski-Szmek 62fe94
+        { 205,   0, 205 }, /* magenta */
Zbigniew Jędrzejewski-Szmek 62fe94
+        {   0, 205, 205 }, /* cyan */
Zbigniew Jędrzejewski-Szmek 62fe94
+        { 229, 229, 229 }, /* light grey */
Zbigniew Jędrzejewski-Szmek 62fe94
+        { 127, 127, 127 }, /* dark grey */
Zbigniew Jędrzejewski-Szmek 62fe94
+        { 255,   0,   0 }, /* light red */
Zbigniew Jędrzejewski-Szmek 62fe94
+        {   0, 255,   0 }, /* light green */
Zbigniew Jędrzejewski-Szmek 62fe94
+        { 255, 255,   0 }, /* light yellow */
Zbigniew Jędrzejewski-Szmek 62fe94
+        {  92,  92, 255 }, /* light blue */
Zbigniew Jędrzejewski-Szmek 62fe94
+        { 255,   0, 255 }, /* light magenta */
Zbigniew Jędrzejewski-Szmek 62fe94
+        {   0, 255, 255 }, /* light cyan */
Zbigniew Jędrzejewski-Szmek 62fe94
+        { 255, 255, 255 }, /* white */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        { 229, 229, 229 }, /* light grey */
Zbigniew Jędrzejewski-Szmek 62fe94
+        {   0,   0,   0 }, /* black */
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+static uint32_t term_color_to_argb32(const term_color *color, const term_attr *attr, const uint8_t *palette) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        static const uint8_t bval[] = {
Zbigniew Jędrzejewski-Szmek 62fe94
+                0x00, 0x5f, 0x87,
Zbigniew Jędrzejewski-Szmek 62fe94
+                0xaf, 0xd7, 0xff,
Zbigniew Jędrzejewski-Szmek 62fe94
+        };
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint8_t r, g, b, t;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(color);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!palette)
Zbigniew Jędrzejewski-Szmek 62fe94
+                palette = (void*)default_palette;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        switch (color->ccode) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        case TERM_CCODE_RGB:
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = color->red;
Zbigniew Jędrzejewski-Szmek 62fe94
+                g = color->green;
Zbigniew Jędrzejewski-Szmek 62fe94
+                b = color->blue;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case TERM_CCODE_256:
Zbigniew Jędrzejewski-Szmek 62fe94
+                t = color->c256;
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (t < 16) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        r = palette[t * 3 + 0];
Zbigniew Jędrzejewski-Szmek 62fe94
+                        g = palette[t * 3 + 1];
Zbigniew Jędrzejewski-Szmek 62fe94
+                        b = palette[t * 3 + 2];
Zbigniew Jędrzejewski-Szmek 62fe94
+                } else if (t < 232) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        t -= 16;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        b = bval[t % 6];
Zbigniew Jędrzejewski-Szmek 62fe94
+                        t /= 6;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        g = bval[t % 6];
Zbigniew Jędrzejewski-Szmek 62fe94
+                        t /= 6;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        r = bval[t % 6];
Zbigniew Jędrzejewski-Szmek 62fe94
+                } else {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        t = (t - 232) * 10 + 8;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        r = t;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        g = t;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        b = t;
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case TERM_CCODE_BLACK ... TERM_CCODE_LIGHT_WHITE:
Zbigniew Jędrzejewski-Szmek 62fe94
+                t = color->ccode - TERM_CCODE_BLACK;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                /* bold causes light colors */
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (t < 8 && attr->bold)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        t += 8;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = palette[t * 3 + 0];
Zbigniew Jędrzejewski-Szmek 62fe94
+                g = palette[t * 3 + 1];
Zbigniew Jędrzejewski-Szmek 62fe94
+                b = palette[t * 3 + 2];
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case TERM_CCODE_DEFAULT:
Zbigniew Jędrzejewski-Szmek 62fe94
+                /* fallthrough */
Zbigniew Jędrzejewski-Szmek 62fe94
+        default:
Zbigniew Jędrzejewski-Szmek 62fe94
+                t = 16 + !(color == &attr->fg);
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = palette[t * 3 + 0];
Zbigniew Jędrzejewski-Szmek 62fe94
+                g = palette[t * 3 + 1];
Zbigniew Jędrzejewski-Szmek 62fe94
+                b = palette[t * 3 + 2];
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return (0xff << 24) | (r << 16) | (g << 8) | b;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+/**
Zbigniew Jędrzejewski-Szmek 62fe94
+ * term_attr_to_argb32() - Encode terminal colors as native ARGB32 value
Zbigniew Jędrzejewski-Szmek 62fe94
+ * @color: Terminal attributes to work on
Zbigniew Jędrzejewski-Szmek 62fe94
+ * @fg: Storage for foreground color (or NULL)
Zbigniew Jędrzejewski-Szmek 62fe94
+ * @bg: Storage for background color (or NULL)
Zbigniew Jędrzejewski-Szmek 62fe94
+ * @palette: The color palette to use (or NULL for default)
Zbigniew Jędrzejewski-Szmek 62fe94
+ *
Zbigniew Jędrzejewski-Szmek 62fe94
+ * This encodes the colors attr->fg and attr->bg as native-endian ARGB32 values
Zbigniew Jędrzejewski-Szmek 62fe94
+ * and returns them. Any color conversions are automatically applied.
Zbigniew Jędrzejewski-Szmek 62fe94
+ */
Zbigniew Jędrzejewski-Szmek 62fe94
+void term_attr_to_argb32(const term_attr *attr, uint32_t *fg, uint32_t *bg, const uint8_t *palette) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint32_t f, b, t;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert(attr);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        f = term_color_to_argb32(&attr->fg, attr, palette);
Zbigniew Jędrzejewski-Szmek 62fe94
+        b = term_color_to_argb32(&attr->bg, attr, palette);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (attr->inverse) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                t = f;
Zbigniew Jędrzejewski-Szmek 62fe94
+                f = b;
Zbigniew Jędrzejewski-Szmek 62fe94
+                b = t;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (fg)
Zbigniew Jędrzejewski-Szmek 62fe94
+                *fg = f;
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (bg)
Zbigniew Jędrzejewski-Szmek 62fe94
+                *bg = b;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
 /**
Zbigniew Jędrzejewski-Szmek 62fe94
  * term_utf8_encode() - Encode single UCS-4 character as UTF-8
Zbigniew Jędrzejewski-Szmek 62fe94
  * @out_utf8: output buffer of at least 4 bytes or NULL
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c
Zbigniew Jędrzejewski-Szmek 62fe94
index ccfb9a450c..3f7ef1cf3c 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd-terminal/term-screen.c
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/term-screen.c
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -2944,31 +2944,9 @@ static int screen_SGR(term_screen *screen, const term_seq *seq) {
Zbigniew Jędrzejewski-Szmek 62fe94
                                 if (i >= seq->n_args || seq->args[i] < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
                                         break;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+                                dst->ccode = TERM_CCODE_256;
Zbigniew Jędrzejewski-Szmek 62fe94
                                 code = seq->args[i];
Zbigniew Jędrzejewski-Szmek 62fe94
-                                if (code < 16) {
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        dst->ccode = code;
Zbigniew Jędrzejewski-Szmek 62fe94
-                                } else if (code < 232) {
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        static const uint8_t bval[] = {
Zbigniew Jędrzejewski-Szmek 62fe94
-                                                0x00, 0x5f, 0x87,
Zbigniew Jędrzejewski-Szmek 62fe94
-                                                0xaf, 0xd7, 0xff,
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        };
Zbigniew Jędrzejewski-Szmek 62fe94
-
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        dst->ccode = TERM_CCODE_256;
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        dst->c256 = code;
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        code -= 16;
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        dst->blue = bval[code % 6];
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        code /= 6;
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        dst->green = bval[code % 6];
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        code /= 6;
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        dst->red = bval[code % 6];
Zbigniew Jędrzejewski-Szmek 62fe94
-                                } else if (code < 256) {
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        dst->ccode = TERM_CCODE_256;
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        dst->c256 = code;
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        code = (code - 232) * 10 + 8;
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        dst->red = code;
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        dst->green = code;
Zbigniew Jędrzejewski-Szmek 62fe94
-                                        dst->blue = code;
Zbigniew Jędrzejewski-Szmek 62fe94
-                                }
Zbigniew Jędrzejewski-Szmek 62fe94
+                                dst->c256 = code < 256 ? code : 0;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
                                 break;
Zbigniew Jędrzejewski-Szmek 62fe94
                         }
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/term.h b/src/libsystemd-terminal/term.h
Zbigniew Jędrzejewski-Szmek 62fe94
index 5228ce0601..8efd48b263 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd-terminal/term.h
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/term.h
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -97,6 +97,8 @@ struct term_attr {
Zbigniew Jędrzejewski-Szmek 62fe94
         unsigned int hidden : 1;                /* hidden */
Zbigniew Jędrzejewski-Szmek 62fe94
 };
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+void term_attr_to_argb32(const term_attr *attr, uint32_t *fg, uint32_t *bg, const uint8_t *palette);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
 /*
Zbigniew Jędrzejewski-Szmek 62fe94
  * UTF-8
Zbigniew Jędrzejewski-Szmek 62fe94
  */