mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
osc: wip: kitty text size protocol
This brings initial support for the new kitty text-sizing
protocol. Note hat only the width-parameter ('w') is supported. That
is, no font scaling, and no multi-line cells.
For now, only explicit widths are supported. That is, w=0 does not yet
work.
There are a couple of changes to the renderer, to handle e.g.
OSC 66 ; w=6 ; foobar ST
There are two ways this can get rendered, depending on whether
grapheme shaping has been enabled. We either shape it, and get an
array of glyphs back that we render. Or, we rasterize each codepoint
ourselves, and render each resulting glyph.
The two cases ends up in two different renderer loops, that worked
somewhat different. In particular, the first case has probably never
been tested/used at all...
With this patch, both are changed, and now uses some heuristic to
differentiate between multi-cell text strings (like in the example
above), or single-cell combining characters. The difference is mainly
in which offset to use for the secondary glyphs.
In a multi-cell string, each glyph is mapped to its own cell, while in
the combining case, we try to map all glyphs to the same cell.
This commit is contained in:
parent
1111f7e918
commit
7a8d2b5e01
2 changed files with 104 additions and 14 deletions
81
osc.c
81
osc.c
|
|
@ -610,7 +610,6 @@ verify_kitty_id_is_valid(const char *id)
|
|||
}
|
||||
UNIGNORE_WARNINGS
|
||||
|
||||
|
||||
static void
|
||||
kitty_notification(struct terminal *term, char *string)
|
||||
{
|
||||
|
|
@ -1135,6 +1134,82 @@ out:
|
|||
free(sound_name);
|
||||
}
|
||||
|
||||
static void
|
||||
kitty_text_size(struct terminal *term, char *string)
|
||||
{
|
||||
char *text = strchr(string, ';');
|
||||
if (text == NULL)
|
||||
return;
|
||||
|
||||
char *parameters = string;
|
||||
*text = '\0';
|
||||
text++;
|
||||
|
||||
char32_t *wchars = ambstoc32(text);
|
||||
if (wchars == NULL)
|
||||
return;
|
||||
|
||||
int width = 0;
|
||||
|
||||
char *ctx = NULL;
|
||||
for (char *param = strtok_r(parameters, ":", &ctx);
|
||||
param != NULL;
|
||||
param = strtok_r(NULL, ":", &ctx))
|
||||
{
|
||||
/* All parameters are on the form X=value, where X is always
|
||||
exactly one character */
|
||||
if (param[0] == '\0' || param[1] != '=')
|
||||
continue;
|
||||
|
||||
char *value = ¶m[2];
|
||||
|
||||
switch (param[0]) {
|
||||
case 'w': {
|
||||
errno = 0;
|
||||
char *end = NULL;
|
||||
unsigned long w = strtoul(value, &end, 10);
|
||||
|
||||
if (*end == '\0' && errno == 0 && w <= 7) {
|
||||
width = (int)w;
|
||||
break;
|
||||
} else
|
||||
LOG_ERR("OSC-66: invalid 'w' value, ignoring");
|
||||
break;
|
||||
}
|
||||
|
||||
case 's':
|
||||
case 'n':
|
||||
case 'd':
|
||||
case 'v':
|
||||
LOG_WARN("OSC-66: unsupported: '%c' parameter, ignoring", param[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t len = c32len(wchars);
|
||||
uint32_t key = composed_key_from_chars(wchars, len);
|
||||
|
||||
const struct composed *composed = composed_lookup_without_collision(
|
||||
term->composed, &key, wchars, len - 1, wchars[len - 1], width);
|
||||
|
||||
if (composed == NULL) {
|
||||
struct composed *new_cc = xmalloc(sizeof(*new_cc));
|
||||
new_cc->chars = wchars;
|
||||
new_cc->count = len;
|
||||
new_cc->key = key;
|
||||
new_cc->width = width;
|
||||
new_cc->forced_width = width;
|
||||
|
||||
term->composed_count++;
|
||||
composed_insert(&term->composed, new_cc);
|
||||
composed = new_cc;
|
||||
} else if (composed->width == width) {
|
||||
free(wchars);
|
||||
}
|
||||
|
||||
term_print(term, CELL_COMB_CHARS_LO + composed->key, composed->forced_width > 0 ? composed->forced_width : composed->width);
|
||||
}
|
||||
|
||||
void
|
||||
osc_dispatch(struct terminal *term)
|
||||
{
|
||||
|
|
@ -1371,6 +1446,10 @@ osc_dispatch(struct terminal *term)
|
|||
osc_selection(term, string);
|
||||
break;
|
||||
|
||||
case 66: /* text-size protocol (kitty) */
|
||||
kitty_text_size(term, string);
|
||||
break;
|
||||
|
||||
case 99: /* Kitty notifications */
|
||||
kitty_notification(term, string);
|
||||
break;
|
||||
|
|
|
|||
37
render.c
37
render.c
|
|
@ -869,11 +869,16 @@ render_cell(struct terminal *term, pixman_image_t *pix, pixman_region32_t *damag
|
|||
}
|
||||
|
||||
if (grapheme != NULL) {
|
||||
cell_cols = composed->width;
|
||||
const int forced_width = composed->forced_width;
|
||||
|
||||
cell_cols = forced_width > 0 ? forced_width : composed->width;
|
||||
|
||||
composed = NULL;
|
||||
glyphs = grapheme->glyphs;
|
||||
glyph_count = grapheme->count;
|
||||
|
||||
if (forced_width > 0)
|
||||
glyph_count = min(glyph_count, forced_width);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -890,7 +895,9 @@ render_cell(struct terminal *term, pixman_image_t *pix, pixman_region32_t *damag
|
|||
} else {
|
||||
glyph_count = 1;
|
||||
glyphs = &single;
|
||||
cell_cols = single->cols;
|
||||
|
||||
const size_t forced_width = composed != NULL ? composed->forced_width : 0;
|
||||
cell_cols = forced_width > 0 ? forced_width : single->cols;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -972,7 +979,7 @@ render_cell(struct terminal *term, pixman_image_t *pix, pixman_region32_t *damag
|
|||
int g_x = glyph->x;
|
||||
int g_y = glyph->y;
|
||||
|
||||
if (i > 0 && glyph->x >= 0)
|
||||
if (i > 0 && glyph->x >= 0 && cell_cols == 1)
|
||||
g_x -= term->cell_width;
|
||||
|
||||
if (unlikely(pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8)) {
|
||||
|
|
@ -993,9 +1000,9 @@ render_cell(struct terminal *term, pixman_image_t *pix, pixman_region32_t *damag
|
|||
if (composed != NULL) {
|
||||
assert(glyph_count == 1);
|
||||
|
||||
for (size_t i = 1; i < composed->count; i++) {
|
||||
for (size_t j = 1; j < composed->count; j++) {
|
||||
const struct fcft_glyph *g = fcft_rasterize_char_utf32(
|
||||
font, composed->chars[i], term->font_subpixel);
|
||||
font, composed->chars[j], term->font_subpixel);
|
||||
|
||||
if (g == NULL)
|
||||
continue;
|
||||
|
|
@ -1017,22 +1024,26 @@ render_cell(struct terminal *term, pixman_image_t *pix, pixman_region32_t *damag
|
|||
* somewhat deal with double-width glyphs we use
|
||||
* an offset of *one* cell.
|
||||
*/
|
||||
int x_ofs = g->x < 0
|
||||
? cell_cols * term->cell_width
|
||||
: (cell_cols - 1) * term->cell_width;
|
||||
int x_ofs = cell_cols == 1
|
||||
? g->x < 0
|
||||
? cell_cols * term->cell_width
|
||||
: (cell_cols - 1) * term->cell_width
|
||||
: 0;
|
||||
|
||||
if (cell_cols > 1)
|
||||
pen_x += term->cell_width;
|
||||
|
||||
pixman_image_composite32(
|
||||
PIXMAN_OP_OVER, clr_pix, g->pix, pix, 0, 0, 0, 0,
|
||||
/* Some fonts use a negative offset, while others use a
|
||||
* "normal" offset */
|
||||
pen_x + x_ofs + g->x,
|
||||
y + term->font_baseline - g->y,
|
||||
g->width, g->height);
|
||||
pen_x + letter_x_ofs + x_ofs + g->x,
|
||||
y + term->font_baseline - g->y, g->width, g->height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pen_x += glyph->advance.x;
|
||||
pen_x += cell_cols > 1 ? term->cell_width : glyph->advance.x;
|
||||
}
|
||||
|
||||
pixman_image_unref(clr_pix);
|
||||
|
|
@ -4398,7 +4409,7 @@ render_resize(struct terminal *term, int width, int height, uint8_t opts)
|
|||
}
|
||||
|
||||
/* Don't shrink grid too much */
|
||||
const int min_cols = 2;
|
||||
const int min_cols = 7;
|
||||
const int min_rows = 1;
|
||||
|
||||
/* Minimum window size (must be divisible by the scaling factor)*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue