mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-07 04:06:07 -05:00
render: poc: use freetype to render glyphs
Initial POC that uses freetype to render the glyphs. The bitmap produced by freetype contains the alpha value. We use this bitmap in a mask surface and then draw the final glyph with cairo by applying the source rgb using the OVER operator and the freetype generated alpha mask as surface mask. Note that we only support grayscale antialiasing (and no antialiasing). We are probably not setting the antialias options correctly either.
This commit is contained in:
parent
709c29c7c4
commit
90d357befb
1 changed files with 124 additions and 0 deletions
124
render.c
124
render.c
|
|
@ -5,6 +5,10 @@
|
|||
#include <sys/time.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include <cairo-ft.h>
|
||||
|
||||
#include <wayland-cursor.h>
|
||||
#include <xdg-shell.h>
|
||||
|
||||
|
|
@ -255,11 +259,14 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell,
|
|||
gseq.foreground = _fg;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int new_glyphs
|
||||
= sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]) - gseq.count;
|
||||
#endif
|
||||
|
||||
struct font *font = attrs_to_font(term, &cell->attrs);
|
||||
|
||||
#if 0
|
||||
struct glyph_cache *entry = cell->c[1] == '\0'
|
||||
? &font->glyph_cache[(unsigned char)cell->c[0]]
|
||||
: NULL;
|
||||
|
|
@ -287,6 +294,123 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell,
|
|||
gseq.g += new_glyphs;
|
||||
gseq.count += new_glyphs;
|
||||
assert(gseq.count <= sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]));
|
||||
#else
|
||||
|
||||
struct foo_cache {
|
||||
uint8_t *data;
|
||||
cairo_surface_t *surf;
|
||||
int left;
|
||||
int top;
|
||||
};
|
||||
static struct foo_cache foo_cache[4][256] = {0};
|
||||
|
||||
cairo_surface_t *glyph = NULL;
|
||||
double left, top;
|
||||
|
||||
struct foo_cache *e = strnlen(cell->c, 4) == 1
|
||||
? &foo_cache[cell->attrs.italic << 1 | cell->attrs.bold][(unsigned char)cell->c[0]]
|
||||
: NULL;
|
||||
|
||||
if (e == NULL || e->data == NULL) {
|
||||
wchar_t wc;
|
||||
int res __attribute__((unused)) = mbstowcs(&wc, cell->c, 1);
|
||||
if (res != 1)
|
||||
return;
|
||||
|
||||
FT_Face ft_face = cairo_ft_scaled_font_lock_face(font->font);
|
||||
|
||||
FT_UInt glyph_idx = FT_Get_Char_Index(ft_face, wc);
|
||||
FT_Error ft_err = FT_Load_Glyph(ft_face, glyph_idx, FT_LOAD_DEFAULT);
|
||||
if (ft_err != 0) {
|
||||
LOG_ERR("FT_Load_Glyph");
|
||||
cairo_ft_scaled_font_unlock_face(font->font);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ft_err = FT_Render_Glyph(ft_face->glyph, FT_RENDER_MODE_NORMAL);
|
||||
if (ft_err != 0) {
|
||||
LOG_ERR("FT_Render_Glyph");
|
||||
cairo_ft_scaled_font_unlock_face(font->font);
|
||||
goto done;
|
||||
}
|
||||
|
||||
FT_Bitmap *bitmap = &ft_face->glyph->bitmap;
|
||||
assert(bitmap->pixel_mode == FT_PIXEL_MODE_GRAY ||
|
||||
bitmap->pixel_mode == FT_PIXEL_MODE_MONO);
|
||||
|
||||
cairo_format_t cr_format = bitmap->pixel_mode == FT_PIXEL_MODE_GRAY
|
||||
? CAIRO_FORMAT_A8 : CAIRO_FORMAT_A1;
|
||||
|
||||
int stride = cairo_format_stride_for_width(cr_format, buf->width);
|
||||
assert(stride >= bitmap->pitch);
|
||||
|
||||
uint8_t *copy = malloc(bitmap->rows * stride);
|
||||
|
||||
switch (bitmap->pixel_mode) {
|
||||
case FT_PIXEL_MODE_MONO: {
|
||||
for (size_t r = 0; r < bitmap->rows; r++) {
|
||||
for (size_t c = 0; c < bitmap->width; c++) {
|
||||
uint8_t v = bitmap->buffer[r * bitmap->pitch + c];
|
||||
uint8_t reversed = 0;
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
reversed |= (v & 1) << (7 - i);
|
||||
v >>= 1;
|
||||
}
|
||||
copy[r * stride + c] = reversed;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FT_PIXEL_MODE_GRAY:
|
||||
for (size_t r = 0; r < bitmap->rows; r++) {
|
||||
for (size_t c = 0; c < bitmap->width; c++)
|
||||
copy[r * stride + c] = bitmap->buffer[r * bitmap->pitch + c];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERR("unimplemented FT bitmap pixel mode: %d", bitmap->pixel_mode);
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
glyph = cairo_image_surface_create_for_data(
|
||||
copy, cr_format, bitmap->width, bitmap->rows, stride);
|
||||
|
||||
left = ft_face->glyph->bitmap_left;
|
||||
top = ft_face->glyph->bitmap_top;
|
||||
|
||||
assert(cairo_surface_status(glyph) == CAIRO_STATUS_SUCCESS);
|
||||
|
||||
if (e != NULL) {
|
||||
e->data = copy;
|
||||
e->surf = glyph;
|
||||
e->left = left;
|
||||
e->top = top;
|
||||
}
|
||||
|
||||
cairo_ft_scaled_font_unlock_face(font->font);
|
||||
} else {
|
||||
glyph = e->surf;
|
||||
left = e->left;
|
||||
top = e->top;
|
||||
}
|
||||
|
||||
assert(glyph != NULL);
|
||||
cairo_set_source_rgb(buf->cairo, fg.r, fg.g, fg.b);
|
||||
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_OVER);
|
||||
cairo_mask_surface(buf->cairo, glyph, x + left, y + term->fextents.ascent - top);
|
||||
|
||||
if (e == NULL) {
|
||||
void *raw = cairo_image_surface_get_data(glyph);
|
||||
cairo_surface_destroy(glyph);
|
||||
free(raw);
|
||||
}
|
||||
|
||||
done:
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue