[pango/pango2: 5/10] Redo the cairo backend code




commit f53d87e8da407892124bdd2c4616b81832efcc57
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Jun 26 10:12:48 2022 -0400

    Redo the cairo backend code
    
    We need to be more careful when creating a cairo
    font face. Even on Windows or macOS, we may encounter
    hb_font_t's that haven't been created from a native
    font, so we need to handle those (if we have freetype).
    
    Also simplify the cairo build machinery a bit, and
    rely more on cairo-features.h.

 examples/cairoshape.c             |   6 ++
 examples/cairosimple.c            |   5 +
 examples/cairotwisted.c           |   5 +
 examples/columns.c                |  13 ++-
 examples/first-steps.c            |   5 +
 examples/meson.build              |  20 ++--
 examples/parshape.c               |  13 ++-
 examples/userfont.c               |   5 +
 meson.build                       |  15 ++-
 pango2/meson.build                |   7 ++
 pango2/pangocairo-coretext-font.c |  51 +++++++++
 pango2/pangocairo-dwrite-font.cpp |  10 +-
 pango2/pangocairo-font.c          | 219 ++++----------------------------------
 pango2/pangocairo-ft-font.c       |  99 +++++++++++++++++
 pango2/pangocairo-private.h       |  15 ++-
 pango2/pangocairo-user-font.c     | 123 +++++++++++++++++++++
 utils/viewer-pangocairo.c         |   6 +-
 17 files changed, 390 insertions(+), 227 deletions(-)
---
diff --git a/examples/cairoshape.c b/examples/cairoshape.c
index a778cd760..cdb08702a 100644
--- a/examples/cairoshape.c
+++ b/examples/cairoshape.c
@@ -314,7 +314,13 @@ main (int argc, char **argv)
   cairo_destroy (cr);
 
   /* Write out the surface as PNG */
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
   status = cairo_surface_write_to_png (surface, filename);
+#else
+  status = CAIRO_STATUS_PNG_ERROR; /* Not technically correct, but... */
+#endif
+
   cairo_surface_destroy (surface);
 
   if (status != CAIRO_STATUS_SUCCESS)
diff --git a/examples/cairosimple.c b/examples/cairosimple.c
index 75bc30b35..70c0098ce 100644
--- a/examples/cairosimple.c
+++ b/examples/cairosimple.c
@@ -80,7 +80,12 @@ main (int argc, char **argv)
   draw_text (cr);
   cairo_destroy (cr);
 
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
   status = cairo_surface_write_to_png (surface, filename);
+#else
+  status = CAIRO_STATUS_PNG_ERROR; /* Not technically correct, but... */
+#endif
+
   cairo_surface_destroy (surface);
 
   if (status != CAIRO_STATUS_SUCCESS)
diff --git a/examples/cairotwisted.c b/examples/cairotwisted.c
index d809703c8..99dacd356 100644
--- a/examples/cairotwisted.c
+++ b/examples/cairotwisted.c
@@ -612,7 +612,12 @@ int main (int argc, char **argv)
 
   cairo_destroy (cr);
 
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
   status = cairo_surface_write_to_png (surface, filename);
+#else
+  status = CAIRO_STATUS_PNG_ERROR; /* Not technically correct, but... */
+#endif
+
   cairo_surface_destroy (surface);
 
   if (status != CAIRO_STATUS_SUCCESS)
diff --git a/examples/columns.c b/examples/columns.c
index 514d71dd9..3db7a892c 100644
--- a/examples/columns.c
+++ b/examples/columns.c
@@ -13,6 +13,7 @@ main (int argc, char *argv[])
   Pango2Lines *lines;
   cairo_surface_t *surface;
   cairo_t *cr;
+  cairo_status_t status;
   char *text;
   gsize length;
   Pango2AttrList *attrs;
@@ -116,8 +117,16 @@ retry:
 
   pango2_cairo_show_lines (cr, lines);
 
-  cairo_surface_write_to_png (surface, filename);
-  g_print ("Output written to %s\n", filename);
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+  status = cairo_surface_write_to_png (surface, filename);
+#else
+  status = CAIRO_STATUS_PNG_ERROR; /* Not technically correct, but... */
+#endif
+
+  if (status != CAIRO_STATUS_SUCCESS)
+    g_printerr ("Could not save png to '%s'\n", filename);
+  else
+    g_print ("Output written to %s\n", filename);
 
   g_object_unref (lines);
   g_object_unref (breaker);
diff --git a/examples/first-steps.c b/examples/first-steps.c
index 50f1ab28d..692c81de5 100644
--- a/examples/first-steps.c
+++ b/examples/first-steps.c
@@ -62,7 +62,12 @@ main (int argc, char **argv)
 
   cairo_destroy (cr);
 
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
   status = cairo_surface_write_to_png (surface, filename);
+#else
+  status = CAIRO_STATUS_PNG_ERROR; /* Not technically correct, but... */
+#endif
+
   cairo_surface_destroy (surface);
 
   if (status != CAIRO_STATUS_SUCCESS)
diff --git a/examples/meson.build b/examples/meson.build
index e2c138733..4455a2a6f 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -1,16 +1,14 @@
 examples = []
 
-if cairo_png_dep.found()
-  examples += [
-    'first-steps',
-    'cairoshape',
-    'cairosimple',
-    'cairotwisted',
-    'parshape',
-    'columns',
-    'userfont',
-  ]
-endif
+examples += [
+  'first-steps',
+  'cairoshape',
+  'cairosimple',
+  'cairotwisted',
+  'parshape',
+  'columns',
+  'userfont',
+]
 
 examples_deps = [ libpango_dep ]
 
diff --git a/examples/parshape.c b/examples/parshape.c
index 0f3f30966..0f0fbb41b 100644
--- a/examples/parshape.c
+++ b/examples/parshape.c
@@ -100,6 +100,7 @@ main (int argc, char *argv[])
   char *text;
   gsize length;
   GError *error = NULL;
+  cairo_status_t status;
 
   if (argc != 3)
     {
@@ -125,8 +126,16 @@ main (int argc, char *argv[])
   draw_lines (cr, lines);
   g_object_unref (lines);
 
-  cairo_surface_write_to_png (surface, filename);
-  g_print ("Output written to %s\n", filename);
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+  status = cairo_surface_write_to_png (surface, filename);
+#else
+  status = CAIRO_STATUS_PNG_ERROR; /* Not technically correct, but... */
+#endif
+
+  if (status != CAIRO_STATUS_SUCCESS)
+    g_printerr ("Could not save png to '%s'\n", filename);
+  else
+    g_print ("Output written to %s\n", filename);
 
   cairo_surface_destroy (surface);
   cairo_destroy (cr);
diff --git a/examples/userfont.c b/examples/userfont.c
index 930ad2cf9..3c8735c7a 100644
--- a/examples/userfont.c
+++ b/examples/userfont.c
@@ -344,7 +344,12 @@ main (int argc, char **argv)
   g_object_unref (layout);
 
   /* Write out the surface as PNG */
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
   status = cairo_surface_write_to_png (surface, filename);
+#else
+  status = CAIRO_STATUS_PNG_ERROR; /* Not technically correct, but... */
+#endif
+
   cairo_surface_destroy (surface);
 
   if (status != CAIRO_STATUS_SUCCESS)
diff --git a/meson.build b/meson.build
index 1d371b5cb..4634faa7a 100644
--- a/meson.build
+++ b/meson.build
@@ -295,6 +295,8 @@ else
   fontconfig_dep = disabler()
 endif
 
+cairo_pkg = 'cairo-ft'
+
 if host_system == 'darwin'
   if not cc.links('''#include <CoreText/CoreText.h>
                               int main (void) {
@@ -309,6 +311,8 @@ if host_system == 'darwin'
   pango_conf.set('HAVE_CORE_TEXT', 1)
 
   pango_deps += dependency('appleframeworks', modules: [ 'CoreFoundation', 'ApplicationServices' ])
+
+  cairo_pkg = 'cairo-quartz-font'
 endif
 
 if host_system == 'windows'
@@ -318,22 +322,25 @@ if host_system == 'windows'
     cc.find_library('gdi32'),
     cc.find_library('dwrite'),
   ]
+
+  cairo_pkg = 'cairo-win32-dwrite-font'
 endif
 
 if get_option('cairo').disabled()
   cairo_dep = disabler()
-  cairo_png_dep = disabler()
   cairo_xlib_dep = disabler()
+  cairo_ft_dep = disabler()
 else
-  cairo_dep = dependency('cairo', version: cairo_req_version,
+  cairo_dep = dependency(cairo_pkg, version: cairo_req_version,
                          fallback: ['cairo', 'libcairo_dep'], required: get_option('cairo'))
-  cairo_png_dep = dependency('cairo-png', required: false)
   cairo_xlib_dep = dependency('cairo-xlib', required: false)
+  cairo_ft_dep = dependency('cairo-ft', required: false)
 endif
 
 pango_conf.set('HAVE_CAIRO', cairo_dep.found ())
-pango_conf.set('HAVE_CAIRO_PNG', cairo_dep.found() and cairo_png_dep.found())
 pango_conf.set('HAVE_CAIRO_XLIB', cairo_dep.found() and cairo_xlib_dep.found())
+pango_conf.set('HAVE_CAIRO_FT', cairo_dep.found() and cairo_xlib_dep.found())
+
 if cairo_dep.found()
   pango_deps += cairo_dep
 endif
diff --git a/pango2/meson.build b/pango2/meson.build
index 8dce43d8c..dbe562497 100644
--- a/pango2/meson.build
+++ b/pango2/meson.build
@@ -109,6 +109,8 @@ if cairo_dep.found()
     'pangocairo-context.c',
     'pangocairo-font.c',
     'pangocairo-render.c',
+    'pangocairo-user-font.c',
+    'pangocairo-ft-font.c',
   ]
 
   pango_gir_includes += [
@@ -124,6 +126,11 @@ if host_system == 'darwin'
   pango_sources += [
     'pangocoretext-fontmap.c',
   ]
+  if cairo_dep.found()
+    pango_sources += [
+      'pangocairo-coretext-font.c',
+    ]
+  endif
 endif
 
 if host_system == 'linux'
diff --git a/pango2/pangocairo-coretext-font.c b/pango2/pangocairo-coretext-font.c
new file mode 100644
index 000000000..e8f0faca2
--- /dev/null
+++ b/pango2/pangocairo-coretext-font.c
@@ -0,0 +1,51 @@
+/*
+ * pangocairo-coretext-font.c: CoreText font handling
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "pangocairo-private.h"
+#include "pango-font.h"
+
+#include <Carbon/Carbon.h>
+#include <cairo-quartz.h>
+#include <hb-coretext.h>
+
+cairo_font_face_t *
+create_cairo_core_text_font_face (Pango2Font *font)
+{
+  hb_font_t *hbfont;
+  CTFontRef ctfont;
+  CGFontRef cgfont;
+  cairo_font_face_t *cairo_face;
+
+  hbfont = pango2_font_get_hb_font (font);
+  ctfont = hb_coretext_font_get_ct_font (hbfont);
+
+  if (!ctfont)
+    return NULL;
+
+  cgfont = CTFontCopyGraphicsFont (ctfont, NULL);
+  cairo_face = cairo_quartz_font_face_create_for_cgfont (cgfont);
+  CFRelease (cgfont);
+
+  return cairo_face;
+}
+
diff --git a/pango2/pangocairo-dwrite-font.cpp b/pango2/pangocairo-dwrite-font.cpp
index ed5b4f0c9..7068d59f6 100644
--- a/pango2/pangocairo-dwrite-font.cpp
+++ b/pango2/pangocairo-dwrite-font.cpp
@@ -32,16 +32,16 @@
 
 /* {{{ DirectWrite PangoCairo utilities */
 cairo_font_face_t *
-pango_cairo_create_font_face_for_dwrite_pango_font (PangoFont *font)
+create_cairo_dwrite_font_face (Pango2Font *font)
 {
   hb_font_t *hb_font;
   IDWriteFontFace *dwrite_font_face = NULL;
-  cairo_font_face_t *result;
+  cairo_font_face_t *result = NULL;
 
-  hb_font = pango_font_get_hb_font (font);
+  hb_font = pango2_font_get_hb_font (font);
   dwrite_font_face = hb_directwrite_face_get_font_face (hb_font_get_face (hb_font));
-
-  result = cairo_dwrite_font_face_create_for_dwrite_fontface (dwrite_font_face);
+  if (dwrite_font_face)
+    result = cairo_dwrite_font_face_create_for_dwrite_fontface (dwrite_font_face);
 
   return result;
 }
diff --git a/pango2/pangocairo-font.c b/pango2/pangocairo-font.c
index 3eda3d5a0..6536671de 100644
--- a/pango2/pangocairo-font.c
+++ b/pango2/pangocairo-font.c
@@ -35,20 +35,6 @@
 #include "pango-userface-private.h"
 #include "pango-font-private.h"
 
-#if defined (HAVE_CORE_TEXT)
-
-#include <Carbon/Carbon.h>
-#include <cairo-quartz.h>
-#include <hb-coretext.h>
-
-#elif defined (HAVE_FONTCONFIG)
-
-#include <hb-ot.h>
-#include <cairo-ft.h>
-#include <freetype/ftmm.h>
-
-#endif
-
 static Pango2CairoFontPrivate * _pango2_font_get_cairo_font_private (Pango2Font *font);
 static cairo_scaled_font_t * _pango2_font_get_scaled_font (Pango2Font *font);
 static void _pango2_cairo_font_private_initialize (Pango2CairoFontPrivate     *cf_priv,
@@ -77,197 +63,35 @@ _pango2_cairo_font_private_scaled_font_data_destroy (Pango2CairoFontPrivateScale
     }
 }
 
-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;
-  Pango2Font *font;
-  Pango2UserFace *face;
-  hb_glyph_extents_t glyph_extents;
-  hb_position_t h_advance;
-  hb_position_t v_advance;
-  gboolean is_color;
-
-  font_face = cairo_scaled_font_get_font_face (scaled_font);
-  font = cairo_font_face_get_user_data (font_face, &cairo_user_data);
-  face = PANGO2_USER_FACE (font->face);
-
-  extents->x_bearing = 0;
-  extents->y_bearing = 0;
-  extents->width = 0;
-  extents->height = 0;
-  extents->x_advance = 0;
-  extents->y_advance = 0;
-
-  if (!face->glyph_info_func (face, 1024,
-                              (hb_codepoint_t)glyph,
-                              &glyph_extents,
-                              &h_advance, &v_advance,
-                              &is_color,
-                              face->user_data))
-    {
-      return CAIRO_STATUS_USER_FONT_ERROR;
-    }
-
-  extents->x_bearing = glyph_extents.x_bearing / 1024.;
-  extents->y_bearing = - glyph_extents.y_bearing / 1024.;
-  extents->width = glyph_extents.width / 1024.;
-  extents->height = - glyph_extents.height / 1024.;
-  extents->x_advance = h_advance / 1024.;
-  extents->y_advance = v_advance / 1024.;
-
-  if (!face->render_func (face, font->size,
-                          (hb_codepoint_t)glyph,
-                          face->user_data,
-                          "cairo",
-                          cr))
-    {
-      return CAIRO_STATUS_USER_FONT_ERROR;
-    }
-
-  return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-init_func (cairo_scaled_font_t  *scaled_font,
-           cairo_t              *cr,
-           cairo_font_extents_t *extents)
-{
-  cairo_font_face_t *cairo_face;
-  Pango2Font *font;
-  Pango2UserFace *face;
-  hb_font_extents_t font_extents;
-
-  cairo_face = cairo_scaled_font_get_font_face (scaled_font);
-  font = cairo_font_face_get_user_data (cairo_face, &cairo_user_data);
-  face = (Pango2UserFace *) pango2_font_get_face (font);
-
-  face->font_info_func (face,
-                        pango2_font_get_size (font),
-                        &font_extents,
-                        face->user_data);
-
-  extents->ascent = font_extents.ascender / (font_extents.ascender + font_extents.descender);
-  extents->descent = font_extents.descender / (font_extents.ascender + font_extents.descender);
-
-  return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_font_face_t *
-create_cairo_font_face_for_user_font (Pango2Font *font)
-{
-  cairo_font_face_t *cairo_face;
-
-  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_init_func (cairo_face, init_func);
-  cairo_user_font_face_set_render_color_glyph_func (cairo_face, render_func);
-
-  return cairo_face;
-}
-
-#if defined (HAVE_CORE_TEXT)
-
 static cairo_font_face_t *
-create_cairo_font_face_for_hb_font (Pango2Font *font)
+create_cairo_font_face (Pango2Font *font)
 {
-  hb_font_t *hbfont;
-  CTFontRef ctfont;
-  CGFontRef cgfont;
   cairo_font_face_t *cairo_face;
 
-  hbfont = pango2_font_get_hb_font (font);
-  ctfont = hb_coretext_font_get_ct_font (hbfont);
-  cgfont = CTFontCopyGraphicsFont (ctfont, NULL);
+  if (PANGO2_IS_USER_FONT (font))
+    return create_cairo_user_font_face (font);
 
-  cairo_face = cairo_quartz_font_face_create_for_cgfont (cgfont);
-
-  CFRelease (cgfont);
-
-  return cairo_face;
-}
-
-#elif defined (HAVE_DIRECT_WRITE)
-
-static cairo_font_face_t *
-create_cairo_font_face_for_hb_font (Pango2Font *font)
-{
-  return pango2_cairo_create_font_face_for_dwrite_pango2_font (font);
-}
-
-#else
-
-static cairo_font_face_t *
-create_cairo_font_face_for_hb_font (Pango2Font *font)
-{
-  static FT_Library ft_library;
-
-  Pango2HbFace *face = PANGO2_HB_FACE (font->face);
-  hb_blob_t *blob;
-  const char *blob_data;
-  unsigned int blob_length;
-  FT_Face ft_face;
-  hb_font_t *hb_font;
-  unsigned int num_coords;
-  const int *coords;
-  cairo_font_face_t *cairo_face;
-  static const cairo_user_data_key_t key;
-  static const cairo_user_data_key_t key2;
-  FT_Error error;
-
-  if (g_once_init_enter (&ft_library))
-    {
-      FT_Library library;
-      FT_Init_FreeType (&library);
-      g_once_init_leave (&ft_library, library);
-    }
-
-  hb_font = pango2_font_get_hb_font (font);
-  blob = hb_face_reference_blob (hb_font_get_face (hb_font));
-  blob_data = hb_blob_get_data (blob, &blob_length);
-
-  if ((error = FT_New_Memory_Face (ft_library,
-                                   (const FT_Byte *) blob_data,
-                                   blob_length,
-                                   hb_face_get_index (face->face),
-                                   &ft_face)) != 0)
-    {
-      hb_blob_destroy (blob);
-      g_warning ("FT_New_Memory_Face failed: %d %s", error, FT_Error_String (error));
-      return NULL;
-    }
-
-  coords = hb_font_get_var_coords_normalized (hb_font, &num_coords);
-  if (num_coords > 0)
-    {
-      FT_Fixed *ft_coords = (FT_Fixed *) g_alloca (num_coords * sizeof (FT_Fixed));
-
-      for (unsigned int i = 0; i < num_coords; i++)
-        ft_coords[i] = coords[i] << 2;
-
-      FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
-    }
-
-  cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, FT_LOAD_NO_HINTING | FT_LOAD_COLOR);
+#ifdef HAVE_CORE_TEXT
+  cairo_face = create_cairo_core_text_font_face (font);
+  if (cairo_face)
+    return cairo_face;
+#endif
 
-  if (face->embolden)
-    cairo_ft_font_face_set_synthesize (cairo_face, CAIRO_FT_SYNTHESIZE_BOLD);
+#ifdef HAVE_DIRECT_WRITE
+  cairo_face = create_dwrite_font_face (font);
+  if (cairo_face)
+    return cairo_face;
+#endif
 
-  cairo_font_face_set_user_data (cairo_face, &key,
-                                 ft_face, (cairo_destroy_func_t) FT_Done_Face);
-  cairo_font_face_set_user_data (cairo_face, &key2,
-                                 blob, (cairo_destroy_func_t) hb_blob_destroy);
+#ifdef CAIRO_HAS_FT_FONT
+  cairo_face = create_cairo_ft_font_face (font);
+  if (cairo_face)
+    return cairo_face;
+#endif
 
-  return cairo_face;
+  return NULL;
 }
 
-#endif
-
 static cairo_scaled_font_t *
 _pango2_cairo_font_private_get_scaled_font (Pango2CairoFontPrivate *cf_priv)
 {
@@ -284,10 +108,7 @@ _pango2_cairo_font_private_get_scaled_font (Pango2CairoFontPrivate *cf_priv)
       return NULL;
     }
 
-  if (PANGO2_IS_HB_FONT (cf_priv->cfont))
-    font_face = create_cairo_font_face_for_hb_font (cf_priv->cfont);
-  else if (PANGO2_IS_USER_FONT (cf_priv->cfont))
-    font_face = create_cairo_font_face_for_user_font (cf_priv->cfont);
+  font_face = create_cairo_font_face (cf_priv->cfont);
 
   if (G_UNLIKELY (font_face == NULL))
     goto done;
diff --git a/pango2/pangocairo-ft-font.c b/pango2/pangocairo-ft-font.c
new file mode 100644
index 000000000..f8595ac0b
--- /dev/null
+++ b/pango2/pangocairo-ft-font.c
@@ -0,0 +1,99 @@
+/*
+ * pangocairo-ft-font.c: Freetype font handling
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "pango-features.h"
+#include "pangocairo-private.h"
+#include "pango-hbfont-private.h"
+#include "pango-hbface-private.h"
+
+#ifdef CAIRO_HAS_FT_FONT
+
+#include <hb-ot.h>
+#include <cairo-ft.h>
+#include <freetype/ftmm.h>
+
+cairo_font_face_t *
+create_cairo_ft_font_face (Pango2Font *font)
+{
+  static FT_Library ft_library;
+
+  Pango2HbFace *face = PANGO2_HB_FACE (font->face);
+  hb_blob_t *blob;
+  const char *blob_data;
+  unsigned int blob_length;
+  FT_Face ft_face;
+  hb_font_t *hb_font;
+  unsigned int num_coords;
+  const int *coords;
+  cairo_font_face_t *cairo_face;
+  static const cairo_user_data_key_t key;
+  static const cairo_user_data_key_t key2;
+  FT_Error error;
+
+  if (g_once_init_enter (&ft_library))
+    {
+      FT_Library library;
+      FT_Init_FreeType (&library);
+      g_once_init_leave (&ft_library, library);
+    }
+
+  hb_font = pango2_font_get_hb_font (font);
+  blob = hb_face_reference_blob (hb_font_get_face (hb_font));
+  blob_data = hb_blob_get_data (blob, &blob_length);
+
+  if ((error = FT_New_Memory_Face (ft_library,
+                                   (const FT_Byte *) blob_data,
+                                   blob_length,
+                                   hb_face_get_index (face->face),
+                                   &ft_face)) != 0)
+    {
+      hb_blob_destroy (blob);
+      g_warning ("FT_New_Memory_Face failed: %d %s", error, FT_Error_String (error));
+      return NULL;
+    }
+
+  coords = hb_font_get_var_coords_normalized (hb_font, &num_coords);
+  if (num_coords > 0)
+    {
+      FT_Fixed *ft_coords = (FT_Fixed *) g_alloca (num_coords * sizeof (FT_Fixed));
+
+      for (unsigned int i = 0; i < num_coords; i++)
+        ft_coords[i] = coords[i] << 2;
+
+      FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
+    }
+
+  cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, FT_LOAD_NO_HINTING | FT_LOAD_COLOR);
+
+  if (face->embolden)
+    cairo_ft_font_face_set_synthesize (cairo_face, CAIRO_FT_SYNTHESIZE_BOLD);
+
+  cairo_font_face_set_user_data (cairo_face, &key,
+                                 ft_face, (cairo_destroy_func_t) FT_Done_Face);
+  cairo_font_face_set_user_data (cairo_face, &key2,
+                                 blob, (cairo_destroy_func_t) hb_blob_destroy);
+
+  return cairo_face;
+}
+
+#endif
diff --git a/pango2/pangocairo-private.h b/pango2/pangocairo-private.h
index d3ad69941..be9fa8cf9 100644
--- a/pango2/pangocairo-private.h
+++ b/pango2/pangocairo-private.h
@@ -66,9 +66,22 @@ GType pango2_cairo_renderer_get_type    (void) G_GNUC_CONST;
 const cairo_font_options_t *
          pango2_cairo_context_get_merged_font_options (Pango2Context *context);
 
+cairo_font_face_t *
+create_cairo_user_font_face (Pango2Font *font);
+
+#ifdef CAIRO_HAS_FT_FONT
+cairo_font_face_t *
+create_cairo_ft_font_face (Pango2Font *font);
+#endif
+
+#ifdef HAVE_CORE_TEXT
+cairo_font_face_t *
+create_cairo_core_text_font_face (Pango2Font *font);
+#endif
+
 #ifdef HAVE_DIRECT_WRITE
 cairo_font_face_t *
-pango2_cairo_create_font_face_for_dwrite_pango2_font (Pango2Font *font);
+create_cairo_dwrite_font_face (Pango2Font *font);
 #endif
 
 G_END_DECLS
diff --git a/pango2/pangocairo-user-font.c b/pango2/pangocairo-user-font.c
new file mode 100644
index 000000000..edf494573
--- /dev/null
+++ b/pango2/pangocairo-user-font.c
@@ -0,0 +1,123 @@
+/*
+ * pangocairo-user-font.c: User font handling
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "pango-features.h"
+#include "pangocairo-private.h"
+#include "pango-userfont-private.h"
+#include "pango-userface-private.h"
+
+#include <hb-ot.h>
+
+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;
+  Pango2Font *font;
+  Pango2UserFace *face;
+  hb_glyph_extents_t glyph_extents;
+  hb_position_t h_advance;
+  hb_position_t v_advance;
+  gboolean is_color;
+
+  font_face = cairo_scaled_font_get_font_face (scaled_font);
+  font = cairo_font_face_get_user_data (font_face, &cairo_user_data);
+  face = PANGO2_USER_FACE (font->face);
+
+  extents->x_bearing = 0;
+  extents->y_bearing = 0;
+  extents->width = 0;
+  extents->height = 0;
+  extents->x_advance = 0;
+  extents->y_advance = 0;
+
+  if (!face->glyph_info_func (face, 1024,
+                              (hb_codepoint_t)glyph,
+                              &glyph_extents,
+                              &h_advance, &v_advance,
+                              &is_color,
+                              face->user_data))
+    {
+      return CAIRO_STATUS_USER_FONT_ERROR;
+    }
+
+  extents->x_bearing = glyph_extents.x_bearing / 1024.;
+  extents->y_bearing = - glyph_extents.y_bearing / 1024.;
+  extents->width = glyph_extents.width / 1024.;
+  extents->height = - glyph_extents.height / 1024.;
+  extents->x_advance = h_advance / 1024.;
+  extents->y_advance = v_advance / 1024.;
+
+  if (!face->render_func (face, font->size,
+                          (hb_codepoint_t)glyph,
+                          face->user_data,
+                          "cairo",
+                          cr))
+    {
+      return CAIRO_STATUS_USER_FONT_ERROR;
+    }
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+init_func (cairo_scaled_font_t  *scaled_font,
+           cairo_t              *cr,
+           cairo_font_extents_t *extents)
+{
+  cairo_font_face_t *cairo_face;
+  Pango2Font *font;
+  Pango2UserFace *face;
+  hb_font_extents_t font_extents;
+
+  cairo_face = cairo_scaled_font_get_font_face (scaled_font);
+  font = cairo_font_face_get_user_data (cairo_face, &cairo_user_data);
+  face = (Pango2UserFace *) pango2_font_get_face (font);
+
+  face->font_info_func (face,
+                        pango2_font_get_size (font),
+                        &font_extents,
+                        face->user_data);
+
+  extents->ascent = font_extents.ascender / (font_extents.ascender + font_extents.descender);
+  extents->descent = font_extents.descender / (font_extents.ascender + font_extents.descender);
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_font_face_t *
+create_cairo_user_font_face (Pango2Font *font)
+{
+  cairo_font_face_t *cairo_face;
+
+  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_init_func (cairo_face, init_func);
+  cairo_user_font_face_set_render_color_glyph_func (cairo_face, render_func);
+
+  return cairo_face;
+}
diff --git a/utils/viewer-pangocairo.c b/utils/viewer-pangocairo.c
index df3912590..252e57443 100644
--- a/utils/viewer-pangocairo.c
+++ b/utils/viewer-pangocairo.c
@@ -851,7 +851,7 @@ pangocairo_view_render (gpointer      instance,
   cairo_destroy (cr);
 }
 
-#ifdef HAVE_CAIRO_PNG
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
 static cairo_status_t
 write_func (void                *closure,
            const unsigned char *data,
@@ -993,7 +993,7 @@ pangocairo_view_get_option_group (const Pango2Viewer *klass G_GNUC_UNUSED)
 const Pango2Viewer pangocairo_viewer = {
   "Pango2Cairo",
   "cairo",
-#ifdef HAVE_CAIRO_PNG
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
   "png",
 #else
   NULL,
@@ -1004,7 +1004,7 @@ const Pango2Viewer pangocairo_viewer = {
   pangocairo_view_create_surface,
   pangocairo_view_destroy_surface,
   pangocairo_view_render,
-#ifdef HAVE_CAIRO_PNG
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
   pangocairo_view_write,
 #else
   NULL,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]