mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-08 10:06:22 -05:00
Merge branch 'pixman'
This commit is contained in:
commit
d21c4a02a0
12 changed files with 205 additions and 209 deletions
3
PKGBUILD
3
PKGBUILD
|
|
@ -9,7 +9,7 @@ makedepends=('meson' 'ninja' 'scdoc')
|
|||
depends=(
|
||||
'libxkbcommon'
|
||||
'wayland'
|
||||
'freetype2' 'fontconfig' 'cairo')
|
||||
'freetype2' 'fontconfig' 'pixman')
|
||||
source=()
|
||||
|
||||
pkgver() {
|
||||
|
|
@ -25,4 +25,3 @@ build() {
|
|||
package() {
|
||||
DESTDIR="${pkgdir}/" ninja install
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
* fontconfig
|
||||
* freetype
|
||||
* cairo
|
||||
* pixman
|
||||
* wayland (_client_ and _cursor_ libraries)
|
||||
* wayland protocols
|
||||
* xkbcommon
|
||||
|
|
|
|||
4
config.c
4
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 = {
|
||||
|
|
|
|||
2
config.h
2
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 {
|
||||
|
|
|
|||
54
font.c
54
font.c
|
|
@ -367,19 +367,26 @@ glyph_for_wchar(struct font *font, wchar_t wc, struct glyph *glyph)
|
|||
if (bitmap->width == 0)
|
||||
goto err;
|
||||
|
||||
/* Map FT pixel format to cairo surface format */
|
||||
cairo_format_t cr_format =
|
||||
bitmap->pixel_mode == FT_PIXEL_MODE_MONO ? CAIRO_FORMAT_A1 :
|
||||
bitmap->pixel_mode == FT_PIXEL_MODE_GRAY ? CAIRO_FORMAT_A8 :
|
||||
bitmap->pixel_mode == FT_PIXEL_MODE_BGRA ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_INVALID;
|
||||
/* Map FT pixel format to pixman format */
|
||||
pixman_format_code_t pix_format =
|
||||
bitmap->pixel_mode == FT_PIXEL_MODE_MONO ? PIXMAN_a1 :
|
||||
bitmap->pixel_mode == FT_PIXEL_MODE_GRAY ? PIXMAN_a8 :
|
||||
bitmap->pixel_mode == FT_PIXEL_MODE_BGRA ? PIXMAN_a8r8g8b8 : -1;
|
||||
|
||||
int stride = cairo_format_stride_for_width(cr_format, bitmap->width);
|
||||
/* Calculate stride. Copied from cairoint.h:CAIRO_STRIDE_FOR_WIDTH_BPP */
|
||||
int bpp =
|
||||
pix_format == PIXMAN_a1 ? 1 :
|
||||
pix_format == PIXMAN_a8 ? 8 :
|
||||
pix_format == PIXMAN_a8r8g8b8 ? 32 : -1;
|
||||
assert(bpp >= 0);
|
||||
|
||||
int stride = (((bpp * bitmap->width + 7) / 8 + 4 - 1) & -4);
|
||||
assert(stride >= bitmap->pitch);
|
||||
|
||||
uint8_t *data = malloc(bitmap->rows * stride);
|
||||
assert(bitmap->pitch >= 0);
|
||||
|
||||
/* Convert FT bitmap to cairo surface (well, the backing image) */
|
||||
/* Convert FT bitmap to pixman image */
|
||||
switch (bitmap->pixel_mode) {
|
||||
case FT_PIXEL_MODE_MONO:
|
||||
for (size_t r = 0; r < bitmap->rows; r++) {
|
||||
|
|
@ -413,22 +420,31 @@ glyph_for_wchar(struct font *font, wchar_t wc, struct glyph *glyph)
|
|||
goto err;
|
||||
}
|
||||
|
||||
cairo_surface_t *surf = cairo_image_surface_create_for_data(
|
||||
data, cr_format, bitmap->width, bitmap->rows, stride);
|
||||
pixman_image_t *pix = pixman_image_create_bits_no_clear(
|
||||
pix_format, bitmap->width, bitmap->rows, (uint32_t *)data, stride);
|
||||
|
||||
if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
|
||||
if (pix == NULL) {
|
||||
free(data);
|
||||
cairo_surface_destroy(surf);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (font->pixel_size_fixup != 1.) {
|
||||
struct pixman_transform scale;
|
||||
pixman_transform_init_scale(
|
||||
&scale,
|
||||
pixman_double_to_fixed(1. / font->pixel_size_fixup),
|
||||
pixman_double_to_fixed(1. / font->pixel_size_fixup));
|
||||
pixman_image_set_transform(pix, &scale);
|
||||
}
|
||||
|
||||
*glyph = (struct glyph){
|
||||
.wc = wc,
|
||||
.width = wcwidth(wc),
|
||||
.surf = surf,
|
||||
.left = font->face->glyph->bitmap_left,
|
||||
.top = font->face->glyph->bitmap_top,
|
||||
.pixel_size_fixup = font->pixel_size_fixup,
|
||||
.cols = wcwidth(wc),
|
||||
.pix = pix,
|
||||
.x = font->face->glyph->bitmap_left / font->pixel_size_fixup,
|
||||
.y = font->face->glyph->bitmap_top * font->pixel_size_fixup,
|
||||
.width = bitmap->width,
|
||||
.height = bitmap->rows,
|
||||
.valid = true,
|
||||
};
|
||||
|
||||
|
|
@ -506,10 +522,8 @@ font_destroy(struct font *font)
|
|||
if (!it->item.valid)
|
||||
continue;
|
||||
|
||||
cairo_surface_flush(it->item.surf);
|
||||
void *image = cairo_image_surface_get_data(it->item.surf);
|
||||
|
||||
cairo_surface_destroy(it->item.surf);
|
||||
void *image = pixman_image_get_data(it->item.pix);
|
||||
pixman_image_unref(it->item.pix);
|
||||
free(image);
|
||||
}
|
||||
|
||||
|
|
|
|||
21
font.h
21
font.h
|
|
@ -7,7 +7,7 @@
|
|||
#include FT_FREETYPE_H
|
||||
#include FT_LCD_FILTER_H
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include <cairo.h>
|
||||
#include <pixman.h>
|
||||
|
||||
#include "tllist.h"
|
||||
//#include "terminal.h"
|
||||
|
|
@ -16,13 +16,14 @@ typedef tll(const char *) font_list_t;
|
|||
|
||||
struct glyph {
|
||||
wchar_t wc;
|
||||
int cols;
|
||||
|
||||
pixman_image_t *pix;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
cairo_surface_t *surf;
|
||||
int left;
|
||||
int top;
|
||||
|
||||
double pixel_size_fixup;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
|
|
@ -40,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;
|
||||
|
|
|
|||
6
main.c
6
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.;
|
||||
|
|
@ -1085,8 +1085,6 @@ out:
|
|||
tll_free(term.render.workers.queue);
|
||||
|
||||
config_free(conf);
|
||||
|
||||
cairo_debug_reset_static_data();
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,8 +42,9 @@ cc = meson.get_compiler('c')
|
|||
math = cc.find_library('m')
|
||||
|
||||
threads = dependency('threads')
|
||||
freetype = dependency('freetype2')
|
||||
fontconfig = dependency('fontconfig')
|
||||
cairo = dependency('cairo')
|
||||
pixman = dependency('pixman-1')
|
||||
wayland_protocols = dependency('wayland-protocols')
|
||||
wayland_client = dependency('wayland-client')
|
||||
wayland_cursor = dependency('wayland-cursor')
|
||||
|
|
@ -99,7 +100,7 @@ executable(
|
|||
'tllist.h',
|
||||
'vt.c', 'vt.h',
|
||||
wl_proto_src + wl_proto_headers,
|
||||
dependencies: [threads, math, cairo, fontconfig, wayland_client, wayland_cursor, xkb],
|
||||
dependencies: [threads, math, freetype, fontconfig, pixman, wayland_client, wayland_cursor, xkb],
|
||||
install: true)
|
||||
|
||||
custom_target(
|
||||
|
|
|
|||
232
render.c
232
render.c
|
|
@ -37,6 +37,25 @@ 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)
|
||||
{
|
||||
/* Count on the compiler optimizing this */
|
||||
return color_hex_to_pixman_with_alpha(color, 0xffff);
|
||||
}
|
||||
|
||||
static inline void
|
||||
color_dim(struct rgb *rgb)
|
||||
{
|
||||
|
|
@ -45,48 +64,50 @@ color_dim(struct rgb *rgb)
|
|||
rgb->b /= 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)
|
||||
static inline void
|
||||
pixman_color_dim(pixman_color_t *color)
|
||||
{
|
||||
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);
|
||||
color->red /= 2;
|
||||
color->green /= 2;
|
||||
color->blue /= 2;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_bar(const struct terminal *term, cairo_t *cr, struct rgb color,
|
||||
double x, double y)
|
||||
draw_bar(const struct terminal *term, pixman_image_t *pix,
|
||||
const pixman_color_t *color, int x, int y)
|
||||
{
|
||||
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);
|
||||
/* 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_strikeout(const struct terminal *term, cairo_t *cr, const struct font *font,
|
||||
struct rgb color, double x, double y, int cols)
|
||||
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)
|
||||
{
|
||||
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->underline.thickness;
|
||||
int 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_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_under, cols * term->cell_width, width});
|
||||
}
|
||||
|
||||
static void
|
||||
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)
|
||||
{
|
||||
int baseline = y + term->fextents.height - term->fextents.descent;
|
||||
int width = font->strikeout.thickness;
|
||||
int y_strike = baseline - font->strikeout.position - width / 2;
|
||||
|
||||
pixman_image_fill_rectangles(
|
||||
PIXMAN_OP_SRC, pix, color,
|
||||
1, &(pixman_rectangle16_t){x, y_strike, cols * term->cell_width, width});
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -136,7 +157,7 @@ arm_blink_timer(struct terminal *term)
|
|||
}
|
||||
|
||||
static int
|
||||
render_cell(struct terminal *term, cairo_t *cr,
|
||||
render_cell(struct terminal *term, pixman_image_t *pix,
|
||||
struct cell *cell, int col, int row, bool has_cursor)
|
||||
{
|
||||
if (cell->attrs.clean)
|
||||
|
|
@ -144,10 +165,10 @@ render_cell(struct terminal *term, cairo_t *cr,
|
|||
|
||||
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);
|
||||
|
|
@ -169,41 +190,42 @@ 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_with_alpha(
|
||||
_bg, block_cursor ? 0xffff : term->colors.alpha);
|
||||
|
||||
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) {
|
||||
struct rgb cursor_color = term->cursor_color.text >> 31
|
||||
? color_hex_to_rgb(term->cursor_color.cursor)
|
||||
: fg;
|
||||
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) {
|
||||
|
|
@ -215,36 +237,38 @@ 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);
|
||||
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), 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;
|
||||
}
|
||||
|
|
@ -258,21 +282,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 +308,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, 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, pix, &row->cells[col], col, row_no, false);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -349,7 +367,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->pix, grid_row_in_view(term->grid, row_no), row_no);
|
||||
break;
|
||||
|
||||
case -1:
|
||||
|
|
@ -387,8 +405,7 @@ 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;
|
||||
|
||||
bool all_clean = tll_length(term->grid->scroll_damage) == 0;
|
||||
|
||||
|
|
@ -399,7 +416,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, pix, cell, at.col, at.row, false);
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->wl.surface,
|
||||
|
|
@ -431,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);
|
||||
|
|
@ -504,7 +524,7 @@ grid_render(struct terminal *term)
|
|||
if (!row->dirty)
|
||||
continue;
|
||||
|
||||
render_row(term, cr, row, r);
|
||||
render_row(term, pix, row, r);
|
||||
|
||||
row->dirty = false;
|
||||
all_clean = false;
|
||||
|
|
@ -590,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, 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,
|
||||
|
|
@ -605,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);
|
||||
|
|
@ -617,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);
|
||||
|
|
|
|||
73
shm.c
73
shm.c
|
|
@ -7,6 +7,8 @@
|
|||
#include <sys/mman.h>
|
||||
#include <linux/memfd.h>
|
||||
|
||||
#include <pixman.h>
|
||||
|
||||
#define LOG_MODULE "shm"
|
||||
#include "log.h"
|
||||
#include "tllist.h"
|
||||
|
|
@ -45,11 +47,10 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies)
|
|||
* No existing buffer available. Create a new one by:
|
||||
*
|
||||
* 1. open a memory backed "file" with memfd_create()
|
||||
* 2. mmap() the memory file, to be used by the cairo surface
|
||||
* 2. mmap() the memory file, to be used by the pixman image
|
||||
* 3. create a wayland shm buffer for the same memory file
|
||||
*
|
||||
* The cairo surface and the wayland buffer are now sharing
|
||||
* memory.
|
||||
* The pixman image and the wayland buffer are now sharing memory.
|
||||
*/
|
||||
|
||||
int pool_fd = -1;
|
||||
|
|
@ -59,8 +60,7 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies)
|
|||
struct wl_shm_pool *pool = NULL;
|
||||
struct wl_buffer *buf = NULL;
|
||||
|
||||
cairo_surface_t **cairo_surface = NULL;
|
||||
cairo_t **cairo = NULL;
|
||||
pixman_image_t *pix = NULL;
|
||||
|
||||
/* Backing memory for SHM */
|
||||
pool_fd = memfd_create("f00sel-wayland-shm-buffer-pool", MFD_CLOEXEC);
|
||||
|
|
@ -69,8 +69,12 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies)
|
|||
goto err;
|
||||
}
|
||||
|
||||
/* TODO: copied from font.c */
|
||||
/* Calculate stride. Copied from cairoint.h:CAIRO_STRIDE_FOR_WIDTH_BPP */
|
||||
int bpp = 32;
|
||||
const int stride = (((bpp * width + 7) / 8 + 4 - 1) & -4);
|
||||
|
||||
/* Total size */
|
||||
const uint32_t stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
|
||||
size = stride * height;
|
||||
if (ftruncate(pool_fd, size) == -1) {
|
||||
LOG_ERRNO("failed to truncate SHM pool");
|
||||
|
|
@ -100,27 +104,9 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies)
|
|||
wl_shm_pool_destroy(pool); pool = NULL;
|
||||
close(pool_fd); pool_fd = -1;
|
||||
|
||||
/* Create a cairo surface around the mmapped memory */
|
||||
cairo_surface = calloc(copies, sizeof(cairo_surface[0]));
|
||||
cairo = calloc(copies, sizeof(cairo[0]));
|
||||
|
||||
for (size_t i = 0; i < copies; i++) {
|
||||
cairo_surface[i] = cairo_image_surface_create_for_data(
|
||||
mmapped, CAIRO_FORMAT_ARGB32, width, height, stride);
|
||||
|
||||
if (cairo_surface_status(cairo_surface[i]) != CAIRO_STATUS_SUCCESS) {
|
||||
LOG_ERR("failed to create cairo surface: %s",
|
||||
cairo_status_to_string(cairo_surface_status(cairo_surface[i])));
|
||||
goto err;
|
||||
}
|
||||
|
||||
cairo[i] = cairo_create(cairo_surface[i]);
|
||||
if (cairo_status(cairo[i]) != CAIRO_STATUS_SUCCESS) {
|
||||
LOG_ERR("failed to create cairo context: %s",
|
||||
cairo_status_to_string(cairo_status(cairo[i])));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
/* One pixman image for each worker thread (do we really need multiple?) */
|
||||
pix = pixman_image_create_bits_no_clear(
|
||||
PIXMAN_a8r8g8b8, width, height, (uint32_t *)mmapped, stride);
|
||||
|
||||
/* Push to list of available buffers, but marked as 'busy' */
|
||||
tll_push_back(
|
||||
|
|
@ -128,13 +114,12 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies)
|
|||
((struct buffer){
|
||||
.width = width,
|
||||
.height = height,
|
||||
.stride = stride,
|
||||
.busy = true,
|
||||
.size = size,
|
||||
.mmapped = mmapped,
|
||||
.wl_buf = buf,
|
||||
.copies = copies,
|
||||
.cairo_surface = cairo_surface,
|
||||
.cairo = cairo}
|
||||
.pix = pix}
|
||||
)
|
||||
);
|
||||
|
||||
|
|
@ -143,18 +128,8 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies)
|
|||
return ret;
|
||||
|
||||
err:
|
||||
if (cairo != NULL) {
|
||||
for (size_t i = 0; i < copies; i++)
|
||||
if (cairo[i] != NULL)
|
||||
cairo_destroy(cairo[i]);
|
||||
free(cairo);
|
||||
}
|
||||
if (cairo_surface != NULL) {
|
||||
for (size_t i = 0; i < copies; i++)
|
||||
if (cairo_surface[i] != NULL)
|
||||
cairo_surface_destroy(cairo_surface[i]);
|
||||
free(cairo_surface);
|
||||
}
|
||||
if (pix != NULL)
|
||||
pixman_image_unref(pix);
|
||||
if (buf != NULL)
|
||||
wl_buffer_destroy(buf);
|
||||
if (pool != NULL)
|
||||
|
|
@ -173,18 +148,8 @@ shm_fini(void)
|
|||
tll_foreach(buffers, it) {
|
||||
struct buffer *buf = &it->item;
|
||||
|
||||
if (buf->cairo != NULL) {
|
||||
for (size_t i = 0; i < buf->copies; i++)
|
||||
if (buf->cairo[i] != NULL)
|
||||
cairo_destroy(buf->cairo[i]);
|
||||
free(buf->cairo);
|
||||
}
|
||||
if (buf->cairo_surface != NULL) {
|
||||
for (size_t i = 0; i < buf->copies; i++)
|
||||
if (buf->cairo_surface[i] != NULL)
|
||||
cairo_surface_destroy(buf->cairo_surface[i]);
|
||||
free(buf->cairo_surface);
|
||||
}
|
||||
if (buf->pix != NULL)
|
||||
pixman_image_unref(buf->pix);
|
||||
wl_buffer_destroy(buf->wl_buf);
|
||||
munmap(buf->mmapped, buf->size);
|
||||
|
||||
|
|
|
|||
11
shm.h
11
shm.h
|
|
@ -3,23 +3,22 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cairo.h>
|
||||
#include <pixman.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
struct buffer {
|
||||
int width;
|
||||
int height;
|
||||
int stride;
|
||||
|
||||
bool busy;
|
||||
size_t size;
|
||||
void *mmapped;
|
||||
|
||||
struct wl_buffer *wl_buf;
|
||||
|
||||
size_t copies;
|
||||
cairo_surface_t **cairo_surface;
|
||||
cairo_t **cairo;
|
||||
pixman_image_t *pix;
|
||||
};
|
||||
|
||||
struct buffer *shm_get_buffer(struct wl_shm *shm, int width, int height, size_t copies);
|
||||
struct buffer *shm_get_buffer(
|
||||
struct wl_shm *shm, int width, int height, size_t copies);
|
||||
void shm_fini(void);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
#include <threads.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <cairo.h>
|
||||
#include <wayland-client.h>
|
||||
#include <primary-selection-unstable-v1.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue