summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2022-06-26 10:12:48 -0400
committerMatthias Clasen <mclasen@redhat.com>2022-07-04 11:17:28 -0400
commitbd052ba5190fc79dae469df80d00ed91d279f9b4 (patch)
treef5c55be3c2e01a34ba90b73b466e3394b77f9eef
parent29057df96c1373938d73fb43c82251698993082f (diff)
downloadpango-bd052ba5190fc79dae469df80d00ed91d279f9b4.tar.gz
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.
-rw-r--r--examples/cairoshape.c6
-rw-r--r--examples/cairosimple.c5
-rw-r--r--examples/cairotwisted.c5
-rw-r--r--examples/columns.c13
-rw-r--r--examples/first-steps.c5
-rw-r--r--examples/meson.build20
-rw-r--r--examples/parshape.c13
-rw-r--r--examples/userfont.c5
-rw-r--r--meson.build15
-rw-r--r--pango2/meson.build7
-rw-r--r--pango2/pangocairo-coretext-font.c51
-rw-r--r--pango2/pangocairo-dwrite-font.cpp10
-rw-r--r--pango2/pangocairo-font.c219
-rw-r--r--pango2/pangocairo-ft-font.c99
-rw-r--r--pango2/pangocairo-private.h15
-rw-r--r--pango2/pangocairo-user-font.c123
-rw-r--r--utils/viewer-pangocairo.c6
17 files changed, 390 insertions, 227 deletions
diff --git a/examples/cairoshape.c b/examples/cairoshape.c
index a778cd76..cdb08702 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 75bc30b3..70c0098c 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 d809703c..99dacd35 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 514d71dd..3db7a892 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 50f1ab28..692c81de 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 e2c13873..4455a2a6 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 0f3f3096..0f0fbb41 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 930ad2cf..3c8735c7 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 1d371b5c..4634faa7 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 8dce43d8..dbe56249 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 00000000..e8f0faca
--- /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 ed5b4f0c..7068d59f 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 3eda3d5a..6536671d 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 00000000..f8595ac0
--- /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 d3ad6994..be9fa8cf 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 00000000..edf49457
--- /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 df391259..252e5744 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,