diff --git a/font.c b/font.c index b22e4457..49fd8130 100644 --- a/font.c +++ b/font.c @@ -25,6 +25,14 @@ fini(void) FT_Done_FreeType(ft_lib); } +static void +font_populate_glyph_cache(struct font *font) +{ + memset(font->cache, 0, sizeof(font->cache)); + for (size_t i = 0; i < 256; i++) + font_glyph_for_utf8(font, &(char){i}, &font->cache[i]); +} + bool font_from_name(const char *name, struct font *font) { @@ -94,6 +102,7 @@ font_from_name(const char *name, struct font *font) FcPatternDestroy(final_pattern); font->face = ft_face; + font_populate_glyph_cache(font); return true; } @@ -114,6 +123,8 @@ font_glyph_for_utf8(const struct font *font, const char *utf8, if (err != 0) return false; + assert(font->face->glyph->format == FT_GLYPH_FORMAT_BITMAP); + FT_Bitmap *bitmap = &font->face->glyph->bitmap; assert(bitmap->pixel_mode == FT_PIXEL_MODE_GRAY || bitmap->pixel_mode == FT_PIXEL_MODE_MONO); @@ -172,3 +183,17 @@ font_glyph_for_utf8(const struct font *font, const char *utf8, }; return true; } + +void +font_destroy(struct font *font) +{ + if (font->face != NULL) + FT_Done_Face(font->face); + + for (size_t i = 0; i < 256; i++) { + if (font->cache[i].surf != NULL) + cairo_surface_destroy(font->cache[i].surf); + if (font->cache[i].data != NULL) + free(font->cache[i].data); + } +} diff --git a/font.h b/font.h index d8efd509..c02e4ac1 100644 --- a/font.h +++ b/font.h @@ -6,3 +6,4 @@ bool font_from_name(const char *name, struct font *result); bool font_glyph_for_utf8( const struct font *font, const char *utf8, struct glyph *glyph); +void font_destroy(struct font *font); diff --git a/main.c b/main.c index dfcc28ab..7d0fa355 100644 --- a/main.c +++ b/main.c @@ -896,12 +896,8 @@ out: free(term.window_title); tll_free_and_free(term.window_title_stack, free); - for (size_t i = 0; i < sizeof(term.fonts) / sizeof(term.fonts[0]); i++) { - struct font *f = &term.fonts[i]; - - if (f->face != NULL) - FT_Done_Face(f->face); - } + for (size_t i = 0; i < sizeof(term.fonts) / sizeof(term.fonts[0]); i++) + font_destroy(&term.fonts[i]); if (term.flash.fd != -1) close(term.flash.fd); @@ -921,4 +917,5 @@ out: cairo_debug_reset_static_data(); return ret; + } diff --git a/render.c b/render.c index 7bebbbce..cf6c013e 100644 --- a/render.c +++ b/render.c @@ -258,93 +258,30 @@ 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; - - if (likely(entry != NULL && entry->glyphs != NULL)) { - /* Copy cached glyph(s) and upate position */ - memcpy(gseq.g, entry->glyphs, entry->count * sizeof(gseq.g[0])); - for (size_t i = 0; i < entry->count; i++) { - gseq.g[i].x += x; - gseq.g[i].y += y; - } - - new_glyphs = entry->count; - } else { - /* Must generate new glyph(s) */ - cairo_status_t status = cairo_scaled_font_text_to_glyphs( - font->font, x, y + term->fextents.ascent, - cell->c, strnlen(cell->c, 4), &gseq.g, &new_glyphs, - NULL, NULL, NULL); - - if (status != CAIRO_STATUS_SUCCESS) - return; + struct glyph *glyph = NULL; + if (strnlen(cell->c, 4) == 1) { + if (font->cache[(unsigned char)cell->c[0]].surf != NULL) + glyph = &font->cache[(unsigned char)cell->c[0]]; } - 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) { - struct glyph g; - if (!font_glyph_for_utf8(font, cell->c, &g)) - goto done; - - if (e != NULL) { - e->data = g.data; - e->surf = g.surf; - e->left = g.left; - e->top = g.top; - } - - glyph = g.surf; - left = g.left; - top = g.top; - } else { - glyph = e->surf; - left = e->left; - top = e->top; + struct glyph _glyph; + if (glyph == NULL) { + if (!font_glyph_for_utf8(font, cell->c, &_glyph)) + return; + glyph = &_glyph; } 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); + cairo_mask_surface(buf->cairo, glyph->surf, x + glyph->left, y + term->fextents.ascent - glyph->top); - if (e == NULL) { - void *raw = cairo_image_surface_get_data(glyph); - cairo_surface_destroy(glyph); - free(raw); + if (glyph == &_glyph) { + cairo_surface_destroy(_glyph.surf); + free(_glyph.data); } - -done: - return; -#endif } static void diff --git a/terminal.h b/terminal.h index 83efe69a..89f3dc39 100644 --- a/terminal.h +++ b/terminal.h @@ -223,6 +223,8 @@ struct font { double position; double thickness; } strikeout; + + struct glyph cache[256]; }; enum cursor_style { CURSOR_BLOCK, CURSOR_UNDERLINE, CURSOR_BAR };