#include "term-internal.h"
#include "util.h"
+static const uint8_t default_palette[18][3] = {
+ { 0, 0, 0 }, /* black */
+ { 205, 0, 0 }, /* red */
+ { 0, 205, 0 }, /* green */
+ { 205, 205, 0 }, /* yellow */
+ { 0, 0, 238 }, /* blue */
+ { 205, 0, 205 }, /* magenta */
+ { 0, 205, 205 }, /* cyan */
+ { 229, 229, 229 }, /* light grey */
+ { 127, 127, 127 }, /* dark grey */
+ { 255, 0, 0 }, /* light red */
+ { 0, 255, 0 }, /* light green */
+ { 255, 255, 0 }, /* light yellow */
+ { 92, 92, 255 }, /* light blue */
+ { 255, 0, 255 }, /* light magenta */
+ { 0, 255, 255 }, /* light cyan */
+ { 255, 255, 255 }, /* white */
+
+ { 229, 229, 229 }, /* light grey */
+ { 0, 0, 0 }, /* black */
+};
+
+static uint32_t term_color_to_argb32(const term_color *color, const term_attr *attr, const uint8_t *palette) {
+ static const uint8_t bval[] = {
+ 0x00, 0x5f, 0x87,
+ 0xaf, 0xd7, 0xff,
+ };
+ uint8_t r, g, b, t;
+
+ assert(color);
+
+ if (!palette)
+ palette = (void*)default_palette;
+
+ switch (color->ccode) {
+ case TERM_CCODE_RGB:
+ r = color->red;
+ g = color->green;
+ b = color->blue;
+
+ break;
+ case TERM_CCODE_256:
+ t = color->c256;
+ if (t < 16) {
+ r = palette[t * 3 + 0];
+ g = palette[t * 3 + 1];
+ b = palette[t * 3 + 2];
+ } else if (t < 232) {
+ t -= 16;
+ b = bval[t % 6];
+ t /= 6;
+ g = bval[t % 6];
+ t /= 6;
+ r = bval[t % 6];
+ } else {
+ t = (t - 232) * 10 + 8;
+ r = t;
+ g = t;
+ b = t;
+ }
+
+ break;
+ case TERM_CCODE_BLACK ... TERM_CCODE_LIGHT_WHITE:
+ t = color->ccode - TERM_CCODE_BLACK;
+
+ /* bold causes light colors (only for foreground colors) */
+ if (t < 8 && attr->bold && color == &attr->fg)
+ t += 8;
+
+ r = palette[t * 3 + 0];
+ g = palette[t * 3 + 1];
+ b = palette[t * 3 + 2];
+ break;
+ case TERM_CCODE_DEFAULT:
+ /* fallthrough */
+ default:
+ t = 16 + !(color == &attr->fg);
+ r = palette[t * 3 + 0];
+ g = palette[t * 3 + 1];
+ b = palette[t * 3 + 2];
+ break;
+ }
+
+ return (0xff << 24) | (r << 16) | (g << 8) | b;
+}
+
/**
- * term_utf8_encode() - Encode single UCS-4 character as UTF-8
- * @out_utf8: output buffer of at least 4 bytes or NULL
- * @g: UCS-4 character to encode
+ * term_attr_to_argb32() - Encode terminal colors as native ARGB32 value
+ * @color: Terminal attributes to work on
+ * @fg: Storage for foreground color (or NULL)
+ * @bg: Storage for background color (or NULL)
+ * @palette: The color palette to use (or NULL for default)
*
- * This encodes a single UCS-4 character as UTF-8 and writes it into @out_utf8.
- * The length of the character is returned. It is not zero-terminated! If the
- * output buffer is NULL, only the length is returned.
- *
- * Returns: The length in bytes that the UTF-8 representation does or would
- * occupy.
+ * This encodes the colors attr->fg and attr->bg as native-endian ARGB32 values
+ * and returns them. Any color conversions are automatically applied.
*/
-size_t term_utf8_encode(char *out_utf8, uint32_t g) {
- if (g < (1 << 7)) {
- if (out_utf8)
- out_utf8[0] = g & 0x7f;
- return 1;
- } else if (g < (1 << 11)) {
- if (out_utf8) {
- out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f);
- out_utf8[1] = 0x80 | (g & 0x3f);
- }
- return 2;
- } else if (g < (1 << 16)) {
- if (out_utf8) {
- out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f);
- out_utf8[1] = 0x80 | ((g >> 6) & 0x3f);
- out_utf8[2] = 0x80 | (g & 0x3f);
- }
- return 3;
- } else if (g < (1 << 21)) {
- if (out_utf8) {
- out_utf8[0] = 0xf0 | ((g >> 18) & 0x07);
- out_utf8[1] = 0x80 | ((g >> 12) & 0x3f);
- out_utf8[2] = 0x80 | ((g >> 6) & 0x3f);
- out_utf8[3] = 0x80 | (g & 0x3f);
- }
- return 4;
- } else {
- return 0;
+void term_attr_to_argb32(const term_attr *attr, uint32_t *fg, uint32_t *bg, const uint8_t *palette) {
+ uint32_t f, b, t;
+
+ assert(attr);
+
+ f = term_color_to_argb32(&attr->fg, attr, palette);
+ b = term_color_to_argb32(&attr->bg, attr, palette);
+
+ if (attr->inverse) {
+ t = f;
+ f = b;
+ b = t;
}
+
+ if (fg)
+ *fg = f;
+ if (bg)
+ *bg = b;
}
/**
* term_utf8_decode() - Try decoding the next UCS-4 character
* @p: decoder object to operate on or NULL
- * @out_len: output buffer for length of decoded UCS-4 string or NULL
+ * @out_len: output storage for pointer to decoded UCS-4 string or NULL
* @c: next char to push into decoder
*
* This decodes a UTF-8 stream. It must be called for each input-byte of the
- * UTF-8 stream and returns a UCS-4 stream. The length of the returned UCS-4
- * string (number of parsed characters) is stored in @out_len if non-NULL. A
- * pointer to the string is returned (or NULL if none was parsed). The string
- * is not zero-terminated! Furthermore, the string is only valid until the next
- * invokation of this function. It is also bound to the parser-state @p.
+ * UTF-8 stream and returns a UCS-4 stream. A pointer to the parsed UCS-4
+ * string is stored in @out_buf if non-NULL. The length of this string (number
+ * of parsed UCS4 characters) is returned as result. The string is not
+ * zero-terminated! Furthermore, the string is only valid until the next
+ * invocation of this function. It is also bound to the parser state @p and
+ * must not be freed nor written to by the caller.
*
* This function is highly optimized to work with terminal-emulators. Instead
* of being strict about UTF-8 validity, this tries to perform a fallback to
* no helpers to do that for you. To initialize it, simply reset it to all
* zero. You can reset or free the object at any point in time.
*
- * Returns: Pointer to the UCS-4 string or NULL.
+ * Returns: Number of parsed UCS4 characters
*/
-const uint32_t *term_utf8_decode(term_utf8 *p, size_t *out_len, char c) {
+size_t term_utf8_decode(term_utf8 *p, uint32_t **out_buf, char c) {
+ static uint32_t ucs4_null = 0;
uint32_t t, *res = NULL;
uint8_t byte;
size_t len = 0;
p->n_bytes = 4;
p->i_bytes = 1;
p->valid = 1;
- }
+ } else
+ assert_not_reached("Should not happen");
p->chars[0] = byte;
p->ucs4 = t << (6 * (p->n_bytes - p->i_bytes));
p->n_bytes = 0;
out:
- if (out_len)
- *out_len = len;
- return len > 0 ? res : NULL;
+ if (out_buf)
+ *out_buf = res ? : &ucs4_null;
+ return len;
}
/*