mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-20 01:40:14 -05:00
wip: render background and glyphs using pixman
This commit is contained in:
parent
9259696b18
commit
bed7b34c28
5 changed files with 134 additions and 78 deletions
115
render.c
115
render.c
|
|
@ -37,6 +37,17 @@ color_hex_to_rgb(uint32_t color)
|
|||
};
|
||||
}
|
||||
|
||||
static inline pixman_color_t
|
||||
color_hex_to_pixman(uint32_t color)
|
||||
{
|
||||
return (pixman_color_t){
|
||||
.red = (((color >> 16) & 0xff) + 1) * 256 - 1,
|
||||
.green = (((color >> 8) & 0xff) + 1) * 256 - 1,
|
||||
.blue = (((color >> 0) & 0xff) + 1) * 256 - 1,
|
||||
.alpha = -1,
|
||||
};
|
||||
}
|
||||
|
||||
static inline void
|
||||
color_dim(struct rgb *rgb)
|
||||
{
|
||||
|
|
@ -45,6 +56,14 @@ color_dim(struct rgb *rgb)
|
|||
rgb->b /= 2.;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pixman_color_dim(pixman_color_t *color)
|
||||
{
|
||||
color->red /= 2;
|
||||
color->green /= 2;
|
||||
color->blue /= 2;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_underline(const struct terminal *term, cairo_t *cr, const struct font *font,
|
||||
struct rgb color, double x, double y, int cols)
|
||||
|
|
@ -136,7 +155,7 @@ arm_blink_timer(struct terminal *term)
|
|||
}
|
||||
|
||||
static int
|
||||
render_cell(struct terminal *term, cairo_t *cr,
|
||||
render_cell(struct terminal *term, cairo_t *cr, pixman_image_t *pix,
|
||||
struct cell *cell, int col, int row, bool has_cursor)
|
||||
{
|
||||
if (cell->attrs.clean)
|
||||
|
|
@ -169,35 +188,36 @@ render_cell(struct terminal *term, cairo_t *cr,
|
|||
if (cell->attrs.blink && term->blink.state == BLINK_OFF)
|
||||
_fg = _bg;
|
||||
|
||||
struct rgb fg = color_hex_to_rgb(_fg);
|
||||
struct rgb bg = color_hex_to_rgb(_bg);
|
||||
pixman_color_t fg = color_hex_to_pixman(_fg);
|
||||
pixman_color_t bg = color_hex_to_pixman(_bg);
|
||||
|
||||
if (cell->attrs.dim)
|
||||
color_dim(&fg);
|
||||
pixman_color_dim(&fg);
|
||||
|
||||
if (block_cursor && term->cursor_color.text >> 31) {
|
||||
/* User configured cursor color overrides all attributes */
|
||||
assert(term->cursor_color.cursor >> 31);
|
||||
fg = color_hex_to_rgb(term->cursor_color.text);
|
||||
bg = color_hex_to_rgb(term->cursor_color.cursor);
|
||||
fg = color_hex_to_pixman(term->cursor_color.text);
|
||||
bg = color_hex_to_pixman(term->cursor_color.cursor);
|
||||
}
|
||||
|
||||
struct font *font = attrs_to_font(term, &cell->attrs);
|
||||
const struct glyph *glyph = font_glyph_for_wc(font, cell->wc);
|
||||
|
||||
int cell_cols = glyph != NULL ? max(1, glyph->width) : 1;
|
||||
int cell_cols = glyph != NULL ? max(1, glyph->cols) : 1;
|
||||
|
||||
/* Background */
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_source_rgba(cr, bg.r, bg.g, bg.b, block_cursor ? 1.0 : term->colors.alpha);
|
||||
cairo_rectangle(cr, x, y, cell_cols * width, height);
|
||||
cairo_fill(cr);
|
||||
pixman_image_fill_rectangles(
|
||||
PIXMAN_OP_SRC, pix, &bg, 1,
|
||||
&(pixman_rectangle16_t){x, y, cell_cols * width, height});
|
||||
|
||||
/* Non-block cursors */
|
||||
if (has_cursor) {
|
||||
#if 1
|
||||
struct rgb cursor_color = term->cursor_color.text >> 31
|
||||
? color_hex_to_rgb(term->cursor_color.cursor)
|
||||
: fg;
|
||||
: color_hex_to_rgb(_fg);
|
||||
#endif
|
||||
|
||||
if (term->cursor_style == CURSOR_BAR)
|
||||
draw_bar(term, cr, cursor_color, x, y);
|
||||
|
|
@ -215,36 +235,32 @@ render_cell(struct terminal *term, cairo_t *cr,
|
|||
return cell_cols;
|
||||
|
||||
if (glyph != NULL) {
|
||||
cairo_save(cr);
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
|
||||
|
||||
double fixup = glyph->pixel_size_fixup;
|
||||
cairo_translate(
|
||||
cr,
|
||||
x + glyph->left / fixup,
|
||||
y + term->fextents.ascent - glyph->top * fixup);
|
||||
cairo_scale(cr, fixup, fixup);
|
||||
|
||||
if (cairo_image_surface_get_format(glyph->surf) == CAIRO_FORMAT_ARGB32) {
|
||||
if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) {
|
||||
/* Glyph surface is a pre-rendered image (typically a color emoji...) */
|
||||
if (!(cell->attrs.blink && term->blink.state == BLINK_OFF)) {
|
||||
cairo_set_source_surface(cr, glyph->surf, 0, 0);
|
||||
cairo_paint(cr);
|
||||
pixman_image_composite(
|
||||
PIXMAN_OP_OVER, glyph->pix, NULL, pix, 0, 0, 0, 0,
|
||||
x + glyph->x, y + term->fextents.ascent - glyph->y,
|
||||
glyph->width, glyph->height);
|
||||
}
|
||||
} else {
|
||||
/* Glyph surface is an alpha mask */
|
||||
cairo_set_source_rgb(cr, fg.r, fg.g, fg.b);
|
||||
cairo_mask_surface(cr, glyph->surf, 0, 0);
|
||||
/* TODO: cache */
|
||||
pixman_image_t *src = pixman_image_create_solid_fill(&fg);
|
||||
pixman_image_composite(
|
||||
PIXMAN_OP_OVER, src, glyph->pix, pix, 0, 0, 0, 0,
|
||||
x + glyph->x, y + term->fextents.ascent - glyph->y,
|
||||
glyph->width, glyph->height);
|
||||
pixman_image_unref(src);
|
||||
}
|
||||
cairo_restore(cr);
|
||||
}
|
||||
|
||||
/* Underline */
|
||||
if (cell->attrs.underline)
|
||||
draw_underline(term, cr, attrs_to_font(term, &cell->attrs), fg, x, y, cell_cols);
|
||||
draw_underline(term, cr, attrs_to_font(term, &cell->attrs), color_hex_to_rgb(_fg), x, y, cell_cols);
|
||||
|
||||
if (cell->attrs.strikethrough)
|
||||
draw_strikeout(term, cr, attrs_to_font(term, &cell->attrs), fg, x, y, cell_cols);
|
||||
draw_strikeout(term, cr, attrs_to_font(term, &cell->attrs), color_hex_to_rgb(_fg), x, y, cell_cols);
|
||||
|
||||
return cell_cols;
|
||||
}
|
||||
|
|
@ -258,21 +274,18 @@ grid_render_scroll(struct terminal *term, struct buffer *buf,
|
|||
int width = buf->width;
|
||||
int height = (dmg->scroll.region.end - dmg->scroll.region.start - dmg->scroll.lines) * term->cell_height;
|
||||
|
||||
const uint32_t stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
|
||||
|
||||
LOG_DBG("damage: SCROLL: %d-%d by %d lines (dst-y: %d, src-y: %d, "
|
||||
"height: %d, stride: %d, mmap-size: %zu)",
|
||||
dmg->scroll.region.start, dmg->scroll.region.end,
|
||||
dmg->scroll.lines,
|
||||
dst_y, src_y, height, stride,
|
||||
dst_y, src_y, height, buf->stride,
|
||||
buf->size);
|
||||
|
||||
if (height > 0) {
|
||||
cairo_surface_flush(buf->cairo_surface[0]);
|
||||
uint8_t *raw = cairo_image_surface_get_data(buf->cairo_surface[0]);
|
||||
|
||||
memmove(raw + dst_y * stride, raw + src_y * stride, height * stride);
|
||||
cairo_surface_mark_dirty(buf->cairo_surface[0]);
|
||||
uint8_t *raw = buf->mmapped;
|
||||
memmove(raw + dst_y * buf->stride,
|
||||
raw + src_y * buf->stride,
|
||||
height * buf->stride);
|
||||
|
||||
wl_surface_damage_buffer(term->wl.surface, 0, dst_y, width, height);
|
||||
}
|
||||
|
|
@ -287,31 +300,28 @@ grid_render_scroll_reverse(struct terminal *term, struct buffer *buf,
|
|||
int width = buf->width;
|
||||
int height = (dmg->scroll.region.end - dmg->scroll.region.start - dmg->scroll.lines) * term->cell_height;
|
||||
|
||||
const uint32_t stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
|
||||
|
||||
LOG_DBG("damage: SCROLL REVERSE: %d-%d by %d lines (dst-y: %d, src-y: %d, "
|
||||
"height: %d, stride: %d, mmap-size: %zu)",
|
||||
dmg->scroll.region.start, dmg->scroll.region.end,
|
||||
dmg->scroll.lines,
|
||||
dst_y, src_y, height, stride,
|
||||
dst_y, src_y, height, buf->stride,
|
||||
buf->size);
|
||||
|
||||
if (height > 0) {
|
||||
cairo_surface_flush(buf->cairo_surface[0]);
|
||||
uint8_t *raw = cairo_image_surface_get_data(buf->cairo_surface[0]);
|
||||
|
||||
memmove(raw + dst_y * stride, raw + src_y * stride, height * stride);
|
||||
cairo_surface_mark_dirty(buf->cairo_surface[0]);
|
||||
uint8_t *raw = buf->mmapped;
|
||||
memmove(raw + dst_y * buf->stride,
|
||||
raw + src_y * buf->stride,
|
||||
height * buf->stride);
|
||||
|
||||
wl_surface_damage_buffer(term->wl.surface, 0, dst_y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
render_row(struct terminal *term, cairo_t *cr, struct row *row, int row_no)
|
||||
render_row(struct terminal *term, cairo_t *cr, pixman_image_t *pix, struct row *row, int row_no)
|
||||
{
|
||||
for (int col = term->cols - 1; col >= 0; col--)
|
||||
render_cell(term, cr, &row->cells[col], col, row_no, false);
|
||||
render_cell(term, cr, pix, &row->cells[col], col, row_no, false);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -349,7 +359,7 @@ render_worker_thread(void *_ctx)
|
|||
switch (row_no) {
|
||||
default:
|
||||
assert(buf != NULL);
|
||||
render_row(term, buf->cairo[my_id], grid_row_in_view(term->grid, row_no), row_no);
|
||||
render_row(term, buf->cairo[my_id], buf->pix[my_id], grid_row_in_view(term->grid, row_no), row_no);
|
||||
break;
|
||||
|
||||
case -1:
|
||||
|
|
@ -389,6 +399,7 @@ grid_render(struct terminal *term)
|
|||
struct buffer *buf = shm_get_buffer(term->wl.shm, term->width, term->height, 1 + term->render.workers.count);
|
||||
cairo_t *cr = buf->cairo[0];
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
||||
pixman_image_t *pix = buf->pix[0];
|
||||
|
||||
bool all_clean = tll_length(term->grid->scroll_damage) == 0;
|
||||
|
||||
|
|
@ -399,7 +410,7 @@ grid_render(struct terminal *term)
|
|||
|
||||
if (cell->attrs.clean) {
|
||||
cell->attrs.clean = 0;
|
||||
render_cell(term, cr, cell, at.col, at.row, false);
|
||||
render_cell(term, cr, pix, cell, at.col, at.row, false);
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->wl.surface,
|
||||
|
|
@ -504,7 +515,7 @@ grid_render(struct terminal *term)
|
|||
if (!row->dirty)
|
||||
continue;
|
||||
|
||||
render_row(term, cr, row, r);
|
||||
render_row(term, cr, pix, row, r);
|
||||
|
||||
row->dirty = false;
|
||||
all_clean = false;
|
||||
|
|
@ -590,7 +601,7 @@ grid_render(struct terminal *term)
|
|||
cell->attrs.clean = 0;
|
||||
term->render.last_cursor.cell = cell;
|
||||
int cols_updated = render_cell(
|
||||
term, cr, cell, term->cursor.col, view_aligned_row, true);
|
||||
term, cr, pix, cell, term->cursor.col, view_aligned_row, true);
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->wl.surface,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue