forked from external/yambar
font: use font-config to load font
This allows us to a) move away from cairo's "toy" API, and b) let the user specify font options in a single font "name" string: Serif:size=10:weight=bold:slant=italic This also allows us to simplify the font code significantly (except for the fontconfig parts...); the font no longer sets itself in a cairo surface - font users do that; the font simply returns a cairo_scaled_font_t. Furthermore, font_clone() has now been simplified to basically just refcount the scaled font. I.e. there's no need to run the full constructor and lookup and instantiate the cairo scaled font again.
This commit is contained in:
parent
b52bdf14b2
commit
f6977417e0
7 changed files with 167 additions and 111 deletions
|
@ -15,7 +15,8 @@ find_package(Threads REQUIRED)
|
|||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
pkg_check_modules(XCB REQUIRED xcb xcb-randr xcb-render xcb-cursor) # Core
|
||||
pkg_check_modules(CAIRO REQUIRED cairo cairo-xcb) # Core
|
||||
pkg_check_modules(FONTCONFIG REQUIRED fontconfig) # Core
|
||||
pkg_check_modules(CAIRO REQUIRED cairo cairo-xcb cairo-ft) # Core
|
||||
pkg_check_modules(YAML REQUIRED yaml-0.1) # Core (configuration)
|
||||
|
||||
pkg_check_modules(XCB_XKB REQUIRED xcb-xkb) # Module/xkb
|
||||
|
@ -67,6 +68,7 @@ target_compile_definitions(f00bar PRIVATE _GNU_SOURCE)
|
|||
|
||||
target_compile_options(f00bar PRIVATE
|
||||
${XCB_CFLAGS_OTHER}
|
||||
${FONTCONFIG_CFLAGS_OTHER}
|
||||
${CAIRO_CFLAGS_OTHER}
|
||||
${YAML_CFLAGS_OTHER}
|
||||
${XCB_XKB_CFLAGS_OTHER}
|
||||
|
@ -78,6 +80,7 @@ target_compile_options(f00bar PRIVATE
|
|||
|
||||
target_include_directories(f00bar PRIVATE
|
||||
${XCB_INCLUDE_DIRS}
|
||||
${FONTCONFIG_INCLUDE_DIRS}
|
||||
${CAIRO_INCLUDE_DIRS}
|
||||
${YAML_INCLUDE_DIRS}
|
||||
${XCB_XKB_INCLUDE_DIRS}
|
||||
|
@ -90,6 +93,7 @@ target_include_directories(f00bar PRIVATE
|
|||
target_link_libraries(f00bar
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${XCB_LIBRARIES}
|
||||
${FONTCONFIG_LIBRARIES}
|
||||
${CAIRO_LIBRARIES}
|
||||
${YAML_LIBRARIES}
|
||||
${XCB_XKB_LIBRARIES}
|
||||
|
|
|
@ -121,12 +121,7 @@ verify_font(keychain_t *chain, const struct yml_node *node)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(sub_key, "size") == 0 ||
|
||||
strcmp(sub_key, "y_offset") == 0)
|
||||
{
|
||||
if (!verify_int(chain_push(chain, sub_key), it.value))
|
||||
return false;
|
||||
} else if (strcmp(sub_key, "family") == 0) {
|
||||
if (strcmp(sub_key, "family") == 0) {
|
||||
if (!verify_string(chain_push(chain, sub_key), it.value))
|
||||
return false;
|
||||
} else {
|
||||
|
|
17
config.c
17
config.c
|
@ -86,17 +86,7 @@ static struct font *
|
|||
font_from_config(const struct yml_node *node)
|
||||
{
|
||||
const struct yml_node *family = yml_get_value(node, "family");
|
||||
const struct yml_node *size = yml_get_value(node, "size");
|
||||
const struct yml_node *italic = yml_get_value(node, "italic");
|
||||
const struct yml_node *bold = yml_get_value(node, "bold");
|
||||
const struct yml_node *y_offset = yml_get_value(node, "y_offset");
|
||||
|
||||
return font_new(
|
||||
family != NULL ? yml_value_as_string(family) : "monospace",
|
||||
size != NULL ? yml_value_as_int(size) : 12,
|
||||
italic != NULL ? yml_value_as_bool(italic) : false,
|
||||
bold != NULL ? yml_value_as_bool(bold) : false,
|
||||
y_offset != NULL ? yml_value_as_int(y_offset) : 0);
|
||||
return font_new(family != NULL ? yml_value_as_string(family) : "monospace");
|
||||
}
|
||||
|
||||
static struct deco *
|
||||
|
@ -191,10 +181,12 @@ particle_string_from_config(const struct yml_node *node,
|
|||
assert(yml_is_dict(node));
|
||||
|
||||
const struct yml_node *text = yml_get_value(node, "text");
|
||||
const struct yml_node *max = yml_get_value(node, "max");
|
||||
const struct yml_node *font = yml_get_value(node, "font");
|
||||
const struct yml_node *foreground = yml_get_value(node, "foreground");
|
||||
|
||||
assert(text != NULL && yml_is_scalar(text));
|
||||
assert(max == NULL || yml_value_is_int(max));
|
||||
|
||||
struct rgba fg_color = foreground != NULL
|
||||
? color_from_hexstr(yml_value_as_string(foreground)) :
|
||||
|
@ -202,6 +194,7 @@ particle_string_from_config(const struct yml_node *node,
|
|||
|
||||
return particle_string_new(
|
||||
yml_value_as_string(text),
|
||||
max != NULL ? yml_value_as_int(max) : 0,
|
||||
font != NULL ? font_from_config(font) : font_clone(parent_font),
|
||||
fg_color, left_margin, right_margin, on_click_template);
|
||||
}
|
||||
|
@ -597,7 +590,7 @@ conf_to_bar(const struct yml_node *bar)
|
|||
struct bar_config conf = {0};
|
||||
|
||||
/* Create a default font */
|
||||
struct font *font = font_new("sans", 12, false, false, 0);
|
||||
struct font *font = font_new("sans");
|
||||
|
||||
const struct yml_node *height = yml_get_value(bar, "height");
|
||||
const struct yml_node *location = yml_get_value(bar, "location");
|
||||
|
|
165
font.c
165
font.c
|
@ -2,32 +2,107 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include <cairo-ft.h>
|
||||
|
||||
#define LOG_MODULE "font"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
|
||||
struct font {
|
||||
char *face;
|
||||
int size;
|
||||
bool italic;
|
||||
bool bold;
|
||||
|
||||
int y_offset;
|
||||
cairo_font_options_t *cairo_font_options;
|
||||
char *name;
|
||||
cairo_scaled_font_t *scaled_font;
|
||||
};
|
||||
|
||||
struct font *
|
||||
font_new(const char *face, int size, bool italic, bool bold, int y_offset)
|
||||
static void __attribute__((constructor))
|
||||
init(void)
|
||||
{
|
||||
FcInit();
|
||||
|
||||
#if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
|
||||
int raw_version = FcGetVersion();
|
||||
|
||||
/* See FC_VERSION in <fontconfig/fontconfig.h> */
|
||||
const int major = raw_version / 10000; raw_version %= 10000;
|
||||
const int minor = raw_version / 100; raw_version %= 100;
|
||||
const int patch = raw_version;
|
||||
#endif
|
||||
|
||||
LOG_DBG("fontconfig: %d.%d.%d", major, minor, patch);
|
||||
}
|
||||
|
||||
static void __attribute__((destructor))
|
||||
fini(void)
|
||||
{
|
||||
FcFini();
|
||||
}
|
||||
|
||||
struct font *
|
||||
font_new(const char *name)
|
||||
{
|
||||
FcPattern *pattern = FcNameParse((const unsigned char *)name);
|
||||
if (pattern == NULL) {
|
||||
LOG_ERR("%s: failed to lookup font", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!FcConfigSubstitute(NULL, pattern, FcMatchPattern)) {
|
||||
LOG_ERR("%s: failed to do config substitution", name);
|
||||
FcPatternDestroy(pattern);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FcDefaultSubstitute(pattern);
|
||||
|
||||
FcResult result;
|
||||
FcPattern *final_pattern = FcFontMatch(NULL, pattern, &result);
|
||||
FcPatternDestroy(pattern);
|
||||
|
||||
if (final_pattern == NULL) {
|
||||
LOG_ERR("%s: failed to match font", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double font_size;
|
||||
if (FcPatternGetDouble(final_pattern, FC_PIXEL_SIZE, 0, &font_size)) {
|
||||
LOG_ERR("%s: failed to get size", name);
|
||||
FcPatternDestroy(final_pattern);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cairo_font_face_t *face = cairo_ft_font_face_create_for_pattern(
|
||||
final_pattern);
|
||||
|
||||
FcPatternDestroy(final_pattern);
|
||||
|
||||
if (cairo_font_face_status(face) != CAIRO_STATUS_SUCCESS) {
|
||||
LOG_ERR("%s: failed to create cairo font face", name);
|
||||
cairo_font_face_destroy(face);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cairo_matrix_t matrix, ctm;
|
||||
cairo_matrix_init_identity(&ctm);
|
||||
cairo_matrix_init_scale(&matrix, font_size, font_size);
|
||||
|
||||
cairo_font_options_t *options = cairo_font_options_create();
|
||||
cairo_scaled_font_t *scaled_font = cairo_scaled_font_create(
|
||||
face, &matrix, &ctm, options);
|
||||
|
||||
cairo_font_options_destroy(options);
|
||||
cairo_font_face_destroy(face);
|
||||
|
||||
if (cairo_scaled_font_status(scaled_font) != CAIRO_STATUS_SUCCESS) {
|
||||
LOG_ERR("%s: failed to create scaled font", name);
|
||||
cairo_scaled_font_destroy(scaled_font);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct font *font = malloc(sizeof(*font));
|
||||
|
||||
font->face = strdup(face);
|
||||
font->size = size;
|
||||
font->italic = italic;
|
||||
font->bold = bold;
|
||||
font->y_offset = y_offset;
|
||||
|
||||
font->cairo_font_options = cairo_font_options_create();
|
||||
cairo_font_options_set_antialias(
|
||||
font->cairo_font_options, CAIRO_ANTIALIAS_DEFAULT);
|
||||
//antialias ? CAIRO_ANTIALIAS_SUBPIXEL : CAIRO_ANTIALIAS_NONE);
|
||||
font->name = strdup(name);
|
||||
font->scaled_font = scaled_font;
|
||||
|
||||
return font;
|
||||
}
|
||||
|
@ -35,58 +110,30 @@ font_new(const char *face, int size, bool italic, bool bold, int y_offset)
|
|||
struct font *
|
||||
font_clone(const struct font *font)
|
||||
{
|
||||
return font_new(font->face, font->size, font->italic, font->bold, font->y_offset);
|
||||
struct font *clone = malloc(sizeof(*font));
|
||||
clone->name = strdup(font->name);
|
||||
clone->scaled_font = font->scaled_font;
|
||||
|
||||
cairo_scaled_font_reference(clone->scaled_font);
|
||||
return clone;
|
||||
}
|
||||
|
||||
void
|
||||
font_destroy(struct font *font)
|
||||
{
|
||||
cairo_font_options_destroy(font->cairo_font_options);
|
||||
free(font->face);
|
||||
cairo_scaled_font_destroy(font->scaled_font);
|
||||
free(font->name);
|
||||
free(font);
|
||||
}
|
||||
|
||||
const char *
|
||||
font_face(const struct font *font)
|
||||
{
|
||||
return font->face;
|
||||
}
|
||||
|
||||
int
|
||||
font_size(const struct font *font)
|
||||
{
|
||||
return font->size;
|
||||
}
|
||||
|
||||
bool
|
||||
font_is_italic(const struct font *font)
|
||||
{
|
||||
return font->italic;
|
||||
}
|
||||
|
||||
bool
|
||||
font_is_bold(const struct font *font)
|
||||
{
|
||||
return font->bold;
|
||||
}
|
||||
|
||||
int
|
||||
font_y_offset(const struct font *font)
|
||||
{
|
||||
return font->y_offset;
|
||||
return font->name;
|
||||
}
|
||||
|
||||
cairo_scaled_font_t *
|
||||
font_use_in_cairo(const struct font *font, cairo_t *cr)
|
||||
font_scaled_font(const struct font *font)
|
||||
{
|
||||
cairo_font_slant_t slant = font->italic
|
||||
? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_NORMAL;
|
||||
cairo_font_weight_t weight = font->bold
|
||||
? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL;
|
||||
|
||||
cairo_select_font_face(cr, font->face, slant, weight);
|
||||
cairo_set_font_size(cr, font->size);
|
||||
cairo_set_font_options(cr, font->cairo_font_options);
|
||||
|
||||
return cairo_get_scaled_font(cr);
|
||||
return font->scaled_font;
|
||||
}
|
||||
|
|
11
font.h
11
font.h
|
@ -7,16 +7,9 @@
|
|||
|
||||
struct font;
|
||||
|
||||
struct font *font_new(
|
||||
const char *face, int size, bool italic, bool bold, int y_offset);
|
||||
|
||||
struct font *font_new(const char *name);
|
||||
struct font *font_clone(const struct font *font);
|
||||
void font_destroy(struct font *font);
|
||||
|
||||
const char *font_face(const struct font *font);
|
||||
int font_size(const struct font *font);
|
||||
bool font_is_italic(const struct font *font);
|
||||
bool font_is_bold(const struct font *font);
|
||||
int font_y_offset(const struct font *font);
|
||||
|
||||
cairo_scaled_font_t *font_use_in_cairo(const struct font *font, cairo_t *cr);
|
||||
cairo_scaled_font_t *font_scaled_font(const struct font *font);
|
||||
|
|
|
@ -4,33 +4,46 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define LOG_MODULE "string"
|
||||
#define LOG_ENABLE_DBG 1
|
||||
#include "../log.h"
|
||||
|
||||
struct private {
|
||||
char *text;
|
||||
size_t max_len;
|
||||
|
||||
struct font *font;
|
||||
struct rgba foreground;
|
||||
};
|
||||
|
||||
struct eprivate {
|
||||
char *text;
|
||||
|
||||
const struct font *font;
|
||||
struct rgba foreground;
|
||||
|
||||
cairo_text_extents_t extents;
|
||||
};
|
||||
|
||||
static void
|
||||
exposable_destroy(struct exposable *exposable)
|
||||
{
|
||||
struct private *e = exposable->private;
|
||||
struct eprivate *e = exposable->private;
|
||||
free(e->text);
|
||||
free(e);
|
||||
exposable_default_destroy(exposable);
|
||||
}
|
||||
|
||||
static int
|
||||
begin_expose(struct exposable *exposable, cairo_t *cr)
|
||||
begin_expose(struct exposable *exposable)
|
||||
{
|
||||
const struct private *e = exposable->private;
|
||||
struct eprivate *e = exposable->private;
|
||||
|
||||
cairo_scaled_font_t *scaled = font_use_in_cairo(e->font, cr);
|
||||
cairo_text_extents_t extents;
|
||||
cairo_scaled_font_text_extents(scaled, e->text, &extents);
|
||||
cairo_scaled_font_t *scaled = font_scaled_font(e->font);
|
||||
cairo_scaled_font_text_extents(scaled, e->text, &e->extents);
|
||||
|
||||
exposable->width = (exposable->particle->left_margin +
|
||||
extents.x_advance +
|
||||
e->extents.x_advance +
|
||||
exposable->particle->right_margin);
|
||||
|
||||
return exposable->width;
|
||||
|
@ -39,12 +52,12 @@ begin_expose(struct exposable *exposable, cairo_t *cr)
|
|||
static void
|
||||
expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height)
|
||||
{
|
||||
const struct private *e = exposable->private;
|
||||
exposable_render_deco(exposable, cr, x, y, height);
|
||||
|
||||
cairo_scaled_font_t *scaled = font_use_in_cairo(e->font, cr);
|
||||
const struct eprivate *e = exposable->private;
|
||||
const size_t text_len = strlen(e->text);
|
||||
|
||||
cairo_text_extents_t extents;
|
||||
cairo_scaled_font_text_extents(scaled, e->text, &extents);
|
||||
cairo_scaled_font_t *scaled = font_scaled_font(e->font);
|
||||
|
||||
cairo_glyph_t *glyphs = NULL;
|
||||
cairo_text_cluster_t *clusters = NULL;
|
||||
|
@ -53,37 +66,47 @@ expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height)
|
|||
cairo_scaled_font_text_to_glyphs(
|
||||
scaled,
|
||||
x + exposable->particle->left_margin,
|
||||
(double)y + ((double)height - extents.y_bearing) / 2 + font_y_offset(e->font),
|
||||
e->text, strlen(e->text), &glyphs, &num_glyphs,
|
||||
(double)y + ((double)height - e->extents.height) / 2 - e->extents.y_bearing,
|
||||
e->text, text_len, &glyphs, &num_glyphs,
|
||||
&clusters, &num_clusters, &cluster_flags);
|
||||
|
||||
exposable_render_deco(exposable, cr, x, y, height);
|
||||
|
||||
cairo_set_scaled_font(cr, scaled);
|
||||
cairo_set_source_rgba(cr,
|
||||
e->foreground.red,
|
||||
e->foreground.green,
|
||||
e->foreground.blue,
|
||||
e->foreground.alpha);
|
||||
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_show_text_glyphs(cr, e->text, strlen(e->text),
|
||||
glyphs, num_glyphs,
|
||||
clusters, num_clusters, cluster_flags);
|
||||
|
||||
cairo_show_text_glyphs(
|
||||
cr, e->text, text_len, glyphs, num_glyphs,
|
||||
clusters, num_clusters, cluster_flags);
|
||||
|
||||
cairo_glyph_free(glyphs);
|
||||
cairo_text_cluster_free(clusters);
|
||||
/*cairo_scaled_font_destroy(scaled);*/
|
||||
|
||||
}
|
||||
|
||||
static struct exposable *
|
||||
instantiate(const struct particle *particle, const struct tag_set *tags)
|
||||
{
|
||||
const struct private *p = particle->private;
|
||||
struct private *e = malloc(sizeof(*e));
|
||||
struct eprivate *e = malloc(sizeof(*e));
|
||||
|
||||
e->text = tags_expand_template(p->text, tags);
|
||||
e->font = p->font;
|
||||
e->foreground = p->foreground;
|
||||
memset(&e->extents, 0, sizeof(e->extents));
|
||||
|
||||
if (p->max_len > 0) {
|
||||
size_t len = strlen(e->text);
|
||||
if (len > p->max_len) {
|
||||
if (p->max_len >= 3) {
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
e->text[p->max_len - 3 + i] = '.';
|
||||
}
|
||||
e->text[p->max_len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
char *on_click = tags_expand_template(particle->on_click_template, tags);
|
||||
|
||||
|
@ -108,12 +131,13 @@ particle_destroy(struct particle *particle)
|
|||
}
|
||||
|
||||
struct particle *
|
||||
particle_string_new(const char *text, struct font *font,
|
||||
particle_string_new(const char *text, size_t max_len, struct font *font,
|
||||
struct rgba foreground, int left_margin, int right_margin,
|
||||
const char *on_click_template)
|
||||
{
|
||||
struct private *p = malloc(sizeof(*p));
|
||||
p->text = strdup(text);
|
||||
p->max_len = max_len;
|
||||
p->font = font;
|
||||
p->foreground = foreground;
|
||||
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
#include "../particle.h"
|
||||
|
||||
struct particle *particle_string_new(
|
||||
const char *text, struct font *font, struct rgba foreground,
|
||||
const char *text, size_t max_len, struct font *font, struct rgba foreground,
|
||||
int left_margin, int right_margin, const char *on_click_template);
|
||||
|
|
Loading…
Add table
Reference in a new issue