1/* Example code to show how to use pangocairo to render arbitrary shapes
2 * inside a text layout, positioned by Pango. This has become possibly
3 * using the following API added in Pango 1.18:
4 *
5 * pango_cairo_context_set_shape_renderer ()
6 *
7 * This examples uses a small parser to convert shapes in the format of
8 * SVG paths to cairo instructions. You can typically extract these from
9 * the SVG file's <path> elements directly.
10 *
11 * The code then searches for the Unicode bullet character in the layout
12 * text and automatically adds PangoAttribtues to the layout to replace
13 * each of the with a rendering of the GNOME Foot logo.
14 *
15 *
16 * Written by Behdad Esfahbod, 2007
17 *
18 * Permission to use, copy, modify, distribute, and sell this example
19 * for any purpose is hereby granted without fee.
20 * It is provided "as is" without express or implied warranty.
21 */
22
23
24#include <stdio.h>
25#include <string.h>
26
27#include <pango/pangocairo.h>
28
29#define BULLET "•"
30
31const char text[] =
32"The GNOME project provides two things:\n"
33"\n"
34" • The GNOME desktop environment\n"
35" • The GNOME development platform\n"
36" • Planet GNOME";
37
38typedef struct {
39 double width, height;
40 const char *path;
41} MiniSvg;
42
43static MiniSvg = {
44 96.2152, 118.26,
45 "M 86.068,1 C 61.466,0 56.851,35.041 70.691,35.041 C 84.529,35.041 110.671,0 86.068,0 z "
46 "M 45.217,30.699 C 52.586,31.149 60.671,2.577 46.821,4.374 C 32.976,6.171 37.845,30.249 45.217,30.699 z "
47 "M 11.445,48.453 C 16.686,46.146 12.12,23.581 3.208,29.735 C -5.7,35.89 6.204,50.759 11.445,48.453 z "
48 "M 26.212,36.642 C 32.451,35.37 32.793,9.778 21.667,14.369 C 10.539,18.961 19.978,37.916 26.212,36.642 L 26.212,36.642 z "
49 "M 58.791,93.913 C 59.898,102.367 52.589,106.542 45.431,101.092 C 22.644,83.743 83.16,75.088 79.171,51.386 C 75.86,31.712 15.495,37.769 8.621,68.553 C 3.968,89.374 27.774,118.26 52.614,118.26 C 64.834,118.26 78.929,107.226 81.566,93.248 C 83.58,82.589 57.867,86.86 58.791,93.913 L 58.791,93.913 z "
50 "\0"
51};
52
53static void
54mini_svg_render (MiniSvg *shape,
55 cairo_t *cr,
56 gboolean do_path)
57{
58 double x, y;
59 const char *p;
60 char op[2];
61 int len;
62
63 cairo_get_current_point (cr, x: &x, y: &y);
64 cairo_translate (cr, tx: x, ty: y);
65
66 for (p = shape->path; sscanf (s: p, format: "%1s %n", op, &len), p += len, *p;)
67 switch (*op)
68 {
69 case 'M':
70 {
71 sscanf (s: p, format: "%lf,%lf %n", &x, &y, &len); p += len;
72 cairo_move_to (cr, x, y);
73 break;
74 }
75 case 'L':
76 {
77 sscanf (s: p, format: "%lf,%lf %n", &x, &y, &len); p += len;
78 cairo_line_to (cr, x, y);
79 break;
80 }
81 case 'C':
82 {
83 double x1, y1, x2, y2, x3, y3;
84 sscanf (s: p, format: "%lf,%lf %lf,%lf %lf,%lf %n", &x1, &y1, &x2, &y2, &x3, &y3, &len); p += len;
85 cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
86 break;
87 }
88 case 'z':
89 {
90 cairo_close_path (cr);
91 break;
92 }
93 default:
94 {
95 g_warning ("Invalid MiniSvg operation '%c'", *op);
96 break;
97 }
98 }
99
100 if (!do_path)
101 cairo_fill (cr);
102}
103
104static void
105mini_svg_shape_renderer (cairo_t *cr,
106 PangoAttrShape *attr,
107 gboolean do_path,
108 gpointer data G_GNUC_UNUSED)
109{
110 MiniSvg *shape = (MiniSvg *) attr->data;
111 double scale_x, scale_y;
112
113 scale_x = (double) attr->ink_rect.width / (PANGO_SCALE * shape->width );
114 scale_y = (double) attr->ink_rect.height / (PANGO_SCALE * shape->height);
115
116 cairo_rel_move_to (cr,
117 dx: (double) attr->ink_rect.x / PANGO_SCALE,
118 dy: (double) attr->ink_rect.y / PANGO_SCALE);
119 cairo_scale (cr, sx: scale_x, sy: scale_y);
120
121 mini_svg_render (shape, cr, do_path);
122}
123
124
125static PangoLayout *
126get_layout (cairo_t *cr)
127{
128 PangoLayout *layout;
129 PangoAttrList *attrs;
130 PangoRectangle ink_rect = {1 * PANGO_SCALE, -11 * PANGO_SCALE, 8 * PANGO_SCALE, 10 * PANGO_SCALE};
131 PangoRectangle logical_rect = {0 * PANGO_SCALE, -12 * PANGO_SCALE, 10 * PANGO_SCALE, 12 * PANGO_SCALE};
132 const char *p;
133
134 /* Create a PangoLayout, set the font and text */
135 layout = pango_cairo_create_layout (cr);
136
137 pango_cairo_context_set_shape_renderer (context: pango_layout_get_context (layout),
138 func: mini_svg_shape_renderer, NULL, NULL);
139
140 pango_layout_set_text (layout, text, length: -1);
141
142 attrs = pango_attr_list_new ();
143
144 /* Set gnome shape attributes for all bullets */
145 for (p = text; (p = strstr (haystack: p, BULLET)); p += strlen (BULLET))
146 {
147 PangoAttribute *attr;
148
149 attr = pango_attr_shape_new_with_data (ink_rect: &ink_rect,
150 logical_rect: &logical_rect,
151 data: &GnomeFootLogo,
152 NULL, NULL);
153
154 attr->start_index = p - text;
155 attr->end_index = attr->start_index + strlen (BULLET);
156
157 pango_attr_list_insert (list: attrs, attr);
158 }
159
160 pango_layout_set_attributes (layout, attrs);
161 pango_attr_list_unref (list: attrs);
162
163 return layout;
164}
165
166static void
167draw_text (cairo_t *cr, int *width, int *height)
168{
169
170 PangoLayout *layout = get_layout (cr);
171
172 /* Adds a fixed 10-pixel margin on the sides. */
173
174 if (width || height)
175 {
176 pango_layout_get_pixel_size (layout, width, height);
177 if (width)
178 *width += 20;
179 if (height)
180 *height += 20;
181 }
182
183 cairo_move_to (cr, x: 10, y: 10);
184 pango_cairo_show_layout (cr, layout);
185
186 g_object_unref (object: layout);
187}
188
189int main (int argc, char **argv)
190{
191 cairo_t *cr;
192 char *filename;
193 cairo_status_t status;
194 cairo_surface_t *surface;
195 int width, height;
196
197 if (argc != 2)
198 {
199 g_printerr (format: "Usage: cairoshape OUTPUT_FILENAME\n");
200 return 1;
201 }
202
203 filename = argv[1];
204
205 /* First create and use a 0x0 surface, to measure how large
206 * the final surface needs to be */
207 surface = cairo_image_surface_create (format: CAIRO_FORMAT_ARGB32,
208 width: 0, height: 0);
209 cr = cairo_create (target: surface);
210 draw_text (cr, width: &width, height: &height);
211 cairo_destroy (cr);
212 cairo_surface_destroy (surface);
213
214 /* Now create the final surface and draw to it. */
215 surface = cairo_image_surface_create (format: CAIRO_FORMAT_ARGB32,
216 width, height);
217 cr = cairo_create (target: surface);
218
219 cairo_set_source_rgb (cr, red: 1.0, green: 1.0, blue: 1.0);
220 cairo_paint (cr);
221 cairo_set_source_rgb (cr, red: 0.0, green: 0.0, blue: 0.5);
222 draw_text (cr, NULL, NULL);
223 cairo_destroy (cr);
224
225 /* Write out the surface as PNG */
226 status = cairo_surface_write_to_png (surface, filename);
227 cairo_surface_destroy (surface);
228
229 if (status != CAIRO_STATUS_SUCCESS)
230 {
231 g_printerr (format: "Could not save png to '%s'\n", filename);
232 return 1;
233 }
234
235 return 0;
236}
237

source code of gtk/subprojects/pango/examples/cairoshape.c