diff options
author | Matthias Clasen <mclasen@redhat.com> | 2022-01-27 00:47:16 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2022-01-28 18:43:39 -0500 |
commit | dde79b6cb99246966d411c5abdf6a0924631af64 (patch) | |
tree | 16b7901f9bfd4d0145f7d2e04b1f29d5713e5b7b | |
parent | 4c6078212a87f105fc5c5afba5ccfdf7569b3648 (diff) | |
download | pango-dde79b6cb99246966d411c5abdf6a0924631af64.tar.gz |
cairoshape: Use a user font
-rw-r--r-- | examples/cairoshape.c | 248 |
1 files changed, 175 insertions, 73 deletions
diff --git a/examples/cairoshape.c b/examples/cairoshape.c index d288db14..6a4d30e4 100644 --- a/examples/cairoshape.c +++ b/examples/cairoshape.c @@ -2,7 +2,7 @@ * inside a text layout, positioned by Pango. This has become possibly * using the following API added in Pango 1.18: * - * pango_cairo_context_set_shape_renderer () + * pango_cairo_context_set_shape_renderer () * * This examples uses a small parser to convert shapes in the format of * SVG paths to cairo instructions. You can typically extract these from @@ -25,15 +25,20 @@ #include <string.h> #include <pango/pangocairo.h> +#include <pango/pangofc-hbfontmap.h> + +static PangoFontMap *fontmap; #define BULLET "•" +#define HEART "♥" const char text[] = -"The GNOME project provides two things:\n" +"The GNOME project provides three things:\n" "\n" " • The GNOME desktop environment\n" " • The GNOME development platform\n" -" • Planet GNOME"; +" • Planet GNOME\n" +" ♥ Lots of love"; typedef struct { double width, height; @@ -52,114 +57,95 @@ static MiniSvg GnomeFootLogo = { static void mini_svg_render (MiniSvg *shape, - cairo_t *cr, - gboolean do_path) + cairo_t *cr, + gboolean do_path) { double x, y; const char *p; char op[2]; int len; + double x1, y1, x2, y2, x3, y3; cairo_get_current_point (cr, &x, &y); cairo_translate (cr, x, y); for (p = shape->path; sscanf (p, "%1s %n", op, &len), p += len, *p;) switch (*op) - { + { case 'M': - { - sscanf (p, "%lf,%lf %n", &x, &y, &len); p += len; - cairo_move_to (cr, x, y); - break; - } + sscanf (p, "%lf,%lf %n", &x, &y, &len); p += len; + cairo_move_to (cr, x, y); + break; case 'L': - { - sscanf (p, "%lf,%lf %n", &x, &y, &len); p += len; - cairo_line_to (cr, x, y); - break; - } + sscanf (p, "%lf,%lf %n", &x, &y, &len); p += len; + cairo_line_to (cr, x, y); + break; case 'C': - { - double x1, y1, x2, y2, x3, y3; - sscanf (p, "%lf,%lf %lf,%lf %lf,%lf %n", &x1, &y1, &x2, &y2, &x3, &y3, &len); p += len; - cairo_curve_to (cr, x1, y1, x2, y2, x3, y3); - break; - } + sscanf (p, "%lf,%lf %lf,%lf %lf,%lf %n", &x1, &y1, &x2, &y2, &x3, &y3, &len); p += len; + cairo_curve_to (cr, x1, y1, x2, y2, x3, y3); + break; case 'z': - { - cairo_close_path (cr); - break; - } - default: - { - g_warning ("Invalid MiniSvg operation '%c'", *op); - break; - } - } + cairo_close_path (cr); + break; + default: + g_warning ("Invalid MiniSvg operation '%c'", *op); + break; + } if (!do_path) cairo_fill (cr); } -static void -mini_svg_shape_renderer (cairo_t *cr, - PangoAttrShape *attr, - gboolean do_path, - gpointer data G_GNUC_UNUSED) -{ - MiniSvg *shape = (MiniSvg *) attr->data; - double scale_x, scale_y; - - scale_x = (double) attr->ink_rect.width / (PANGO_SCALE * shape->width ); - scale_y = (double) attr->ink_rect.height / (PANGO_SCALE * shape->height); - - cairo_rel_move_to (cr, - (double) attr->ink_rect.x / PANGO_SCALE, - (double) attr->ink_rect.y / PANGO_SCALE); - cairo_scale (cr, scale_x, scale_y); - - mini_svg_render (shape, cr, do_path); -} - - static PangoLayout * get_layout (cairo_t *cr) { + PangoContext *context; PangoLayout *layout; PangoAttrList *attrs; - PangoRectangle ink_rect = {1 * PANGO_SCALE, -11 * PANGO_SCALE, 8 * PANGO_SCALE, 10 * PANGO_SCALE}; - PangoRectangle logical_rect = {0 * PANGO_SCALE, -12 * PANGO_SCALE, 10 * PANGO_SCALE, 12 * PANGO_SCALE}; const char *p; /* Create a PangoLayout, set the font and text */ - layout = pango_cairo_create_layout (cr); - - pango_cairo_context_set_shape_renderer (pango_layout_get_context (layout), - mini_svg_shape_renderer, NULL, NULL); + context = pango_font_map_create_context (fontmap); + layout = pango_layout_new (context); + g_object_unref (context); pango_layout_set_text (layout, text, -1); attrs = pango_attr_list_new (); - /* Set gnome shape attributes for all bullets */ + PangoFontDescription *font_desc = pango_font_description_from_string ("Bullets 12"); + for (p = text; (p = strstr (p, BULLET)); p += strlen (BULLET)) { PangoAttribute *attr; - - attr = pango_attr_shape_new_with_data (&ink_rect, - &logical_rect, - &GnomeFootLogo, - NULL, NULL); + attr = pango_attr_font_desc_new (font_desc); attr->start_index = p - text; attr->end_index = attr->start_index + strlen (BULLET); + pango_attr_list_insert (attrs, attr); + } + + for (p = text; (p = strstr (p, HEART)); p += strlen (HEART)) + { + PangoAttribute *attr; + + attr = pango_attr_font_desc_new (font_desc); + attr->start_index = p - text; + attr->end_index = attr->start_index + strlen (HEART); + pango_attr_list_insert (attrs, attr); + attr = pango_attr_fallback_new (0); + attr->start_index = p - text; + attr->end_index = attr->start_index + strlen (HEART); pango_attr_list_insert (attrs, attr); } + pango_font_description_free (font_desc); + pango_layout_set_attributes (layout, attrs); pango_attr_list_unref (attrs); + return layout; } @@ -169,6 +155,8 @@ draw_text (cairo_t *cr, int *width, int *height) PangoLayout *layout = get_layout (cr); + pango_layout_write_to_file (layout, PANGO_LAYOUT_SERIALIZE_OUTPUT, "out.layout", NULL); + /* Adds a fixed 10-pixel margin on the sides. */ if (width || height) @@ -186,7 +174,122 @@ draw_text (cairo_t *cr, int *width, int *height) g_object_unref (layout); } -int main (int argc, char **argv) +static gboolean +glyph_cb (PangoUserFace *face, + hb_codepoint_t unicode, + hb_codepoint_t *glyph, + gpointer data) +{ + if (unicode == 0x2022 || /* bullet */ + unicode == 0x2665) /* heart */ + { + *glyph = unicode; + return TRUE; + } + + return FALSE; +} + +static gboolean +glyph_info_cb (PangoUserFace *face, + int size, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + hb_position_t *h_advance, + hb_position_t *v_advance, + gboolean *is_color, + gpointer user_data) +{ + if (glyph == 0x2022 || glyph == 0x2665) + { + extents->x_bearing = 0; + extents->y_bearing = - size; + extents->width = size; + extents->height = size; + + *h_advance = size; + *v_advance = size; + + *is_color = FALSE; + + return TRUE; + } + + return FALSE; +} + +static gboolean +font_info_cb (PangoUserFace *face, + int size, + hb_font_extents_t *extents, + gpointer user_data) +{ + extents->ascender = size; + extents->descender = 0; + extents->line_gap = 0; + + return TRUE; +} + +static gboolean +render_cb (PangoUserFace *face, + int size, + hb_codepoint_t glyph, + gpointer user_data, + const char *backend_id, + gpointer backend_data) +{ + cairo_t *cr = backend_data; + + if (strcmp (backend_id, "cairo") != 0) + return FALSE; + + if (glyph == 0x2022) + { + MiniSvg *shape = &GnomeFootLogo; + + cairo_move_to (cr, 0, -1); + cairo_scale (cr, 1. / shape->width, 1. / shape->height); + + mini_svg_render (shape, cr, FALSE); + } + else if (glyph == 0x2665) + { + cairo_set_source_rgb (cr, 1., 0., 0.); + + cairo_move_to (cr, .5, .0); + cairo_line_to (cr, .9, -.4); + cairo_curve_to (cr, 1.1, -.8, .5, -.9, .5, -.5); + cairo_curve_to (cr, .5, -.9, -.1, -.8, .1, -.4); + cairo_close_path (cr); + cairo_fill (cr); + } + + return TRUE; +} + +static void +setup_fontmap (PangoHbFontMap *fontmap) +{ + PangoFontDescription *desc; + PangoUserFace *face; + + desc = pango_font_description_new (); + pango_font_description_set_family (desc, "Bullets"); + + face = pango_user_face_new (font_info_cb, + glyph_cb, + glyph_info_cb, + NULL, + render_cb, + NULL, NULL, "Black", desc); + pango_hb_font_map_add_face (fontmap, PANGO_FONT_FACE (face)); + + pango_font_description_free (desc); +} + +int +main (int argc, char **argv) { cairo_t *cr; char *filename; @@ -202,18 +305,17 @@ int main (int argc, char **argv) filename = argv[1]; - /* First create and use a 0x0 surface, to measure how large - * the final surface needs to be */ - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - 0, 0); + fontmap = PANGO_FONT_MAP (pango_fc_hb_font_map_new ()); + setup_fontmap (PANGO_HB_FONT_MAP (fontmap)); + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); cr = cairo_create (surface); draw_text (cr, &width, &height); cairo_destroy (cr); cairo_surface_destroy (surface); /* Now create the final surface and draw to it. */ - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - width, height); + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); cr = cairo_create (surface); cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); @@ -228,7 +330,7 @@ int main (int argc, char **argv) if (status != CAIRO_STATUS_SUCCESS) { - g_printerr ("Could not save png to '%s'\n", filename); + g_printerr ("Could not save png to '%s': %s\n", filename, cairo_status_to_string (status)); return 1; } |