From d93ca2f654e686c5b11e90a9e8198382443d65e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 16 Jul 2019 14:20:39 +0200 Subject: [PATCH] render: implement 'underline' --- main.c | 42 +++++++++++++++++++++++++++------- render.c | 66 ++++++++++++++++++++++++++++++++++-------------------- render.h | 2 +- terminal.h | 10 ++++++++- 4 files changed, 86 insertions(+), 34 deletions(-) diff --git a/main.c b/main.c index 9dde438a..992b1650 100644 --- a/main.c +++ b/main.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -349,23 +350,48 @@ main(int argc, char *const *argv) thrd_t keyboard_repeater_id; thrd_create(&keyboard_repeater_id, &keyboard_repeater, &term); - term.fonts[0] = font_from_name(conf.font); - if (term.fonts[0] == NULL) + term.fonts[0].font = font_from_name(conf.font); + if (term.fonts[0].font == NULL) goto out; { char fname[1024]; snprintf(fname, sizeof(fname), "%s:style=bold", conf.font); - term.fonts[1] = font_from_name(fname); + term.fonts[1].font = font_from_name(fname); snprintf(fname, sizeof(fname), "%s:style=italic", conf.font); - term.fonts[2] = font_from_name(fname); + term.fonts[2].font = font_from_name(fname); snprintf(fname, sizeof(fname), "%s:style=bold italic", conf.font); - term.fonts[3] = font_from_name(fname); + term.fonts[3].font = font_from_name(fname); } - cairo_scaled_font_extents(term.fonts[0], &term.fextents); + /* Underline position and size */ + for (size_t i = 0; i < sizeof(term.fonts) / sizeof(term.fonts[0]); i++) { + struct font *f = &term.fonts[i]; + + if (f->font == NULL) + continue; + + FT_Face ft_face = cairo_ft_scaled_font_lock_face(f->font); + + double x_scale = ft_face->size->metrics.x_scale / 65526.; + f->underline.position = ft_face->underline_position * x_scale / 64.; + f->underline.thickness = ft_face->underline_thickness * x_scale / 64.; + + if (f->underline.position == 0.) { + double descent = ft_face->size->metrics.descender / 64; + f->underline.position = descent / 2.; + f->underline.thickness = fabs(round(descent / 5.)); + } + + LOG_DBG("underline: pos=%f, thick=%f", + f->underline.position, f->underline.thickness); + + cairo_ft_scaled_font_unlock_face(f->font); + } + + cairo_scaled_font_extents(term.fonts[0].font, &term.fextents); term.cell_width = (int)ceil(term.fextents.max_x_advance); term.cell_height = (int)ceil(term.fextents.height); @@ -699,8 +725,8 @@ out: free(term.alt.rows); for (size_t i = 0; i < sizeof(term.fonts) / sizeof(term.fonts[0]); i++) { - if (term.fonts[i] != NULL) - cairo_scaled_font_destroy(term.fonts[i]); + if (term.fonts[i].font != NULL) + cairo_scaled_font_destroy(term.fonts[i].font); } if (term.ptmx != -1) diff --git a/render.c b/render.c index 4dc742c4..94c38fc4 100644 --- a/render.c +++ b/render.c @@ -15,11 +15,11 @@ #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) -cairo_scaled_font_t * +const struct font * attrs_to_font(struct terminal *term, const struct attributes *attrs) { int idx = attrs->italic << 1 | attrs->bold; - return term->fonts[idx]; + return &term->fonts[idx]; } struct glyph_sequence { @@ -28,11 +28,7 @@ struct glyph_sequence { int count; struct attributes attrs; -#if 0 - struct rgb foreground; -#else uint32_t foreground; -#endif }; static struct glyph_sequence gseq; @@ -41,18 +37,18 @@ static void gseq_flush(struct terminal *term, struct buffer *buf) { struct rgb fg = { - ((gseq.foreground >> 16) & 0xff) / 255.0, - ((gseq.foreground >> 8) & 0xff) / 255.0, - ((gseq.foreground >> 0) & 0xff) / 255.0, + ((gseq.foreground >> 16) & 0xff) / 255., + ((gseq.foreground >> 8) & 0xff) / 255., + ((gseq.foreground >> 0) & 0xff) / 255., }; if (gseq.attrs.dim) { - fg.r /= 2.0; - fg.g /= 2.0; - fg.b /= 2.0; + fg.r /= 2.; + fg.g /= 2.; + fg.b /= 2.; } - cairo_set_scaled_font(buf->cairo, attrs_to_font(term, &gseq.attrs)); + cairo_set_scaled_font(buf->cairo, attrs_to_font(term, &gseq.attrs)->font); cairo_set_source_rgb(buf->cairo, fg.r, fg.g, fg.b); cairo_show_glyphs(buf->cairo, gseq.glyphs, gseq.count); @@ -109,22 +105,44 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, _background = swap; } - struct rgb background = { - ((_background >> 16) & 0xff) / 255.0, - ((_background >> 8) & 0xff) / 255.0, - ((_background >> 0) & 0xff) / 255.0, + struct rgb foreground = { + ((_foreground >> 16) & 0xff) / 255., + ((_foreground >> 8) & 0xff) / 255., + ((_foreground >> 0) & 0xff) / 255., }; + struct rgb background = { + ((_background >> 16) & 0xff) / 255., + ((_background >> 8) & 0xff) / 255., + ((_background >> 0) & 0xff) / 255., + }; + + if (cell->attrs.dim) { + foreground.r /= 2.; + foreground.g /= 2.; + foreground.b /= 2.; + } + /* Background */ cairo_set_source_rgb(buf->cairo, background.r, background.g, background.b); cairo_rectangle(buf->cairo, x, y, width, height); cairo_fill(buf->cairo); - if (cell->c[0] == '\0' || cell->c[0] == ' ') + if (cell->c[0] == '\0' || cell->attrs.conceal) return; - if (cell->attrs.conceal) - return; + /* Underline */ + if (cell->attrs.underline) { + const struct font *font = attrs_to_font(term, &cell->attrs); + double width = font->underline.thickness; + double y_under = y + term->cell_height + font->underline.position + width / 2.; + + cairo_set_source_rgb(buf->cairo, foreground.r, foreground.g, foreground.b); + cairo_set_line_width(buf->cairo, width); + cairo_move_to(buf->cairo, x, y_under); + cairo_line_to(buf->cairo, x + term->cell_width, y_under); + cairo_stroke(buf->cairo); + } /* * cairo_show_glyphs() apparently works *much* faster when @@ -151,7 +169,7 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, = sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]) - gseq.count; cairo_status_t status = cairo_scaled_font_text_to_glyphs( - attrs_to_font(term, &cell->attrs), x, y + term->fextents.ascent, + attrs_to_font(term, &cell->attrs)->font, x, y + term->fextents.ascent, cell->c, strnlen(cell->c, 4), &gseq.g, &new_glyphs, NULL, NULL, NULL); @@ -256,9 +274,9 @@ grid_render(struct terminal *term) #else uint32_t _bg = !term->reverse ? term->background : term->foreground; struct rgb bg = { - ((_bg >> 16) & 0xff) / 255.0, - ((_bg >> 8) & 0xff) / 255.0, - ((_bg >> 0) & 0xff) / 255.0, + ((_bg >> 16) & 0xff) / 255., + ((_bg >> 8) & 0xff) / 255., + ((_bg >> 0) & 0xff) / 255., }; #endif cairo_set_source_rgb(buf->cairo, bg.r, bg.g, bg.b); diff --git a/render.h b/render.h index 7a79e882..93220dd8 100644 --- a/render.h +++ b/render.h @@ -2,7 +2,7 @@ #include "terminal.h" -cairo_scaled_font_t *attrs_to_font( +const struct font *attrs_to_font( struct terminal *term, const struct attributes *attrs); void grid_render(struct terminal *term); diff --git a/terminal.h b/terminal.h index bbc6c0ad..daec8667 100644 --- a/terminal.h +++ b/terminal.h @@ -202,6 +202,14 @@ struct primary { uint32_t serial; }; +struct font { + cairo_scaled_font_t *font; + struct { + double position; + double thickness; + } underline; +}; + struct terminal { pid_t slave; int ptmx; @@ -258,7 +266,7 @@ struct terminal { struct grid alt; struct grid *grid; - cairo_scaled_font_t *fonts[4]; + struct font fonts[4]; cairo_font_extents_t fextents; struct wayland wl;