diff --git a/config.c b/config.c index 2bb04a65..eb9031ed 100644 --- a/config.c +++ b/config.c @@ -224,7 +224,7 @@ parse_section_colors(const char *key, const char *value, struct config *conf, return false; } - conf->colors.alpha = alpha; + conf->colors.alpha = alpha * 65535.; return true; } @@ -466,7 +466,7 @@ config_load(struct config *conf) default_bright[6], default_bright[7], }, - .alpha = 1., + .alpha = 0xffff, }, .cursor = { diff --git a/config.h b/config.h index cc17c8e2..e7158688 100644 --- a/config.h +++ b/config.h @@ -18,7 +18,7 @@ struct config { uint32_t bg; uint32_t regular[8]; uint32_t bright[8]; - double alpha; + uint16_t alpha; } colors; struct { diff --git a/font.h b/font.h index d0ebb5bb..97c3ec5f 100644 --- a/font.h +++ b/font.h @@ -41,13 +41,13 @@ struct font { double pixel_size_fixup; /* Scale factor - should only be used with ARGB32 glyphs */ struct { - double position; - double thickness; + int position; + int thickness; } underline; struct { - double position; - double thickness; + int position; + int thickness; } strikeout; bool is_fallback; diff --git a/main.c b/main.c index 943a3d32..7fd2b2de 100644 --- a/main.c +++ b/main.c @@ -555,8 +555,8 @@ main(int argc, char *const *argv) LOG_DBG("ft: x-scale: %f, height: %f, descent: %f", x_scale, height, descent); - f->underline.position = ft_face->underline_position * x_scale / 64.; - f->underline.thickness = ft_face->underline_thickness * x_scale / 64.; + f->underline.position = round(ft_face->underline_position * x_scale / 64.); + f->underline.thickness = ceil(ft_face->underline_thickness * x_scale / 64.); if (f->underline.position == 0.) { f->underline.position = descent / 2.; diff --git a/render.c b/render.c index 147583d4..cefff04b 100644 --- a/render.c +++ b/render.c @@ -37,15 +37,23 @@ color_hex_to_rgb(uint32_t color) }; } +static inline pixman_color_t +color_hex_to_pixman_with_alpha(uint32_t color, uint16_t alpha) +{ + int alpha_div = 0xffff / alpha; + return (pixman_color_t){ + .red = ((color >> 16 & 0xff) | (color >> 8 & 0xff00)) / alpha_div, + .green = ((color >> 8 & 0xff) | (color >> 0 & 0xff00)) / alpha_div, + .blue = ((color >> 0 & 0xff) | (color << 8 & 0xff00)) / alpha_div, + .alpha = alpha, + }; +} + 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, - }; + /* Count on the compiler optimizing this */ + return color_hex_to_pixman_with_alpha(color, 0xffff); } static inline void @@ -65,47 +73,41 @@ pixman_color_dim(pixman_color_t *color) } static void -draw_underline(const struct terminal *term, cairo_t *cr, const struct font *font, - struct rgb color, double x, double y, int cols) +draw_bar(const struct terminal *term, pixman_image_t *pix, + const pixman_color_t *color, int x, int y) { - double baseline = y + term->fextents.height - term->fextents.descent; - double width = font->underline.thickness; - double y_under = baseline - font->underline.position - width / 2.; - - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgb(cr, color.r, color.g, color.b); - cairo_set_line_width(cr, width); - cairo_move_to(cr, x, round(y_under) + 0.5); - cairo_rel_line_to(cr, cols * term->cell_width, 0); - cairo_stroke(cr); + /* TODO: investigate if this is the best way */ + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, color, + 1, &(pixman_rectangle16_t){x, y, 1, term->cell_height}); } static void -draw_bar(const struct terminal *term, cairo_t *cr, struct rgb color, - double x, double y) +draw_underline(const struct terminal *term, pixman_image_t *pix, + const struct font *font, + const pixman_color_t *color, int x, int y, int cols) { - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgb(cr, color.r, color.g, color.b); - cairo_set_line_width(cr, 1.0); - cairo_move_to(cr, x + 0.5, y); - cairo_rel_line_to(cr, 0, term->cell_height); - cairo_stroke(cr); + int baseline = y + term->fextents.height - term->fextents.descent; + int width = font->underline.thickness; + int y_under = baseline - font->underline.position - width / 2; + + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, color, + 1, &(pixman_rectangle16_t){x, y_under, cols * term->cell_width, width}); } static void -draw_strikeout(const struct terminal *term, cairo_t *cr, const struct font *font, - struct rgb color, double x, double y, int cols) +draw_strikeout(const struct terminal *term, pixman_image_t *pix, + const struct font *font, + const pixman_color_t *color, int x, int y, int cols) { - double baseline = y + term->fextents.height - term->fextents.descent; - double width = font->strikeout.thickness; - double y_strike = baseline - font->strikeout.position - width / 2.; + int baseline = y + term->fextents.height - term->fextents.descent; + int width = font->strikeout.thickness; + int y_strike = baseline - font->strikeout.position - width / 2; - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgb(cr, color.r, color.g, color.b); - cairo_set_line_width(cr, width); - cairo_move_to(cr, x, round(y_strike) + 0.5); - cairo_rel_line_to(cr, cols * term->cell_width, 0); - cairo_stroke(cr); + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, color, + 1, &(pixman_rectangle16_t){x, y_strike, cols * term->cell_width, width}); } static bool @@ -155,7 +157,7 @@ arm_blink_timer(struct terminal *term) } static int -render_cell(struct terminal *term, cairo_t *cr, pixman_image_t *pix, +render_cell(struct terminal *term, pixman_image_t *pix, struct cell *cell, int col, int row, bool has_cursor) { if (cell->attrs.clean) @@ -163,10 +165,10 @@ render_cell(struct terminal *term, cairo_t *cr, pixman_image_t *pix, cell->attrs.clean = 1; - double width = term->cell_width; - double height = term->cell_height; - double x = col * width; - double y = row * height; + int width = term->cell_width; + int height = term->cell_height; + int x = col * width; + int y = row * height; bool block_cursor = has_cursor && term->cursor_style == CURSOR_BLOCK; bool is_selected = coord_is_selected(term, col, row); @@ -189,7 +191,8 @@ render_cell(struct terminal *term, cairo_t *cr, pixman_image_t *pix, _fg = _bg; pixman_color_t fg = color_hex_to_pixman(_fg); - pixman_color_t bg = color_hex_to_pixman(_bg); + pixman_color_t bg = color_hex_to_pixman_with_alpha( + _bg, block_cursor ? 0xffff : term->colors.alpha); if (cell->attrs.dim) pixman_color_dim(&fg); @@ -213,17 +216,16 @@ render_cell(struct terminal *term, cairo_t *cr, pixman_image_t *pix, /* 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) - : color_hex_to_rgb(_fg); -#endif + pixman_color_t cursor_color = term->cursor_color.text >> 31 + ? color_hex_to_pixman(term->cursor_color.cursor) + : color_hex_to_pixman(_fg); if (term->cursor_style == CURSOR_BAR) - draw_bar(term, cr, cursor_color, x, y); + draw_bar(term, pix, &cursor_color, x, y); else if (term->cursor_style == CURSOR_UNDERLINE) draw_underline( - term, cr, attrs_to_font(term, &cell->attrs), cursor_color, x, y, cell_cols); + term, pix, attrs_to_font(term, &cell->attrs), &cursor_color, + x, y, cell_cols); } if (cell->attrs.blink && !term->blink.active) { @@ -256,11 +258,17 @@ render_cell(struct terminal *term, cairo_t *cr, pixman_image_t *pix, } /* Underline */ - if (cell->attrs.underline) - draw_underline(term, cr, attrs_to_font(term, &cell->attrs), color_hex_to_rgb(_fg), x, y, cell_cols); + if (cell->attrs.underline) { + pixman_color_t color = color_hex_to_pixman(_fg); + draw_underline(term, pix, attrs_to_font(term, &cell->attrs), + &color, x, y, cell_cols); + } - if (cell->attrs.strikethrough) - draw_strikeout(term, cr, attrs_to_font(term, &cell->attrs), color_hex_to_rgb(_fg), x, y, cell_cols); + if (cell->attrs.strikethrough) { + pixman_color_t color = color_hex_to_pixman(_fg); + draw_strikeout(term, pix, attrs_to_font(term, &cell->attrs), + &color, x, y, cell_cols); + } return cell_cols; } @@ -318,10 +326,10 @@ grid_render_scroll_reverse(struct terminal *term, struct buffer *buf, } static void -render_row(struct terminal *term, cairo_t *cr, pixman_image_t *pix, struct row *row, int row_no) +render_row(struct terminal *term, pixman_image_t *pix, struct row *row, int row_no) { for (int col = term->cols - 1; col >= 0; col--) - render_cell(term, cr, pix, &row->cells[col], col, row_no, false); + render_cell(term, pix, &row->cells[col], col, row_no, false); } int @@ -359,7 +367,7 @@ render_worker_thread(void *_ctx) switch (row_no) { default: assert(buf != NULL); - render_row(term, buf->cairo[my_id], buf->pix[my_id], grid_row_in_view(term->grid, row_no), row_no); + render_row(term, buf->pix[my_id], grid_row_in_view(term->grid, row_no), row_no); break; case -1: @@ -397,8 +405,6 @@ grid_render(struct terminal *term) assert(term->height > 0); 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; @@ -410,7 +416,7 @@ grid_render(struct terminal *term) if (cell->attrs.clean) { cell->attrs.clean = 0; - render_cell(term, cr, pix, cell, at.col, at.row, false); + render_cell(term, pix, cell, at.col, at.row, false); wl_surface_damage_buffer( term->wl.surface, @@ -442,12 +448,15 @@ grid_render(struct terminal *term) int bmargin_height = term->height - bmargin; uint32_t _bg = !term->reverse ? term->colors.bg : term->colors.fg; - struct rgb bg = color_hex_to_rgb(_bg); - cairo_set_source_rgba(buf->cairo[0], bg.r, bg.g, bg.b, term->colors.alpha); - cairo_rectangle(buf->cairo[0], rmargin, 0, rmargin_width, term->height); - cairo_rectangle(buf->cairo[0], 0, bmargin, term->width, bmargin_height); - cairo_fill(buf->cairo[0]); + pixman_color_t bg = color_hex_to_pixman_with_alpha(_bg, term->colors.alpha); + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, &bg, 1, + &(pixman_rectangle16_t){rmargin, 0, rmargin_width, term->height}); + + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, &bg, 1, + &(pixman_rectangle16_t){0, bmargin, term->width, bmargin_height}); wl_surface_damage_buffer( term->wl.surface, rmargin, 0, rmargin_width, term->height); @@ -515,7 +524,7 @@ grid_render(struct terminal *term) if (!row->dirty) continue; - render_row(term, cr, pix, row, r); + render_row(term, pix, row, r); row->dirty = false; all_clean = false; @@ -601,7 +610,7 @@ grid_render(struct terminal *term) cell->attrs.clean = 0; term->render.last_cursor.cell = cell; int cols_updated = render_cell( - term, cr, pix, cell, term->cursor.col, view_aligned_row, true); + term, pix, cell, term->cursor.col, view_aligned_row, true); wl_surface_damage_buffer( term->wl.surface, @@ -616,10 +625,11 @@ grid_render(struct terminal *term) } if (term->flash.active) { - cairo_set_source_rgba(buf->cairo[0], 1.0, 1.0, 0.0, 0.5); - cairo_set_operator(buf->cairo[0], CAIRO_OPERATOR_OVER); - cairo_rectangle(buf->cairo[0], 0, 0, term->width, term->height); - cairo_fill(buf->cairo[0]); + /* Note: alpha is pre-computed in each color component */ + pixman_image_fill_rectangles( + PIXMAN_OP_OVER, pix, + &(pixman_color_t){.red=0x7fff, .green=0x7fff, .blue=0, .alpha=0x7fff}, + 1, &(pixman_rectangle16_t){0, 0, term->width, term->height}); wl_surface_damage_buffer( term->wl.surface, 0, 0, term->width, term->height); @@ -628,7 +638,6 @@ grid_render(struct terminal *term) assert(term->grid->offset >= 0 && term->grid->offset < term->grid->num_rows); assert(term->grid->view >= 0 && term->grid->view < term->grid->num_rows); - cairo_surface_flush(buf->cairo_surface[0]); wl_surface_attach(term->wl.surface, buf->wl_buf, 0, 0); assert(term->render.frame_callback == NULL);