[pango/userfont: 3/15] Add a userfont example
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pango/userfont: 3/15] Add a userfont example
- Date: Fri, 28 Jan 2022 14:04:50 +0000 (UTC)
commit ff1e6ac5a8da7813285b50be70d195aa0cd8cb55
Author: Matthias Clasen <mclasen redhat com>
Date: Thu Jan 27 20:44:14 2022 -0500
Add a userfont example
This is a more-or-less direct adaptation of
the user-font test in cairo.
examples/meson.build | 1 +
examples/userfont.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 251 insertions(+)
---
diff --git a/examples/meson.build b/examples/meson.build
index 0ec3860e..f8e416f8 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -5,6 +5,7 @@ if pango_cairo_backends.contains('png')
'cairoshape',
'cairosimple',
'cairotwisted',
+ 'userfont',
]
endif
diff --git a/examples/userfont.c b/examples/userfont.c
new file mode 100644
index 00000000..41ca5621
--- /dev/null
+++ b/examples/userfont.c
@@ -0,0 +1,250 @@
+/* Example code to show how to use user fonts with Pango
+ *
+ * Written by Matthias Clasen, 2022
+ *
+ * Permission to use, copy, modify, distribute, and sell this example
+ * for any purpose is hereby granted without fee.
+ * It is provided "as is" without express or implied warranty.
+ *
+ * Font data taken from the cairo user-font test, written by
+ * Kristian Høgsberg <krh redhat com>
+ * Behdad Esfahbod <behdad behdad org>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <pango/pangocairo.h>
+#include <pango/pangofc-hbfontmap.h>
+
+static PangoFontMap *fontmap;
+
+#define END_GLYPH 0
+#define STROKE 126
+#define CLOSE 127
+
+/* Simple glyph definition: 1 - 15 means lineto (or moveto for first
+ * point) for one of the points on this grid:
+ *
+ * 1 2 3
+ * 4 5 6
+ * 7 8 9
+ * ----10 11 12----(baseline)
+ * 13 14 15
+ */
+typedef struct
+{
+ gunichar ucs4;
+ int width;
+ char data[16];
+} test_scaled_font_glyph_t;
+
+/* Simple glyph definition: 1 - 15 means lineto (or moveto for first
+ * point) for one of the points on this grid:
+ *
+ * 1 2 3
+ * 4 5 6
+ * 7 8 9
+ * ----10 11 12----(baseline)
+ * 13 14 15
+ */
+static const test_scaled_font_glyph_t glyphs [] = {
+ { 'a', 3, { 4, 6, 12, 10, 7, 9, STROKE, END_GLYPH } },
+ { 'c', 3, { 6, 4, 10, 12, STROKE, END_GLYPH } },
+ { 'e', 3, { 12, 10, 4, 6, 9, 7, STROKE, END_GLYPH } },
+ { 'f', 3, { 3, 2, 11, STROKE, 4, 6, STROKE, END_GLYPH } },
+ { 'g', 3, { 12, 10, 4, 6, 15, 13, STROKE, END_GLYPH } },
+ { 'h', 3, { 1, 10, STROKE, 7, 5, 6, 12, STROKE, END_GLYPH } },
+ { 'i', 1, { 1, 1, STROKE, 4, 10, STROKE, END_GLYPH } },
+ { 'l', 1, { 1, 10, STROKE, END_GLYPH } },
+ { 'n', 3, { 10, 4, STROKE, 7, 5, 6, 12, STROKE, END_GLYPH } },
+ { 'o', 3, { 4, 10, 12, 6, CLOSE, END_GLYPH } },
+ { 'p', 3, { 4, 10, 12, 6, CLOSE, 4, 13, STROKE, END_GLYPH } },
+ { 'r', 3, { 4, 10, STROKE, 7, 5, 6, STROKE, END_GLYPH } },
+ { 's', 3, { 6, 4, 7, 9, 12, 10, STROKE, END_GLYPH } },
+ { 't', 3, { 2, 11, 12, STROKE, 4, 6, STROKE, END_GLYPH } },
+ { 'u', 3, { 4, 10, 12, 6, STROKE, END_GLYPH } },
+ { 'z', 3, { 4, 6, 10, 12, STROKE, END_GLYPH } },
+ { ' ', 1, { END_GLYPH } },
+ { '-', 2, { 7, 8, STROKE, END_GLYPH } },
+ { '.', 1, { 10, 10, STROKE, END_GLYPH } },
+ { -1, 0, { END_GLYPH } },
+};
+
+const char text[] = "geez... pango user-font";
+
+static PangoLayout *
+get_layout (cairo_t *cr)
+{
+ PangoContext *context;
+ PangoLayout *layout;
+ PangoFontDescription *desc;
+
+ /* Create a PangoLayout, set the font and text */
+ context = pango_font_map_create_context (fontmap);
+ layout = pango_layout_new (context);
+ g_object_unref (context);
+
+ pango_layout_set_text (layout, text, -1);
+
+ desc = pango_font_description_from_string ("Userfont 12");
+ pango_layout_set_font_description (layout, desc);
+ pango_font_description_free (desc);
+
+ return layout;
+}
+
+static gboolean
+glyph_cb (PangoHbFace *face,
+ hb_codepoint_t unicode,
+ hb_codepoint_t *glyph,
+ gpointer user_data)
+{
+ test_scaled_font_glyph_t *glyphs = user_data;
+
+ for (int i = 0; glyphs[i].ucs4 != (gunichar) -1; i++)
+ {
+ if (glyphs[i].ucs4 == unicode)
+ {
+ *glyph = i;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static hb_position_t
+advance_cb (PangoHbFace *face,
+ int size,
+ hb_codepoint_t glyph,
+ gpointer user_data)
+{
+ test_scaled_font_glyph_t *glyphs = user_data;
+
+ return glyphs[glyph].width / 4.0 * size;
+}
+
+static gboolean
+extents_cb (PangoHbFace *face,
+ int size,
+ hb_codepoint_t glyph,
+ hb_glyph_extents_t *extents,
+ gpointer user_data)
+{
+ extents->x_bearing = 0;
+ extents->y_bearing = - 0.75 * size;
+ extents->width = glyphs[glyph].width / 4.0 * size;
+ extents->height = size;
+
+ return TRUE;
+}
+
+static void
+render_cb (PangoHbFace *face,
+ int size,
+ hb_codepoint_t glyph,
+ gpointer user_data,
+ gpointer backend_data)
+{
+ test_scaled_font_glyph_t *glyphs = user_data;
+ cairo_t *cr = backend_data;
+ const char *data;
+ div_t d;
+ double x, y;
+
+ cairo_set_line_width (cr, 0.1);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+
+ data = glyphs[glyph].data;
+ for (int i = 0; data[i] != END_GLYPH; i++)
+ {
+ switch (data[i])
+ {
+ case STROKE:
+ cairo_new_sub_path (cr);
+ break;
+
+ case CLOSE:
+ cairo_close_path (cr);
+ break;
+
+ default:
+ d = div (data[i] - 1, 3);
+ x = d.rem / 4.0 + 0.125;
+ y = d.quot / 5.0 + 0.4 - 1.0;
+ cairo_line_to (cr, x, y);
+ }
+ }
+
+ cairo_stroke (cr);
+}
+
+static void
+setup_fontmap (PangoHbFontMap *fontmap)
+{
+ PangoFontDescription *desc;
+ PangoHbFace *face;
+
+ desc = pango_font_description_new ();
+ pango_font_description_set_family (desc, "Userfont");
+ face = pango_hb_face_new_user (glyph_cb, advance_cb, extents_cb, render_cb,
+ (gpointer) glyphs, NULL,
+ "Black", desc);
+ pango_hb_font_map_add_face (fontmap, face);
+ pango_font_description_free (desc);
+}
+
+int
+main (int argc, char **argv)
+{
+ cairo_t *cr;
+ char *filename;
+ cairo_status_t status;
+ cairo_surface_t *surface;
+ PangoLayout *layout;
+ int width, height;
+
+ if (argc != 2)
+ {
+ g_printerr ("Usage: userfont OUTPUT_FILENAME\n");
+ return 1;
+ }
+
+ filename = argv[1];
+
+ fontmap = PANGO_FONT_MAP (pango_fc_hb_font_map_new ());
+ setup_fontmap (PANGO_HB_FONT_MAP (fontmap));
+
+ layout = get_layout (cr);
+
+ pango_layout_get_pixel_size (layout, &width, &height);
+
+ /* Now create the final surface and draw to it. */
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width + 20, height + 20);
+ cr = cairo_create (surface);
+
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_paint (cr);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.5);
+
+ cairo_move_to (cr, 10, 10);
+ pango_cairo_show_layout (cr, layout);
+
+ cairo_destroy (cr);
+
+ g_object_unref (layout);
+
+ /* Write out the surface as PNG */
+ status = cairo_surface_write_to_png (surface, filename);
+ cairo_surface_destroy (surface);
+
+ if (status != CAIRO_STATUS_SUCCESS)
+ {
+ g_printerr ("Could not save png to '%s': %s\n", filename, cairo_status_to_string (status));
+ return 1;
+ }
+
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]