Set variation settings for cairo fonts

This commit is contained in:
Kovid Goyal 2025-01-31 21:28:43 +05:30
parent bab14e8612
commit b5cc4b8f4e
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C

View file

@ -295,6 +295,8 @@ face_equals_descriptor(PyObject *face_, PyObject *descriptor) {
return true;
}
static char* get_variation_as_string(Face *self);
PyObject*
face_from_descriptor(PyObject *descriptor, FONTS_DATA_HANDLE fg) {
#define D(key, conv, missing_ok) { \
@ -313,8 +315,8 @@ face_from_descriptor(PyObject *descriptor, FONTS_DATA_HANDLE fg) {
D(hint_style, PyLong_AsLong, true);
#undef D
RAII_PyObject(retval, Face_Type.tp_alloc(&Face_Type, 0));
Face *self = (Face *)retval;
if (retval != NULL) {
Face *self = (Face *)retval;
int error;
if ((error = FT_New_Face(library, path, index, &(self->face)))) { self->face = NULL; return set_load_error(path, error); }
if (!init_ft_face(self, PyDict_GetItemString(descriptor, "path"), hinting, hint_style, index, fg)) { Py_CLEAR(retval); return NULL; }
@ -339,6 +341,7 @@ face_from_descriptor(PyObject *descriptor, FONTS_DATA_HANDLE fg) {
if (!create_features_for_face(postscript_name_for_face((PyObject*)self), PyDict_GetItemString(descriptor, "features"), &self->font_features)) return NULL;
}
Py_XINCREF(retval);
printf("%s\n", get_variation_as_string(self));
return retval;
}
@ -383,6 +386,20 @@ face_from_path(const char *path, int index, FONTS_DATA_HANDLE fg) {
return (PyObject*)ans;
}
static inline void cleanup_ftmm(FT_MM_Var **p) { if (*p) FT_Done_MM_Var(library, *p); *p = NULL; }
static const char*
tag_to_string(uint32_t tag, uint8_t bytes[5]) {
bytes[0] = (tag >> 24) & 0xff;
bytes[1] = (tag >> 16) & 0xff;
bytes[2] = (tag >> 8) & 0xff;
bytes[3] = (tag) & 0xff;
bytes[4] = 0;
return (const char*)bytes;
}
#define RAII_FTMMVar(name) __attribute__((cleanup(cleanup_ftmm))) FT_MM_Var *name = NULL
static void free_cairo(Face *self);
static void
@ -693,6 +710,40 @@ get_preferred_palette_index(Face *self) {
return is_color_dark(OPT(background)) ? self->dark_palette_index : self->light_palette_index;
}
static char*
get_variation_as_string(Face *self) {
RAII_FTMMVar(mm);
FT_Error err;
if ((err = FT_Get_MM_Var(self->face, &mm))) return NULL;
RAII_ALLOC(FT_Fixed, coords, malloc(mm->num_axis * sizeof(FT_Fixed))); if (!coords) return NULL;
if ((err = FT_Get_Var_Design_Coordinates(self->face, mm->num_axis, coords))) return NULL;
RAII_ALLOC(char, buf, NULL);
uint8_t tag[5];
size_t pos = 0, sz = 0;
for (FT_UInt i = 0; i < mm->num_axis; i++) {
double val = coords[i] / 65536.0;
tag_to_string(mm->axis[i].tag, tag);
if (sz - pos < 32) {
sz += 4096; buf = realloc(buf, sz); if (!buf) return NULL;
}
if ((long)val == val) pos += snprintf(buf + pos, sz - pos - 1, "%s=%ld,", tag, (long)val);
else pos += snprintf(buf + pos, sz - pos - 1, "%s=%.4f,", tag, val);
}
char *ans = NULL;
if (buf) {
buf[pos] = 0; if (pos && buf[pos-1] == ',') buf[pos-1] = 0;
ans = buf; buf = NULL;
}
return ans;
}
static void
set_variation_for_cairo(Face *self, cairo_font_options_t *opts) {
RAII_ALLOC(char, buf, get_variation_as_string(self));
cairo_font_options_set_variations(opts, buf ? buf : "");
}
static bool
ensure_cairo_resources(Face *self, size_t width, size_t height) {
if (!self->cairo.font) {
@ -753,6 +804,11 @@ ensure_cairo_resources(Face *self, size_t width, size_t height) {
cairo_font_options_destroy(opts);
return set_cairo_exception("Failed to set cairo palette index", s);
}
set_variation_for_cairo(self, opts);
if ((s = cairo_font_options_status(opts)) != CAIRO_STATUS_SUCCESS) {
cairo_font_options_destroy(opts);
return set_cairo_exception("Failed to set cairo font variations", s);
}
cairo_set_font_options(self->cairo.cr, opts);
cairo_font_options_destroy(opts);
}
@ -1019,20 +1075,6 @@ _get_best_name(Face *self, unsigned long nameid) {
}
// }}}
static inline void cleanup_ftmm(FT_MM_Var **p) { if (*p) FT_Done_MM_Var(library, *p); *p = NULL; }
#define RAII_FTMMVar(name) __attribute__((cleanup(cleanup_ftmm))) FT_MM_Var *name = NULL
static const char*
tag_to_string(uint32_t tag, uint8_t bytes[5]) {
bytes[0] = (tag >> 24) & 0xff;
bytes[1] = (tag >> 16) & 0xff;
bytes[2] = (tag >> 8) & 0xff;
bytes[3] = (tag) & 0xff;
bytes[4] = 0;
return (const char*)bytes;
}
static PyObject*
convert_named_style_to_python(Face *face, const FT_Var_Named_Style *src, FT_Var_Axis *axes, unsigned num_of_axes) {
RAII_PyObject(axis_values, PyDict_New());