render: implement 'underline'

This commit is contained in:
Daniel Eklöf 2019-07-16 14:20:39 +02:00
parent 441337645a
commit d93ca2f654
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
4 changed files with 86 additions and 34 deletions

42
main.c
View file

@ -10,6 +10,7 @@
#include <poll.h>
#include <errno.h>
#include <cairo-ft.h>
#include <wayland-client.h>
#include <wayland-cursor.h>
#include <xdg-shell.h>
@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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;