diff options
author | Behdad Esfahbod <behdad@gnome.org> | 2007-05-04 11:33:14 +0000 |
---|---|---|
committer | Behdad Esfahbod <behdad@src.gnome.org> | 2007-05-04 11:33:14 +0000 |
commit | 0defecb84e0beabd95a1a39801dc715d327c3b59 (patch) | |
tree | cc2c4e11060dc43d7d5938d7fff40b9f4be2fd96 | |
parent | 7dfb3c077cc7b2234fe9ab098a237c11e8de55da (diff) | |
download | pango-0defecb84e0beabd95a1a39801dc715d327c3b59.tar.gz |
New API
2007-05-04 Behdad Esfahbod <behdad@gnome.org>
* pango/pangocairo.h:
* pango/pangocairo-context.c:
* pango/pangocairo-render.c:
New API
PangoCairoShapeRendererFunc and
pango_cairo_context_[sg]et_shape_renderer()
* docs/pango-sections.txt, docs/tmpl/pangocairo.sgml: Document new
* API.
* examples/Makefile.am, examples/cairoshape.c: New example to show off
new API/feature.
svn path=/trunk/; revision=2261
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | docs/pango-sections.txt | 3 | ||||
-rw-r--r-- | docs/tmpl/pangocairo.sgml | 37 | ||||
-rw-r--r-- | examples/Makefile.am | 3 | ||||
-rw-r--r-- | examples/cairoshape.c | 209 | ||||
-rw-r--r-- | examples/cairosimple.c | 3 | ||||
-rw-r--r-- | examples/cairotwisted.c | 3 | ||||
-rw-r--r-- | pango/pango-layout.c | 1 | ||||
-rw-r--r-- | pango/pangocairo-context.c | 89 | ||||
-rw-r--r-- | pango/pangocairo-render.c | 35 | ||||
-rw-r--r-- | pango/pangocairo.h | 12 |
11 files changed, 402 insertions, 8 deletions
@@ -1,5 +1,20 @@ 2007-05-04 Behdad Esfahbod <behdad@gnome.org> + * pango/pangocairo.h: + * pango/pangocairo-context.c: + * pango/pangocairo-render.c: + New API + + PangoCairoShapeRendererFunc and + pango_cairo_context_[sg]et_shape_renderer() + + * docs/pango-sections.txt, docs/tmpl/pangocairo.sgml: Document new API. + + * examples/Makefile.am, examples/cairoshape.c: New example to show off + new API/feature. + +2007-05-04 Behdad Esfahbod <behdad@gnome.org> + * pango/Makefile.am: * pango/pangocairo-context.c: * pango/pangocairo-fontmap.c: diff --git a/docs/pango-sections.txt b/docs/pango-sections.txt index c1ed48e2..6c9e6426 100644 --- a/docs/pango-sections.txt +++ b/docs/pango-sections.txt @@ -831,6 +831,9 @@ pango_cairo_context_set_resolution pango_cairo_context_get_resolution pango_cairo_context_set_font_options pango_cairo_context_get_font_options +PangoCairoShapeRendererFunc +pango_cairo_context_set_shape_renderer +pango_cairo_context_get_shape_renderer pango_cairo_update_context pango_cairo_create_layout pango_cairo_update_layout diff --git a/docs/tmpl/pangocairo.sgml b/docs/tmpl/pangocairo.sgml index 7cda6f2e..1a07574d 100644 --- a/docs/tmpl/pangocairo.sgml +++ b/docs/tmpl/pangocairo.sgml @@ -230,6 +230,43 @@ int main (int argc, char **argv) @Returns: +<!-- ##### USER_FUNCTION PangoCairoShapeRendererFunc ##### --> +<para> +Function type for rendering attributes of type %PANGO_ATTR_SHAPE +with Pango's Cairo renderer. +</para> + +@cr: a Cairo context with current point set to where the shape should + be rendered +@attr: the %PANGO_ATTR_SHAPE to render +@do_path: whether only the shape path should be appended to current + path of @cr and no filling/stroking done. This will be set + to %TRUE when called from pango_cairo_layout_path() and + pango_cairo_layout_line_path() rendering functions. +@data: user data passed to pango_cairo_context_set_shape_renderer() + + +<!-- ##### FUNCTION pango_cairo_context_set_shape_renderer ##### --> +<para> + +</para> + +@context: +@func: +@data: +@dnotify: + + +<!-- ##### FUNCTION pango_cairo_context_get_shape_renderer ##### --> +<para> + +</para> + +@context: +@data: +@Returns: + + <!-- ##### FUNCTION pango_cairo_update_context ##### --> <para> diff --git a/examples/Makefile.am b/examples/Makefile.am index 7381296a..12ff04c3 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -15,7 +15,7 @@ INCLUDES = \ noinst_PROGRAMS = if HAVE_CAIRO_PNG -noinst_PROGRAMS += cairosimple cairotwisted +noinst_PROGRAMS += cairosimple cairotwisted cairoshape cairosimple_LDADD = \ ../pango/libpango-$(PANGO_API_VERSION).la \ @@ -27,4 +27,5 @@ cairosimple_LDADD += \ ../pango/libpangoft2-$(PANGO_API_VERSION).la endif cairotwisted_LDADD = $(cairosimple_LDADD) +cairoshape_LDADD = $(cairosimple_LDADD) endif diff --git a/examples/cairoshape.c b/examples/cairoshape.c new file mode 100644 index 00000000..addde87e --- /dev/null +++ b/examples/cairoshape.c @@ -0,0 +1,209 @@ +/* example to use pangocairo to render arbitrary shapes inside a text layout */ + +#include <stdio.h> +#include <string.h> + +#include <pango/pangocairo.h> + +#define BULLET "•" + +const char text[] = +"The GNOME project provides two things:\n" +"\n" +" • The GNOME desktop environment\n" +" • The GNOME development platform\n" +" • Planet GNOME"; + +typedef struct { + double width, height; + const char *path; +} MiniSvg; + +static MiniSvg GnomeFootLogo = { + 96.2152, 118.26, + "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 " + "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 " + "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 " + "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 " + "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 " + "\0" +}; + +static void +mini_svg_render (MiniSvg *shape, + cairo_t *cr, + gboolean do_path) +{ + double x, y; + const char *p; + char op[2]; + int items, len; + + cairo_get_current_point (cr, &x, &y); + cairo_translate (cr, x, y); + + for (p = shape->path; (items = 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; + } + case 'L': + { + 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; + } + case 'z': + { + 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) +{ + 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) +{ + 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); + + pango_layout_set_text (layout, text, -1); + + attrs = pango_attr_list_new (); + + /* set gnome shape attributes for bullets */ + 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->start_index = p - text; + attr->end_index = attr->start_index + strlen (BULLET); + + pango_attr_list_insert (attrs, attr); + } + + pango_layout_set_attributes (layout, attrs); + pango_attr_list_unref (attrs); + + return layout; +} + +static void +draw_text (cairo_t *cr, int *width, int *height) +{ + + PangoLayout *layout = get_layout (cr); + + if (width || height) + { + pango_layout_get_pixel_size (layout, width, height); + if (width) + *width += 20; + if (height) + *height += 20; + } + + cairo_move_to (cr, 10, 10); + pango_cairo_show_layout (cr, layout); + + g_object_unref (layout); +} + +int main (int argc, char **argv) +{ + cairo_t *cr; + char *filename; + cairo_status_t status; + cairo_surface_t *surface; + int width, height; + + if (argc != 2) + { + g_printerr ("Usage: cairoshape OUTPUT_FILENAME\n"); + return 1; + } + + filename = argv[1]; + + 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); + + 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); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.5); + draw_text (cr, NULL, NULL); + cairo_destroy (cr); + + 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'\n", filename); + return 1; + } + + return 0; +} diff --git a/examples/cairosimple.c b/examples/cairosimple.c index 102b9fb3..d07f004c 100644 --- a/examples/cairosimple.c +++ b/examples/cairosimple.c @@ -1,4 +1,5 @@ -#include <config.h> +/* simple example to use pangocairo to render rotated text */ + #include <math.h> #include <pango/pangocairo.h> diff --git a/examples/cairotwisted.c b/examples/cairotwisted.c index 33d634c9..4da69c80 100644 --- a/examples/cairotwisted.c +++ b/examples/cairotwisted.c @@ -1,4 +1,5 @@ -#include <config.h> +/* example to use pangocairo to render text projected on a path */ + #include <math.h> #include <stdlib.h> #include <pango/pangocairo.h> diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 5e94d498..23378b9d 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -525,6 +525,7 @@ pango_layout_get_spacing (PangoLayout *layout) * @attrs: a #PangoAttrList * * Sets the text attributes for a layout object. + * References @attrs, so the caller can unref its reference. **/ void pango_layout_set_attributes (PangoLayout *layout, diff --git a/pango/pangocairo-context.c b/pango/pangocairo-context.c index ece6b686..6bdaa532 100644 --- a/pango/pangocairo-context.c +++ b/pango/pangocairo-context.c @@ -34,6 +34,10 @@ struct _PangoCairoContextInfo cairo_font_options_t *set_options; cairo_font_options_t *surface_options; cairo_font_options_t *merged_options; + + PangoCairoShapeRendererFunc shape_renderer_func; + gpointer shape_renderer_data; + GDestroyNotify shape_renderer_notify; }; static void @@ -46,6 +50,9 @@ free_context_info (PangoCairoContextInfo *info) if (info->merged_options) cairo_font_options_destroy (info->merged_options); + if (info->shape_renderer_notify) + info->shape_renderer_notify (info->shape_renderer_data); + g_slice_free (PangoCairoContextInfo, info); } @@ -63,11 +70,8 @@ get_context_info (PangoContext *context, if (G_UNLIKELY (!info) && create) { - info = g_slice_new (PangoCairoContextInfo); + info = g_slice_new0 (PangoCairoContextInfo); info->dpi = -1.0; - info->set_options = NULL; - info->surface_options = NULL; - info->merged_options = NULL; g_object_set_qdata_full (G_OBJECT (context), context_info_quark, info, (GDestroyNotify)free_context_info); @@ -262,6 +266,83 @@ _pango_cairo_context_get_merged_font_options (PangoContext *context) } /** + * pango_cairo_context_set_shape_renderer: + * @context: a #PangoContext, from pango_cairo_font_map_create_context() + * @func: Callback function for rendering attributes of type + * %PANGO_ATTR_SHAPE, or %NULL to disable shape rendering. + * @data: User data that will be passed to @func. + * @dnotify: Callback that will be called when the + * context is freed to release @data, or %NULL. + * + * Sets callback function for context to use for rendering attributes + * of type %PANGO_ATTR_SHAPE. See #PangoCairoShapeRendererFunc for + * details. + * + * Since: 1.18 + */ +void +pango_cairo_context_set_shape_renderer (PangoContext *context, + PangoCairoShapeRendererFunc func, + gpointer data, + GDestroyNotify dnotify) +{ + PangoCairoContextInfo *info; + + g_return_if_fail (PANGO_IS_CONTEXT (context)); + + info = get_context_info (context, TRUE); + + if (info->shape_renderer_notify) + info->shape_renderer_notify (info->shape_renderer_data); + + info->shape_renderer_func = func; + info->shape_renderer_data = data; + info->shape_renderer_notify = dnotify; +} + +/** + * pango_cairo_context_get_shape_renderer: + * @context: a #PangoContext, from pango_cairo_font_map_create_context() + * @data: Pointer to #gpointer to return user data + * + * Sets callback function for context to use for rendering attributes + * of type %PANGO_ATTR_SHAPE. See #PangoCairoShapeRendererFunc for + * details. + * + * Retrieves callback function and associated user data for rendering + * attributes of type %PANGO_ATTR_SHAPE as set by + * pango_cairo_context_set_shape_renderer(), if any. + * + * Return value: the shape rendering callback previously set on the context, or %NULL + * if no shape rendering callback have been set. + * + * Since: 1.18 + */ +PangoCairoShapeRendererFunc +pango_cairo_context_get_shape_renderer (PangoContext *context, + gpointer *data) +{ + PangoCairoContextInfo *info; + + g_return_val_if_fail (PANGO_IS_CONTEXT (context), NULL); + + info = get_context_info (context, FALSE); + + if (info) + { + if (data) + *data = info->shape_renderer_data; + return info->shape_renderer_func; + } + else + { + if (data) + *data = NULL; + return NULL; + } +} + +/** * pango_cairo_create_layout: * @cr: a Cairo context * diff --git a/pango/pangocairo-render.c b/pango/pangocairo-render.c index 9ec2e682..4c0baf29 100644 --- a/pango/pangocairo-render.c +++ b/pango/pangocairo-render.c @@ -36,6 +36,8 @@ struct _PangoCairoRenderer cairo_t *cr; gboolean do_path; double x_offset, y_offset; + PangoCairoShapeRendererFunc shape_renderer; + gpointer shape_renderer_data; }; struct _PangoCairoRendererClass @@ -69,7 +71,6 @@ _pango_cairo_renderer_draw_frame (PangoCairoRenderer *crenderer, { if (crenderer->do_path) { - cairo_t *cr = crenderer->cr; double d2 = line_width * .5, d = line_width; /* we draw an outer box in one winding direction and an inner one in the @@ -406,6 +407,31 @@ pango_cairo_renderer_draw_error_underline (PangoRenderer *renderer, } static void +pango_cairo_renderer_draw_shape (PangoRenderer *renderer, + PangoAttrShape *attr, + int x, + int y) +{ + PangoCairoRenderer *crenderer = (PangoCairoRenderer *) (renderer); + cairo_t *cr = crenderer->cr; + double base_x = crenderer->x_offset + (double)x / PANGO_SCALE; + double base_y = crenderer->y_offset + (double)y / PANGO_SCALE; + + if (!crenderer->shape_renderer) + return; + + cairo_save (cr); + if (!crenderer->do_path) + set_color (crenderer, PANGO_RENDER_PART_FOREGROUND); + + cairo_move_to (cr, base_x, base_y); + + crenderer->shape_renderer (cr, attr, crenderer->do_path, crenderer->shape_renderer_data); + + cairo_restore (cr); +} + +static void pango_cairo_renderer_init (PangoCairoRenderer *renderer) { } @@ -418,6 +444,7 @@ pango_cairo_renderer_class_init (PangoCairoRendererClass *klass) renderer_class->draw_glyphs = pango_cairo_renderer_draw_glyphs; renderer_class->draw_rectangle = pango_cairo_renderer_draw_rectangle; renderer_class->draw_error_underline = pango_cairo_renderer_draw_error_underline; + renderer_class->draw_shape = pango_cairo_renderer_draw_shape; } static PangoCairoRenderer *cached_renderer = NULL; @@ -454,6 +481,8 @@ release_renderer (PangoCairoRenderer *renderer, gboolean free_renderer) { renderer->cr = NULL; renderer->do_path = FALSE; + renderer->shape_renderer = NULL; + renderer->shape_renderer_data = NULL; renderer->x_offset = 0.; renderer->y_offset = 0.; @@ -516,6 +545,8 @@ _pango_cairo_do_layout_line (cairo_t *cr, crenderer->cr = cr; crenderer->do_path = do_path; + crenderer->shape_renderer = pango_cairo_context_get_shape_renderer (pango_layout_get_context (line->layout), + &crenderer->shape_renderer_data); cairo_get_current_point (cr, &crenderer->x_offset, &crenderer->y_offset); pango_renderer_draw_layout_line (renderer, line, 0, 0); @@ -534,6 +565,8 @@ _pango_cairo_do_layout (cairo_t *cr, crenderer->cr = cr; crenderer->do_path = do_path; + crenderer->shape_renderer = pango_cairo_context_get_shape_renderer (pango_layout_get_context (layout), + &crenderer->shape_renderer_data); cairo_get_current_point (cr, &crenderer->x_offset, &crenderer->y_offset); pango_renderer_draw_layout (renderer, layout, 0, 0); diff --git a/pango/pangocairo.h b/pango/pangocairo.h index fe97db3b..d8085112 100644 --- a/pango/pangocairo.h +++ b/pango/pangocairo.h @@ -44,6 +44,11 @@ G_BEGIN_DECLS typedef struct _PangoCairoFontMap PangoCairoFontMap; +typedef void (* PangoCairoShapeRendererFunc) (cairo_t *cr, + PangoAttrShape *attr, + gboolean do_path, + gpointer data); + /* * PangoCairoFontMap */ @@ -70,6 +75,13 @@ void pango_cairo_context_set_resolution (PangoContext *c double dpi); double pango_cairo_context_get_resolution (PangoContext *context); +void pango_cairo_context_set_shape_renderer (PangoContext *context, + PangoCairoShapeRendererFunc func, + gpointer data, + GDestroyNotify dnotify); +PangoCairoShapeRendererFunc pango_cairo_context_get_shape_renderer (PangoContext *context, + gpointer *data); + /* Convenience */ PangoLayout *pango_cairo_create_layout (cairo_t *cr); |