summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@gnome.org>2007-05-04 11:33:14 +0000
committerBehdad Esfahbod <behdad@src.gnome.org>2007-05-04 11:33:14 +0000
commit0defecb84e0beabd95a1a39801dc715d327c3b59 (patch)
treecc2c4e11060dc43d7d5938d7fff40b9f4be2fd96
parent7dfb3c077cc7b2234fe9ab098a237c11e8de55da (diff)
downloadpango-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--ChangeLog15
-rw-r--r--docs/pango-sections.txt3
-rw-r--r--docs/tmpl/pangocairo.sgml37
-rw-r--r--examples/Makefile.am3
-rw-r--r--examples/cairoshape.c209
-rw-r--r--examples/cairosimple.c3
-rw-r--r--examples/cairotwisted.c3
-rw-r--r--pango/pango-layout.c1
-rw-r--r--pango/pangocairo-context.c89
-rw-r--r--pango/pangocairo-render.c35
-rw-r--r--pango/pangocairo.h12
11 files changed, 402 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 81e573cf..c1e22991 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);