[pango/simple-fontmap: 16/17] wip: Introduce user fonts




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]