[pango/simple-fontmap: 16/17] wip: Introduce user fonts
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pango/simple-fontmap: 16/17] wip: Introduce user fonts
- Date: Thu, 27 Jan 2022 06:06:40 +0000 (UTC)
commit 26b7c883df4f7774edf09594ba0d2201ca9295e6
Author: Matthias Clasen <mclasen redhat com>
Date: Thu Jan 27 00:46:15 2022 -0500
wip: Introduce user fonts
Add a way to create callback-based faces
and fonts. The cairo implementation of this
uses cairos user fonts.
pango/pango-hbface-private.h | 13 ++++++
pango/pango-hbface.c | 83 +++++++++++++++++++++++++++++++++--
pango/pango-hbface.h | 34 +++++++++++++++
pango/pango-hbfont-private.h | 3 ++
pango/pango-hbfont.c | 102 ++++++++++++++++++++++++++++++++++++++++---
pango/pango-hbfont.h | 3 ++
pango/pangocairo-font.c | 51 ++++++++++++++++++++++
7 files changed, 279 insertions(+), 10 deletions(-)
---
diff --git a/pango/pango-hbface-private.h b/pango/pango-hbface-private.h
index 045a13ef..db016fdc 100644
--- a/pango/pango-hbface-private.h
+++ b/pango/pango-hbface-private.h
@@ -25,6 +25,17 @@
#include "pango-language-set-private.h"
#include <hb.h>
+typedef struct _PangoUserFontFuncs PangoUserFontFuncs;
+struct _PangoUserFontFuncs
+{
+ PangoHbFaceGetNominalGlyphFunc glyph_func;
+ PangoHbFaceGetGlyphAdvanceFunc advance_func;
+ PangoHbFaceGetGlyphExtentsFunc extents_func;
+ PangoHbFaceRenderGlyphFunc render_func;
+ gpointer user_data;
+ GDestroyNotify destroy;
+};
+
struct _PangoHbFace
{
PangoFontFace parent_instance;
@@ -45,6 +56,8 @@ struct _PangoHbFace
PangoLanguageSet *languages;
gboolean embolden;
gboolean synthetic;
+
+ PangoUserFontFuncs *user_font;
};
void pango_hb_face_set_family (PangoHbFace *self,
diff --git a/pango/pango-hbface.c b/pango/pango-hbface.c
index 7c93f9aa..e5194fc5 100644
--- a/pango/pango-hbface.c
+++ b/pango/pango-hbface.c
@@ -216,9 +216,16 @@ ensure_psname (PangoHbFace *self)
if (self->psname)
return;
- ensure_hb_face (self);
+ if (self->user_font)
+ {
+ self->psname = g_strconcat (pango_font_description_get_family (self->description), "_", self->name,
NULL);
+ }
+ else
+ {
+ ensure_hb_face (self);
- self->psname = get_name_from_hb_face (self->face, HB_OT_NAME_ID_POSTSCRIPT_NAME, HB_OT_NAME_ID_INVALID);
+ self->psname = get_name_from_hb_face (self->face, HB_OT_NAME_ID_POSTSCRIPT_NAME,
HB_OT_NAME_ID_INVALID);
+ }
/* PostScript name should not contain problematic chars, but just in case,
* make sure we don't have any ' ', '=' or ',' that would give us parsing
@@ -283,7 +290,8 @@ pango_hb_face_finalize (GObject *object)
{
PangoHbFace *self = PANGO_HB_FACE (object);
- hb_face_destroy (self->face);
+ if (self->face)
+ hb_face_destroy (self->face);
pango_font_description_free (self->description);
g_free (self->name);
g_free (self->file);
@@ -294,6 +302,13 @@ pango_hb_face_finalize (GObject *object)
if (self->matrix)
g_free (self->matrix);
+ if (self->user_font)
+ {
+ if (self->user_font->destroy)
+ self->user_font->destroy (self->user_font->user_data);
+ g_free (self->user_font);
+ }
+
G_OBJECT_CLASS (pango_hb_face_parent_class)->finalize (object);
}
@@ -337,6 +352,9 @@ pango_hb_face_is_monospace (PangoFontFace *face)
{
PangoHbFace *self = PANGO_HB_FACE (face);
+ if (self->user_font)
+ return FALSE;
+
ensure_hb_face (self);
return hb_face_is_monospace (self->face);
@@ -347,6 +365,9 @@ pango_hb_face_is_variable (PangoFontFace *face)
{
PangoHbFace *self = PANGO_HB_FACE (face);
+ if (self->user_font)
+ return FALSE;
+
/* We don't consider named instances as variable, i.e.
* a font chooser UI should not expose axes for them.
*
@@ -498,6 +519,9 @@ pango_hb_face_has_char (PangoHbFace *self,
hb_codepoint_t glyph;
gboolean ret;
+ if (self->user_font)
+ return self->user_font->glyph_func (self, wc, &glyph, self->user_font->user_data);
+
ensure_hb_face (self);
hb_font = hb_font_create (self->face);
@@ -869,6 +893,59 @@ pango_hb_face_new_instance (PangoHbFace *face,
return self;
}
+/**
+ * pango_hb_face_new_user:
+ * @glyph_func: the `PangoHbFaceGetNominalGlyphFunc`
+ * @advance_func: the `PangoHbFaceGetGlyphAdvanceFunc`
+ * @extents_func: the `PangoHbFaceGetGlyphExtentsFunc`
+ * @render_func: the `PangoHbFaceRenderGlyphFunc`
+ * @user_data: user data that will be assed to the callbacks
+ * @destroy: destroy notify for @user_data
+ * @name: name for the face
+ * @description: (nullable): `PangoFontDescription` for the font
+ *
+ * Creates a new user font face.
+ *
+ * A user font face does not rely on font data from a font file,
+ * but instead uses callbacks to determine glyph extents, positions
+ * and rendering.
+ *
+ * Returns: (transfer full): a newly created `PangoHbFace`
+ *
+ * Since: 1.52
+ */
+PangoHbFace *
+pango_hb_face_new_user (PangoHbFaceGetNominalGlyphFunc glyph_func,
+ PangoHbFaceGetGlyphAdvanceFunc advance_func,
+ PangoHbFaceGetGlyphExtentsFunc extents_func,
+ PangoHbFaceRenderGlyphFunc render_func,
+ gpointer user_data,
+ GDestroyNotify destroy,
+ const char *name,
+ const PangoFontDescription *description)
+{
+ PangoHbFace *self;
+
+ self = g_object_new (PANGO_TYPE_HB_FACE, NULL);
+
+ self->user_font = g_new0 (PangoUserFontFuncs, 1);
+
+ self->user_font->glyph_func = glyph_func;
+ self->user_font->advance_func = advance_func;
+ self->user_font->extents_func = extents_func,
+ self->user_font->render_func = render_func;
+ self->user_font->user_data = user_data;
+ self->user_font->destroy = destroy;
+
+ self->synthetic = TRUE;
+
+ self->name = g_strdup (name);
+ self->description = pango_font_description_copy (description);
+ self->languages = PANGO_LANGUAGE_SET (pango_language_set_simple_new ());
+
+ return self;
+}
+
/**
* pango_hb_face_get_hb_face:
* @self: a `PangoHbFace`
diff --git a/pango/pango-hbface.h b/pango/pango-hbface.h
index 80f77509..f1303cd6 100644
--- a/pango/pango-hbface.h
+++ b/pango/pango-hbface.h
@@ -25,6 +25,8 @@
G_BEGIN_DECLS
+typedef struct _PangoHbFont PangoHbFont;
+
#define PANGO_TYPE_HB_FACE (pango_hb_face_get_type ())
PANGO_AVAILABLE_IN_1_52
@@ -57,6 +59,38 @@ PangoHbFace * pango_hb_face_new_instance (PangoHbFace *fac
const char *name,
const PangoFontDescription *description);
+typedef gboolean (* PangoHbFaceGetNominalGlyphFunc) (PangoHbFace *face,
+ hb_codepoint_t unicode,
+ hb_codepoint_t *glyph,
+ gpointer user_data);
+
+typedef hb_position_t (* PangoHbFaceGetGlyphAdvanceFunc) (PangoHbFace *face,
+ int size,
+ hb_codepoint_t glyph,
+ gpointer user_data);
+
+typedef gboolean (* PangoHbFaceGetGlyphExtentsFunc) (PangoHbFace *face,
+ int size,
+ hb_codepoint_t glyph,
+ hb_glyph_extents_t *extents,
+ gpointer user_data);
+
+typedef void (* PangoHbFaceRenderGlyphFunc) (PangoHbFace *face,
+ int size,
+ hb_codepoint_t glyph,
+ gpointer user_data,
+ gpointer backend_data);
+
+PANGO_AVAILABLE_IN_1_52
+PangoHbFace * pango_hb_face_new_user (PangoHbFaceGetNominalGlyphFunc glyph_func,
+ PangoHbFaceGetGlyphAdvanceFunc advance_func,
+ PangoHbFaceGetGlyphExtentsFunc extents,
+ PangoHbFaceRenderGlyphFunc render_glyph,
+ gpointer user_data,
+ GDestroyNotify destroy,
+ const char *name,
+ const PangoFontDescription *description);
+
PANGO_AVAILABLE_IN_1_52
hb_face_t * pango_hb_face_get_hb_face (PangoHbFace *self);
diff --git a/pango/pango-hbfont-private.h b/pango/pango-hbfont-private.h
index fea6162f..6c929099 100644
--- a/pango/pango-hbfont-private.h
+++ b/pango/pango-hbfont-private.h
@@ -53,4 +53,7 @@ struct _PangoHbFont
PangoMatrix matrix;
HexBoxInfo *hex_box_info;
+ PangoLanguage *approximate_char_lang;
+ int approximate_char_width;
+ int approximate_digit_width;
};
diff --git a/pango/pango-hbfont.c b/pango/pango-hbfont.c
index ccfb2e61..87a62f7e 100644
--- a/pango/pango-hbfont.c
+++ b/pango/pango-hbfont.c
@@ -47,7 +47,7 @@
* matrix.
*/
- /* {{{ Utilities */
+/* {{{ Utilities */
static int
get_average_char_width (PangoFont *font,
@@ -763,6 +763,7 @@ static PangoFontMetrics *
pango_hb_font_get_metrics (PangoFont *font,
PangoLanguage *language)
{
+ PangoHbFont *self = PANGO_HB_FONT (font);
hb_font_t *hb_font = pango_font_get_hb_font (font);
PangoFontMetrics *metrics;
hb_font_extents_t extents;
@@ -796,17 +797,62 @@ pango_hb_font_get_metrics (PangoFont *font,
else
metrics->strikethrough_position = metrics->ascent / 2;
- metrics->approximate_char_width = get_average_char_width (font, pango_language_get_sample_string
(language));
- get_max_char_size (font, "0123456789", &metrics->approximate_digit_width, NULL);
+ if (self->approximate_char_width == 0 || self->approximate_char_lang != language)
+ {
+ self->approximate_char_width = get_average_char_width (font, pango_language_get_sample_string
(language));
+ self->approximate_char_lang = language;
+ }
+
+ if (self->approximate_digit_width == 0)
+ get_max_char_size (font, "0123456789", &self->approximate_digit_width, NULL);
+
+ metrics->approximate_char_width = self->approximate_char_width;
+ metrics->approximate_digit_width = self->approximate_digit_width;
return metrics;
}
+static hb_bool_t
+nominal_glyph_func (hb_font_t *font, void *font_data,
+ hb_codepoint_t unicode,
+ hb_codepoint_t *glyph,
+ void *user_data)
+{
+ PangoHbFont *self = font_data;
+ PangoUserFontFuncs *user_font = self->face->user_font;
+
+ return user_font->glyph_func (self->face, unicode, glyph, user_font->user_data);
+}
+
+static hb_position_t
+glyph_h_advance_func (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ void *user_data)
+{
+ PangoHbFont *self = font_data;
+ PangoUserFontFuncs *user_font = self->face->user_font;
+ int size = self->size * self->dpi / 72.;
+
+ return user_font->advance_func (self->face, size, glyph, user_font->user_data);
+}
+
+static hb_bool_t
+glyph_extents_func (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ hb_glyph_extents_t *extents,
+ void *user_data)
+{
+ PangoHbFont *self = font_data;
+ PangoUserFontFuncs *user_font = self->face->user_font;
+ int size = self->size * self->dpi / 72.;
+
+ return user_font->extents_func (self->face, size, glyph, extents, user_font->user_data);
+}
+
static hb_font_t *
pango_hb_font_create_hb_font (PangoFont *font)
{
PangoHbFont *self = PANGO_HB_FONT (font);
- hb_face_t *hb_face;
hb_font_t *hb_font;
double x_scale, y_scale;
unsigned int n_axes;
@@ -814,8 +860,32 @@ pango_hb_font_create_hb_font (PangoFont *font)
float *coords;
int size;
- hb_face = pango_hb_face_get_hb_face (self->face);
- hb_font = hb_font_create (hb_face);
+ if (self->face->user_font)
+ {
+ hb_blob_t *blob;
+ hb_face_t *face;
+ hb_font_funcs_t *funcs;
+
+ blob = hb_blob_create ("", 0, HB_MEMORY_MODE_READONLY, NULL, NULL);
+ face = hb_face_create (blob, 0);
+ hb_font = hb_font_create (face);
+
+ funcs = hb_font_funcs_create ();
+
+ hb_font_funcs_set_nominal_glyph_func (funcs, nominal_glyph_func, NULL, NULL);
+ hb_font_funcs_set_glyph_h_advance_func (funcs, glyph_h_advance_func, NULL, NULL);
+ hb_font_funcs_set_glyph_extents_func (funcs, glyph_extents_func, NULL, NULL);
+
+ hb_font_set_funcs (hb_font, funcs, self, NULL);
+
+ hb_font_funcs_destroy (funcs);
+ hb_face_destroy (face);
+ hb_blob_destroy (blob);
+ }
+ else
+ {
+ hb_font = hb_font_create (pango_hb_face_get_hb_face (self->face));
+ }
size = self->size * self->dpi / 72.f;
x_scale = self->face->x_scale;
@@ -843,7 +913,7 @@ pango_hb_font_create_hb_font (PangoFont *font)
axes = g_alloca (sizeof (hb_ot_var_axis_info_t) * n_axes);
coords = g_alloca (sizeof (float) * n_axes);
- hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, axes);
+ hb_ot_var_get_axis_infos (self->face->face, 0, &n_axes, axes);
if (self->face->instance_id >= 0)
hb_ot_var_named_instance_get_design_coords (self->face->face, self->face->instance_id, &n_axes,
coords);
@@ -1042,6 +1112,24 @@ pango_hb_font_new_for_description (PangoHbFace *face,
return pango_hb_font_new (face, size, features, n_features, variations, n_variations, gravity, dpi,
matrix);
}
+/**
+ * pango_hb_font_get_size:
+ * @font: a `PangoHbFont`
+ *
+ * Returns the size of the font in points, scaled by `PANGO_SCALE`.
+ *
+ * This is the same value that was passed as size to [ctor Pango HbFont new].
+ *
+ * Returns: the size of @font
+ */
+int
+pango_hb_font_get_size (PangoHbFont *font)
+{
+ g_return_val_if_fail (PANGO_IS_HB_FONT (font), 0);
+
+ return font->size;
+}
+
/* }}} */
/* vim:set foldmethod=marker expandtab: */
diff --git a/pango/pango-hbfont.h b/pango/pango-hbfont.h
index 1c747d97..cd2cabc9 100644
--- a/pango/pango-hbfont.h
+++ b/pango/pango-hbfont.h
@@ -48,3 +48,6 @@ PangoHbFont * pango_hb_font_new_for_description (PangoHbFace
float dpi,
const PangoMatrix *matrix);
G_END_DECLS
+
+PANGO_AVAILABLE_IN_1_52
+int pango_hb_font_get_size (PangoHbFont *font);
diff --git a/pango/pangocairo-font.c b/pango/pangocairo-font.c
index e265e540..84cb8364 100644
--- a/pango/pangocairo-font.c
+++ b/pango/pangocairo-font.c
@@ -73,6 +73,49 @@ _pango_cairo_font_private_scaled_font_data_destroy (PangoCairoFontPrivateScaledF
static FT_Library ft_library;
+static cairo_user_data_key_t cairo_user_data;
+
+static cairo_status_t
+render_func (cairo_scaled_font_t *scaled_font,
+ unsigned long glyph,
+ cairo_t *cr,
+ cairo_text_extents_t *extents)
+{
+ cairo_font_face_t *font_face;
+ PangoHbFont *font;
+ PangoUserFontFuncs *user_font;
+ hb_glyph_extents_t glyph_extents;
+ hb_position_t scaled_advance;
+
+ font_face = cairo_scaled_font_get_font_face (scaled_font);
+ font = cairo_font_face_get_user_data (font_face, &cairo_user_data);
+
+ user_font = font->face->user_font;
+ user_font->render_func (font->face, font->size,
+ (hb_codepoint_t)glyph,
+ user_font->user_data,
+ cr);
+
+ scaled_advance = user_font->advance_func (font->face, 1024,
+ (hb_codepoint_t)glyph,
+ user_font->user_data);
+
+ user_font->extents_func (font->face, 1024,
+ (hb_codepoint_t)glyph,
+ &glyph_extents,
+ user_font->user_data);
+
+ extents->x_bearing = glyph_extents.x_bearing / (double) 1024;
+ extents->y_bearing = glyph_extents.y_bearing / (double) 1024;
+ extents->width = glyph_extents.width / (double) 1024;
+ extents->height = glyph_extents.height / (double) 1024;
+
+ extents->x_advance = scaled_advance / (double) 1024;
+ extents->y_advance = 0.;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_font_face_t *
create_font_face_for_hb_font (PangoHbFont *font)
{
@@ -87,6 +130,14 @@ create_font_face_for_hb_font (PangoHbFont *font)
static const cairo_user_data_key_t key;
FT_Error error;
+ if (font->face->user_font)
+ {
+ cairo_face = cairo_user_font_face_create ();
+ cairo_font_face_set_user_data (cairo_face, &cairo_user_data, font, NULL);
+ cairo_user_font_face_set_render_glyph_func (cairo_face, render_func);
+ return cairo_face;
+ }
+
if (g_once_init_enter (&ft_library))
{
FT_Library library;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]