mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
font: add support for fallback fonts
A top-level font now has a list of fallback fonts. When a glyph cannot be found, we try each fallback font in turn, until we either find one that has the glyph, or until we've exhausted the list. To make this actually work in practise (read: to make performance acceptable), the cache is re-worked and is now populated on demand. It also supports non-ASCII characters, by using the 4-byte unicode character as index instead. Since having an array that can be indexed by a 4-byte value isn't really viable, we now have a simple hash table instead of an array.
This commit is contained in:
parent
85ef9df586
commit
73b4d5d05a
7 changed files with 280 additions and 127 deletions
14
config.c
14
config.c
|
|
@ -147,8 +147,12 @@ parse_section_main(const char *key, const char *value, struct config *conf,
|
|||
}
|
||||
|
||||
else if (strcmp(key, "font") == 0) {
|
||||
free(conf->font);
|
||||
conf->font = strdup(value);
|
||||
//free(conf->font);
|
||||
//conf->font = strdup(value);
|
||||
char *copy = strdup(value);
|
||||
for (const char *font = strtok(copy, ","); font != NULL; font = strtok(NULL, ","))
|
||||
tll_push_back(conf->fonts, strdup(font));
|
||||
free(copy);
|
||||
}
|
||||
|
||||
else if (strcmp(key, "workers") == 0) {
|
||||
|
|
@ -404,7 +408,7 @@ config_load(struct config *conf)
|
|||
*conf = (struct config) {
|
||||
.term = strdup("foot"),
|
||||
.shell = get_shell(),
|
||||
.font = strdup("monospace"),
|
||||
.fonts = tll_init(),
|
||||
|
||||
.colors = {
|
||||
.fg = default_foreground,
|
||||
|
|
@ -462,6 +466,7 @@ config_load(struct config *conf)
|
|||
fclose(f);
|
||||
|
||||
out:
|
||||
tll_push_back(conf->fonts, strdup("monospace"));
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -471,5 +476,6 @@ config_free(struct config conf)
|
|||
{
|
||||
free(conf.term);
|
||||
free(conf.shell);
|
||||
free(conf.font);
|
||||
//free(conf.font);
|
||||
tll_free_and_free(conf.fonts, free);
|
||||
}
|
||||
|
|
|
|||
3
config.h
3
config.h
|
|
@ -4,11 +4,12 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#include "terminal.h"
|
||||
#include "tllist.h"
|
||||
|
||||
struct config {
|
||||
char *term;
|
||||
char *shell;
|
||||
char *font;
|
||||
tll(char *) fonts;
|
||||
|
||||
struct {
|
||||
uint32_t fg;
|
||||
|
|
|
|||
221
font.c
221
font.c
|
|
@ -1,33 +1,42 @@
|
|||
#include "font.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <wchar.h>
|
||||
#include <assert.h>
|
||||
#include <threads.h>
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
#define LOG_MODULE "font"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
|
||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
static FT_Library ft_lib;
|
||||
static mtx_t ft_lock;
|
||||
|
||||
static const size_t cache_size = 512;
|
||||
|
||||
static void __attribute__((constructor))
|
||||
init(void)
|
||||
{
|
||||
FcInit();
|
||||
FT_Init_FreeType(&ft_lib);
|
||||
mtx_init(&ft_lock, mtx_plain);
|
||||
}
|
||||
|
||||
static void __attribute__((destructor))
|
||||
fini(void)
|
||||
{
|
||||
FcFini();
|
||||
mtx_destroy(&ft_lock);
|
||||
FT_Done_FreeType(ft_lib);
|
||||
FcFini();
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
font_populate_glyph_cache(struct font *font)
|
||||
{
|
||||
|
|
@ -35,12 +44,25 @@ font_populate_glyph_cache(struct font *font)
|
|||
for (size_t i = 0; i < 256; i++)
|
||||
font_glyph_for_utf8(font, &(char){i}, &font->cache[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
font_from_name(const char *name, struct font *font)
|
||||
static bool
|
||||
from_name(const char *base_name, const font_list_t *fallbacks, const char *attributes, struct font *font, bool is_fallback)
|
||||
{
|
||||
memset(font, 0, sizeof(*font));
|
||||
|
||||
size_t attr_len = attributes == NULL ? 0 : strlen(attributes);
|
||||
bool have_attrs = attr_len > 0;
|
||||
|
||||
char name[strlen(base_name) + (have_attrs ? 1 : 0) + attr_len + 1];
|
||||
strcpy(name, base_name);
|
||||
if (have_attrs){
|
||||
strcat(name, ":");
|
||||
strcat(name, attributes);
|
||||
}
|
||||
|
||||
LOG_DBG("instantiating %s", name);
|
||||
|
||||
FcPattern *pattern = FcNameParse((const unsigned char *)name);
|
||||
if (pattern == NULL) {
|
||||
LOG_ERR("%s: failed to lookup font", name);
|
||||
|
|
@ -86,8 +108,10 @@ font_from_name(const char *name, struct font *font)
|
|||
|
||||
LOG_DBG("loading: %s", face_file);
|
||||
|
||||
mtx_lock(&ft_lock);
|
||||
FT_Face ft_face;
|
||||
FT_Error ft_err = FT_New_Face(ft_lib, (const char *)face_file, 0, &ft_face);
|
||||
mtx_unlock(&ft_lock);
|
||||
if (ft_err != 0)
|
||||
LOG_ERR("%s: failed to create FreeType face", face_file);
|
||||
|
||||
|
|
@ -122,11 +146,13 @@ font_from_name(const char *name, struct font *font)
|
|||
else if (fc_hinting && fc_hintstyle == FC_HINT_SLIGHT)
|
||||
load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_LIGHT;
|
||||
else if (fc_rgba == FC_RGBA_RGB) {
|
||||
LOG_WARN("unimplemented: subpixel antialiasing");
|
||||
if (!is_fallback)
|
||||
LOG_WARN("unimplemented: subpixel antialiasing");
|
||||
// load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_LCD;
|
||||
load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_NORMAL;
|
||||
} else if (fc_rgba == FC_RGBA_VRGB) {
|
||||
LOG_WARN("unimplemented: subpixel antialiasing");
|
||||
if (!is_fallback)
|
||||
LOG_WARN("unimplemented: subpixel antialiasing");
|
||||
//load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_LCD_V;
|
||||
load_flags |= FT_LOAD_DEFAULT | FT_LOAD_TARGET_NORMAL;
|
||||
} else
|
||||
|
|
@ -144,15 +170,17 @@ font_from_name(const char *name, struct font *font)
|
|||
if (!fc_antialias)
|
||||
render_flags |= FT_RENDER_MODE_MONO;
|
||||
else {
|
||||
if (false)
|
||||
;
|
||||
#if 0
|
||||
if (fc_rgba == FC_RGBA_RGB)
|
||||
render_flags |= FT_RENDER_MODE_LCD;
|
||||
else if (fc_rgba == FC_RGBA_VRGB)
|
||||
render_flags |= FT_RENDER_MODE_LCD_V;
|
||||
#endif
|
||||
else
|
||||
if (fc_rgba == FC_RGBA_RGB) {
|
||||
if (!is_fallback)
|
||||
LOG_WARN("unimplemented: subpixel antialiasing");
|
||||
//render_flags |= FT_RENDER_MODE_LCD;
|
||||
render_flags |= FT_RENDER_MODE_NORMAL;
|
||||
} else if (fc_rgba == FC_RGBA_VRGB) {
|
||||
if (!is_fallback)
|
||||
LOG_WARN("unimplemented: subpixel antialiasing");
|
||||
//render_flags |= FT_RENDER_MODE_LCD_V;
|
||||
render_flags |= FT_RENDER_MODE_NORMAL;
|
||||
} else
|
||||
render_flags |= FT_RENDER_MODE_NORMAL;
|
||||
}
|
||||
|
||||
|
|
@ -173,25 +201,64 @@ font_from_name(const char *name, struct font *font)
|
|||
font->face = ft_face;
|
||||
font->load_flags = load_flags;
|
||||
font->render_flags = render_flags;
|
||||
font_populate_glyph_cache(font);
|
||||
font->is_fallback = is_fallback;
|
||||
|
||||
if (fallbacks != NULL) {
|
||||
tll_foreach(*fallbacks, it) {
|
||||
size_t len = strlen(it->item) + (have_attrs ? 1 : 0) + attr_len + 1;
|
||||
char *fallback = malloc(len);
|
||||
|
||||
strcpy(fallback, it->item);
|
||||
if (have_attrs) {
|
||||
strcat(fallback, ":");
|
||||
strcat(fallback, attributes);
|
||||
}
|
||||
|
||||
LOG_DBG("%s: adding fallback: %s", name, fallback);
|
||||
tll_push_back(font->fallbacks, fallback);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_fallback)
|
||||
return true;
|
||||
|
||||
//font_populate_glyph_cache(font);
|
||||
font->cache = calloc(cache_size, sizeof(font->cache[0]));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
font_glyph_for_utf8(struct font *font, const char *utf8,
|
||||
struct glyph *glyph)
|
||||
font_from_name(font_list_t names, const char *attributes, struct font *font)
|
||||
{
|
||||
mbstate_t ps = {0};
|
||||
wchar_t wc;
|
||||
if (mbrtowc(&wc, utf8, 4, &ps) < 0) {
|
||||
LOG_ERR("FAILED: %.4s", utf8);
|
||||
if (tll_length(names) == 0)
|
||||
return false;
|
||||
|
||||
font_list_t fallbacks = tll_init();
|
||||
bool skip_first = true;
|
||||
tll_foreach(names, it) {
|
||||
if (skip_first) {
|
||||
skip_first = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
tll_push_back(fallbacks, it->item);
|
||||
}
|
||||
|
||||
wprintf(L"CONVERTED: %.1s\n", &wc);
|
||||
bool ret = from_name(tll_front(names), &fallbacks, attributes, font, false);
|
||||
|
||||
mtx_lock(&font->lock);
|
||||
tll_free(fallbacks);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t
|
||||
hash_index(wchar_t wc)
|
||||
{
|
||||
return wc % cache_size;
|
||||
}
|
||||
|
||||
static bool
|
||||
glyph_for_wchar(struct font *font, wchar_t wc, struct glyph *glyph)
|
||||
{
|
||||
/*
|
||||
* LCD filter is per library instance. Thus we need to re-set it
|
||||
* every time...
|
||||
|
|
@ -204,6 +271,28 @@ font_glyph_for_utf8(struct font *font, const char *utf8,
|
|||
goto err;
|
||||
|
||||
FT_UInt idx = FT_Get_Char_Index(font->face, wc);
|
||||
if (idx == 0) {
|
||||
/* LOG_DBG("no glyph found for %02x %02x %02x %02x", */
|
||||
/* (unsigned char)utf8[0], (unsigned char)utf8[1], */
|
||||
/* (unsigned char)utf8[2], (unsigned char)utf8[3]); */
|
||||
|
||||
/* Try fallback fonts */
|
||||
tll_foreach(font->fallbacks, it) {
|
||||
struct font fallback;
|
||||
if (from_name(it->item, NULL, "", &fallback, true)) {
|
||||
if (glyph_for_wchar(&fallback, wc, glyph)) {
|
||||
font_destroy(&fallback);
|
||||
return true;
|
||||
}
|
||||
|
||||
font_destroy(&fallback);
|
||||
}
|
||||
}
|
||||
|
||||
if (font->is_fallback)
|
||||
return false;
|
||||
}
|
||||
|
||||
err = FT_Load_Glyph(font->face, idx, font->load_flags);
|
||||
if (err != 0) {
|
||||
LOG_ERR("load failed");
|
||||
|
|
@ -267,36 +356,102 @@ font_glyph_for_utf8(struct font *font, const char *utf8,
|
|||
}
|
||||
|
||||
*glyph = (struct glyph){
|
||||
.wc = wc,
|
||||
.data = data,
|
||||
.surf = surf,
|
||||
.left = font->face->glyph->bitmap_left,
|
||||
.top = font->face->glyph->bitmap_top,
|
||||
|
||||
.format = cr_format,
|
||||
.width = bitmap->width,
|
||||
.height = bitmap->rows,
|
||||
.stride = stride,
|
||||
};
|
||||
mtx_unlock(&font->lock);
|
||||
|
||||
return true;
|
||||
|
||||
err:
|
||||
mtx_unlock(&font->lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct glyph *
|
||||
font_glyph_for_utf8(struct font *font, const char *utf8)
|
||||
{
|
||||
mtx_lock(&font->lock);
|
||||
|
||||
mbstate_t ps = {0};
|
||||
wchar_t wc;
|
||||
if (mbrtowc(&wc, utf8, 4, &ps) < 0) {
|
||||
LOG_DBG("failed to convert utf-8 sequence %02x %02x %02x %02x to unicode",
|
||||
(unsigned char)utf8[0], (unsigned char)utf8[1],
|
||||
(unsigned char)utf8[2], (unsigned char)utf8[3]);
|
||||
mtx_unlock(&font->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(font->cache != NULL);
|
||||
size_t hash_idx = hash_index(wc);
|
||||
hash_entry_t *hash_entry = font->cache[hash_idx];
|
||||
|
||||
if (hash_entry != NULL) {
|
||||
tll_foreach(*hash_entry, it) {
|
||||
if (it->item.wc == wc) {
|
||||
mtx_unlock(&font->lock);
|
||||
return &it->item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct glyph glyph;
|
||||
if (!glyph_for_wchar(font, wc, &glyph)) {
|
||||
mtx_unlock(&font->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hash_entry == NULL) {
|
||||
hash_entry = calloc(1, sizeof(*hash_entry));
|
||||
|
||||
assert(font->cache[hash_idx] == NULL);
|
||||
font->cache[hash_idx] = hash_entry;
|
||||
}
|
||||
|
||||
assert(hash_entry != NULL);
|
||||
tll_push_back(*hash_entry, glyph);
|
||||
|
||||
mtx_unlock(&font->lock);
|
||||
return &tll_back(*hash_entry);
|
||||
}
|
||||
|
||||
void
|
||||
font_destroy(struct font *font)
|
||||
{
|
||||
if (font->face != NULL)
|
||||
FT_Done_Face(font->face);
|
||||
tll_free_and_free(font->fallbacks, free);
|
||||
|
||||
if (font->face != NULL) {
|
||||
mtx_lock(&ft_lock);
|
||||
FT_Done_Face(font->face);
|
||||
mtx_unlock(&ft_lock);
|
||||
}
|
||||
|
||||
if (font->cache != NULL) {
|
||||
for (size_t i = 0; i < cache_size; i++) {
|
||||
if (font->cache[i] == NULL)
|
||||
continue;
|
||||
|
||||
tll_foreach(*font->cache[i], it) {
|
||||
cairo_surface_destroy(it->item.surf);
|
||||
free(it->item.data);
|
||||
}
|
||||
|
||||
tll_free(*font->cache[i]);
|
||||
free(font->cache[i]);
|
||||
}
|
||||
free(font->cache);
|
||||
}
|
||||
|
||||
#if 0
|
||||
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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
mtx_destroy(&font->lock);
|
||||
}
|
||||
|
|
|
|||
55
font.h
55
font.h
|
|
@ -3,9 +3,56 @@
|
|||
#include <stdbool.h>
|
||||
#include <threads.h>
|
||||
|
||||
#include "terminal.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_LCD_FILTER_H
|
||||
#include <cairo.h>
|
||||
|
||||
bool font_from_name(const char *name, struct font *result);
|
||||
bool font_glyph_for_utf8(
|
||||
struct font *font, const char *utf8, struct glyph *glyph);
|
||||
#include "tllist.h"
|
||||
//#include "terminal.h"
|
||||
|
||||
typedef tll(const char *) font_list_t;
|
||||
|
||||
struct glyph {
|
||||
wchar_t wc;
|
||||
|
||||
void *data;
|
||||
cairo_surface_t *surf;
|
||||
int left;
|
||||
int top;
|
||||
|
||||
#if 0
|
||||
int format;
|
||||
int width;
|
||||
int height;
|
||||
int stride;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef tll(struct glyph) hash_entry_t;
|
||||
|
||||
struct font {
|
||||
FT_Face face;
|
||||
int load_flags;
|
||||
int render_flags;
|
||||
FT_LcdFilter lcd_filter;
|
||||
struct {
|
||||
double position;
|
||||
double thickness;
|
||||
} underline;
|
||||
struct {
|
||||
double position;
|
||||
double thickness;
|
||||
} strikeout;
|
||||
|
||||
bool is_fallback;
|
||||
tll(char *) fallbacks;
|
||||
|
||||
//struct glyph cache[256];
|
||||
hash_entry_t **cache;
|
||||
mtx_t lock;
|
||||
};
|
||||
|
||||
bool font_from_name(font_list_t names, const char *attributes, struct font *result);
|
||||
const struct glyph *font_glyph_for_utf8(struct font *font, const char *utf8);
|
||||
void font_destroy(struct font *font);
|
||||
|
|
|
|||
28
main.c
28
main.c
|
|
@ -291,8 +291,8 @@ main(int argc, char *const *argv)
|
|||
break;
|
||||
|
||||
case 'f':
|
||||
free(conf.font);
|
||||
conf.font = strdup(optarg);
|
||||
tll_free_and_free(conf.fonts, free);
|
||||
tll_push_back(conf.fonts, strdup(optarg));
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
|
|
@ -431,21 +431,21 @@ main(int argc, char *const *argv)
|
|||
thrd_create(&term.render.workers.threads[i], &render_worker_thread, &worker_context[i]);
|
||||
}
|
||||
|
||||
if (!font_from_name(conf.font, &term.fonts[0]))
|
||||
font_list_t font_names = tll_init();
|
||||
tll_foreach(conf.fonts, it)
|
||||
tll_push_back(font_names, it->item);
|
||||
|
||||
if (!font_from_name(font_names, "", &term.fonts[0])) {
|
||||
tll_free(font_names);
|
||||
goto out;
|
||||
|
||||
{
|
||||
char fname[1024];
|
||||
snprintf(fname, sizeof(fname), "%s:style=bold", conf.font);
|
||||
font_from_name(fname, &term.fonts[1]);
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s:style=italic", conf.font);
|
||||
font_from_name(fname, &term.fonts[2]);
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s:style=bold italic", conf.font);
|
||||
font_from_name(fname, &term.fonts[3]);
|
||||
}
|
||||
|
||||
font_from_name(font_names, "style=bold", &term.fonts[1]);
|
||||
font_from_name(font_names, "style=italic", &term.fonts[2]);
|
||||
font_from_name(font_names, "style=bold italic", &term.fonts[3]);
|
||||
|
||||
tll_free(font_names);
|
||||
|
||||
/* Underline position and size */
|
||||
for (size_t i = 0; i < sizeof(term.fonts) / sizeof(term.fonts[0]); i++) {
|
||||
struct font *f = &term.fonts[i];
|
||||
|
|
|
|||
50
render.c
50
render.c
|
|
@ -273,38 +273,12 @@ render_cell(struct terminal *term, struct buffer *buf, size_t buf_idx,
|
|||
}
|
||||
|
||||
struct font *font = attrs_to_font(term, &cell->attrs);
|
||||
|
||||
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]];
|
||||
}
|
||||
|
||||
struct glyph _glyph;
|
||||
if (glyph == NULL) {
|
||||
if (!font_glyph_for_utf8(font, cell->c, &_glyph)) {
|
||||
LOG_ERR("FAILED: %.4s", cell->c);
|
||||
return;
|
||||
}
|
||||
glyph = &_glyph;
|
||||
}
|
||||
|
||||
assert(glyph != NULL);
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_set_source_rgb(cr, fg.r, fg.g, fg.b);
|
||||
|
||||
#if 0
|
||||
cairo_surface_t *surf = cairo_image_surface_create_for_data(
|
||||
glyph->data, glyph->format, glyph->width, glyph->height, glyph->stride);
|
||||
cairo_mask_surface(cr, surf, x + glyph->left, y + term->fextents.ascent - glyph->top);
|
||||
cairo_surface_destroy(surf);
|
||||
#else
|
||||
cairo_mask_surface(cr, glyph->surf, x + glyph->left, y + term->fextents.ascent - glyph->top);
|
||||
#endif
|
||||
|
||||
if (glyph == &_glyph) {
|
||||
cairo_surface_destroy(_glyph.surf);
|
||||
free(_glyph.data);
|
||||
const struct glyph *glyph = font_glyph_for_utf8(font, cell->c);
|
||||
if (glyph != NULL) {
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_set_source_rgb(cr, fg.r, fg.g, fg.b);
|
||||
cairo_mask_surface(
|
||||
cr, glyph->surf, x + glyph->left, y + term->fextents.ascent - glyph->top);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -456,9 +430,12 @@ grid_render(struct terminal *term)
|
|||
|
||||
/* Erase old cursor (if we rendered a cursor last time) */
|
||||
if (term->render.last_cursor.cell != NULL) {
|
||||
struct cell *hack = (struct cell *)term->render.last_cursor.cell;
|
||||
hack->attrs.clean = 0;
|
||||
render_cell(
|
||||
term, buf, 0,
|
||||
term->render.last_cursor.cell,
|
||||
//term->render.last_cursor.cell,
|
||||
hack,
|
||||
term->render.last_cursor.in_view.col,
|
||||
term->render.last_cursor.in_view.row, false);
|
||||
|
||||
|
|
@ -622,11 +599,12 @@ grid_render(struct terminal *term)
|
|||
term->cursor.col, view_aligned_row};
|
||||
|
||||
struct row *row = grid_row_in_view(term->grid, view_aligned_row);
|
||||
struct cell *cell = &row->cells[term->cursor.col];
|
||||
|
||||
term->render.last_cursor.cell = &row->cells[term->cursor.col];
|
||||
cell->attrs.clean = 0;
|
||||
term->render.last_cursor.cell = cell;
|
||||
render_cell(
|
||||
term, buf, 0, term->render.last_cursor.cell,
|
||||
term->cursor.col, view_aligned_row, true);
|
||||
term, buf, 0, cell, term->cursor.col, view_aligned_row, true);
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->wl.surface,
|
||||
|
|
|
|||
36
terminal.h
36
terminal.h
|
|
@ -7,17 +7,13 @@
|
|||
#include <threads.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_LCD_FILTER_H
|
||||
|
||||
#include <cairo.h>
|
||||
#include <wayland-client.h>
|
||||
#include <primary-selection-unstable-v1.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
|
||||
|
||||
#include "font.h"
|
||||
#include "tllist.h"
|
||||
|
||||
#define likely(c) __builtin_expect(!!(c), 1)
|
||||
|
|
@ -211,36 +207,6 @@ struct primary {
|
|||
uint32_t serial;
|
||||
};
|
||||
|
||||
struct glyph {
|
||||
void *data;
|
||||
cairo_surface_t *surf;
|
||||
int left;
|
||||
int top;
|
||||
|
||||
int format;
|
||||
int width;
|
||||
int height;
|
||||
int stride;
|
||||
};
|
||||
|
||||
struct font {
|
||||
FT_Face face;
|
||||
int load_flags;
|
||||
int render_flags;
|
||||
FT_LcdFilter lcd_filter;
|
||||
struct {
|
||||
double position;
|
||||
double thickness;
|
||||
} underline;
|
||||
struct {
|
||||
double position;
|
||||
double thickness;
|
||||
} strikeout;
|
||||
|
||||
struct glyph cache[256];
|
||||
mtx_t lock;
|
||||
};
|
||||
|
||||
enum cursor_style { CURSOR_BLOCK, CURSOR_UNDERLINE, CURSOR_BAR };
|
||||
|
||||
struct terminal {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue