csi: fix sub-parameter versions of 38/48 SGR escapes

Well this is embarrassing; the sub-parameter versions of the 38/48 SGR
escapes all required an extra ‘:2’ that wasn’t supposed to be there,
causing all the other sub-parameters to be shifted one step to the
right.

That is, foot expected e.g. 38:2:2:r:g:b, or 38:2:5:idx when the
correct sequences are 38:2:cs:r:g:b and 38:5:idx.

I.e. I mixed up the color-space ID (cs) of 38:2 with *type* of color:
RGB or indexed.

In addition to fixing this, this patch also adds support for a
“bastard” version of the sub-parameter based RGB escapes, where the
color-space identifier has been left out: e.g. 38:2:r:g:b. This
sequence is invalid, but applications tend to “forget” the color-space
ID...
This commit is contained in:
Daniel Eklöf 2020-12-12 20:50:43 +01:00
parent ff96ce1e91
commit 9f321e6030
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
3 changed files with 82 additions and 80 deletions

148
csi.c
View file

@ -141,53 +141,51 @@ csi_sgr(struct terminal *term)
i += 4;
}
/* Sub-parameter style: 38:2:... */
/* Indexed: 38:5:<idx> */
else if (term->vt.params.v[i].sub.idx >= 2 &&
term->vt.params.v[i].sub.value[0] == 5)
{
const struct vt_param *param = &term->vt.params.v[i];
uint8_t idx = param->sub.value[1];
term->vt.attrs.have_fg = 1;
term->vt.attrs.fg = term->colors.table[idx];
}
/*
* RGB: 38:2:<color-space>:r:g:b[:ignored:tolerance:tolerance-color-space]
* RGB: 38:2:r:g:b
*
* The second version is a "bastard" version - many
* programs "forget" the color space ID
* parameter... *sigh*
*/
else if (term->vt.params.v[i].sub.idx >= 4 &&
term->vt.params.v[i].sub.value[0] == 2)
{
const struct vt_param *param = &term->vt.params.v[i];
const int color_space_id = param->sub.value[1];
bool have_color_space_id = param->sub.idx >= 5;
switch (color_space_id) {
case 0: /* Implementation defined - we map it to '2' */
case 2: { /* RGB - 38:2:2:<r>:<g>:<b> */
if (param->sub.idx < 5) {
UNHANDLED_SGR(i);
break;
}
/* 0 - color space (ignored) */
int r_idx = 2 - !have_color_space_id;
int g_idx = 3 - !have_color_space_id;
int b_idx = 4 - !have_color_space_id;
/* 5 - unused */
/* 6 - CS tolerance */
/* 7 - color space associated with tolerance */
uint8_t r = param->sub.value[2];
uint8_t g = param->sub.value[3];
uint8_t b = param->sub.value[4];
/* 5 - unused */
/* 6 - CS tolerance */
/* 7 - color space associated with tolerance */
uint8_t r = param->sub.value[r_idx];
uint8_t g = param->sub.value[g_idx];
uint8_t b = param->sub.value[b_idx];
term->vt.attrs.have_fg = 1;
term->vt.attrs.fg = r << 16 | g << 8 | b;
break;
}
case 5: { /* Indexed - 38:2:5:<idx> */
if (param->sub.idx < 3) {
UNHANDLED_SGR(i);
break;
}
uint8_t idx = param->sub.value[2];
term->vt.attrs.have_fg = 1;
term->vt.attrs.fg = term->colors.table[idx];
break;
}
case 1: /* Transparent */
case 3: /* CMY */
case 4: /* CMYK */
UNHANDLED_SGR(i);
break;
}
term->vt.attrs.have_fg = 1;
term->vt.attrs.fg = r << 16 | g << 8 | b;
}
/* Transparent: 38:1 */
/* CMY: 38:3:<color-space>:c:m:y[:tolerance:tolerance-color-space] */
/* CMYK: 38:4:<color-space>:c:m:y:k[:tolerance:tolerance-color-space] */
/* Unrecognized */
else
UNHANDLED_SGR(i);
@ -236,53 +234,51 @@ csi_sgr(struct terminal *term)
i += 4;
}
/* Sub-parameter style: 48:2:... */
/* Indexed: 48:5:<idx> */
else if (term->vt.params.v[i].sub.idx >= 2 &&
term->vt.params.v[i].sub.value[0] == 5)
{
const struct vt_param *param = &term->vt.params.v[i];
uint8_t idx = param->sub.value[1];
term->vt.attrs.have_bg = 1;
term->vt.attrs.bg = term->colors.table[idx];
}
/*
* RGB: 48:2:<color-space>:r:g:b[:ignored:tolerance:tolerance-color-space]
* RGB: 48:2:r:g:b
*
* The second version is a "bastard" version - many
* programs "forget" the color space ID
* parameter... *sigh*
*/
else if (term->vt.params.v[i].sub.idx >= 4 &&
term->vt.params.v[i].sub.value[0] == 2)
{
const struct vt_param *param = &term->vt.params.v[i];
const int color_space_id = param->sub.value[1];
bool have_color_space_id = param->sub.idx >= 5;
switch (color_space_id) {
case 0: /* Implementation defined - we map it to '2' */
case 2: { /* RGB - 48:2:2:<r>:<g>:<b> */
if (param->sub.idx < 5) {
UNHANDLED_SGR(i);
break;
}
/* 0 - color space (ignored) */
int r_idx = 2 - !have_color_space_id;
int g_idx = 3 - !have_color_space_id;
int b_idx = 4 - !have_color_space_id;
/* 5 - unused */
/* 6 - CS tolerance */
/* 7 - color space associated with tolerance */
uint8_t r = param->sub.value[2];
uint8_t g = param->sub.value[3];
uint8_t b = param->sub.value[4];
/* 5 - unused */
/* 6 - CS tolerance */
/* 7 - color space associated with tolerance */
uint8_t r = param->sub.value[r_idx];
uint8_t g = param->sub.value[g_idx];
uint8_t b = param->sub.value[b_idx];
term->vt.attrs.have_bg = 1;
term->vt.attrs.bg = r << 16 | g << 8 | b;
break;
}
case 5: { /* Indexed - 48:2:5:<idx> */
if (param->sub.idx < 3) {
UNHANDLED_SGR(i);
break;
}
uint8_t idx = param->sub.value[2];
term->vt.attrs.have_bg = 1;
term->vt.attrs.bg = term->colors.table[idx];
break;
}
case 1: /* Transparent */
case 3: /* CMY */
case 4: /* CMYK */
UNHANDLED_SGR(i);
break;
}
term->vt.attrs.have_bg = 1;
term->vt.attrs.bg = r << 16 | g << 8 | b;
}
/* Transparent: 48:1 */
/* CMY: 48:3:<color-space>:c:m:y[:tolerance:tolerance-color-space] */
/* CMYK: 48:4:<color-space>:c:m:y:k[:tolerance:tolerance-color-space] */
else
UNHANDLED_SGR(i);