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:
Daniel Eklöf 2019-01-09 18:30:35 +01:00
parent b52bdf14b2
commit f6977417e0
7 changed files with 167 additions and 111 deletions

165
font.c
View file

@ -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;
}