aboutsummaryrefslogtreecommitdiffstats
path: root/libgnomecanvas/gnome-canvas-shape.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgnomecanvas/gnome-canvas-shape.c')
-rw-r--r--libgnomecanvas/gnome-canvas-shape.c1558
1 files changed, 1558 insertions, 0 deletions
diff --git a/libgnomecanvas/gnome-canvas-shape.c b/libgnomecanvas/gnome-canvas-shape.c
new file mode 100644
index 0000000000..79d8124525
--- /dev/null
+++ b/libgnomecanvas/gnome-canvas-shape.c
@@ -0,0 +1,1558 @@
+/* Generic bezier shape item for GnomeCanvasWidget. Most code taken
+ * from gnome-canvas-bpath but made into a shape item.
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent
+ * canvas widget. Tk is copyrighted by the Regents of the University
+ * of California, Sun Microsystems, and other parties.
+ *
+ * Copyright (C) 1998,1999 The Free Software Foundation
+ *
+ * Authors: Federico Mena <federico@nuclecu.unam.mx>
+ * Raph Levien <raph@acm.org>
+ * Lauris Kaplinski <lauris@ximian.com>
+ * Miguel de Icaza <miguel@kernel.org>
+ * Cody Russell <bratsche@gnome.org>
+ * Rusty Conover <rconover@bangtail.net>
+ */
+
+/* These includes are set up for standalone compile. If/when this codebase
+ is integrated into libgnomeui, the includes will need to change. */
+
+#include <math.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include "gnome-canvas.h"
+#include "gnome-canvas-util.h"
+
+#include "gnome-canvas-shape.h"
+#include "gnome-canvas-shape-private.h"
+#include "gnome-canvas-path-def.h"
+
+#include <libart_lgpl/art_rect.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_bpath.h>
+#include <libart_lgpl/art_vpath_bpath.h>
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_svp_point.h>
+#include <libart_lgpl/art_svp_vpath.h>
+#include <libart_lgpl/art_vpath_dash.h>
+#include <libart_lgpl/art_svp_wind.h>
+#include <libart_lgpl/art_svp_intersect.h>
+#include <libart_lgpl/art_rect_svp.h>
+
+enum {
+ PROP_0,
+ PROP_FILL_COLOR,
+ PROP_FILL_COLOR_GDK,
+ PROP_FILL_COLOR_RGBA,
+ PROP_OUTLINE_COLOR,
+ PROP_OUTLINE_COLOR_GDK,
+ PROP_OUTLINE_COLOR_RGBA,
+ PROP_FILL_STIPPLE,
+ PROP_OUTLINE_STIPPLE,
+ PROP_WIDTH_PIXELS,
+ PROP_WIDTH_UNITS,
+ PROP_CAP_STYLE,
+ PROP_JOIN_STYLE,
+ PROP_WIND,
+ PROP_MITERLIMIT,
+ PROP_DASH
+};
+
+static void gnome_canvas_shape_class_init (GnomeCanvasShapeClass *class);
+static void gnome_canvas_shape_init (GnomeCanvasShape *bpath);
+static void gnome_canvas_shape_destroy (GtkObject *object);
+static void gnome_canvas_shape_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_shape_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gnome_canvas_shape_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
+static void gnome_canvas_shape_realize (GnomeCanvasItem *item);
+static void gnome_canvas_shape_unrealize (GnomeCanvasItem *item);
+static void gnome_canvas_shape_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height);
+static double gnome_canvas_shape_point (GnomeCanvasItem *item, double x, double y,
+ int cx, int cy, GnomeCanvasItem **actual_item);
+static void gnome_canvas_shape_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
+static void gnome_canvas_shape_bounds (GnomeCanvasItem *item,
+ double *x1, double *y1, double *x2, double *y2);
+
+static gulong get_pixel_from_rgba (GnomeCanvasItem *item, guint32 rgba_color);
+static guint32 get_rgba_from_color (GdkColor * color);
+static void set_gc_foreground (GdkGC *gc, gulong pixel);
+static void gcbp_ensure_gdk (GnomeCanvasShape * bpath);
+static void gcbp_destroy_gdk (GnomeCanvasShape * bpath);
+static void set_stipple (GdkGC *gc, GdkBitmap **internal_stipple, GdkBitmap *stipple, int reconfigure);
+static void gcbp_ensure_mask (GnomeCanvasShape * bpath, gint width, gint height);
+static void gcbp_draw_ctx_unref (GCBPDrawCtx * ctx);
+
+static GnomeCanvasItemClass *parent_class;
+
+GType
+gnome_canvas_shape_get_type (void)
+{
+ static GType shape_type;
+
+ if (!shape_type) {
+ const GTypeInfo object_info = {
+ sizeof (GnomeCanvasShapeClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_shape_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasShape),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_shape_init,
+ NULL /* value_table */
+ };
+
+ shape_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasShape",
+ &object_info, 0);
+ }
+
+ return shape_type;
+}
+
+static void
+gnome_canvas_shape_class_init (GnomeCanvasShapeClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+ item_class = (GnomeCanvasItemClass *) class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ /* when this gets checked into libgnomeui, change the
+ GTK_TYPE_POINTER to GTK_TYPE_GNOME_CANVAS_SHAPE, and add an
+ entry to gnome-boxed.defs */
+
+ gobject_class->set_property = gnome_canvas_shape_set_property;
+ gobject_class->get_property = gnome_canvas_shape_get_property;
+
+
+
+ g_object_class_install_property (gobject_class,
+ PROP_FILL_COLOR,
+ g_param_spec_string ("fill_color", NULL, NULL,
+ NULL,
+ (G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_FILL_COLOR_GDK,
+ g_param_spec_boxed ("fill_color_gdk", NULL, NULL,
+ GDK_TYPE_COLOR,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_FILL_COLOR_RGBA,
+ g_param_spec_uint ("fill_color_rgba", NULL, NULL,
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_OUTLINE_COLOR,
+ g_param_spec_string ("outline_color", NULL, NULL,
+ NULL,
+ (G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_OUTLINE_COLOR_GDK,
+ g_param_spec_boxed ("outline_color_gdk", NULL, NULL,
+ GDK_TYPE_COLOR,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_OUTLINE_COLOR_RGBA,
+ g_param_spec_uint ("outline_color_rgba", NULL, NULL,
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_FILL_STIPPLE,
+ g_param_spec_object ("fill_stipple", NULL, NULL,
+ GDK_TYPE_DRAWABLE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_OUTLINE_STIPPLE,
+ g_param_spec_object ("outline_stipple", NULL, NULL,
+ GDK_TYPE_DRAWABLE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_WIDTH_PIXELS,
+ g_param_spec_uint ("width_pixels", NULL, NULL,
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_WIDTH_UNITS,
+ g_param_spec_double ("width_units", NULL, NULL,
+ 0.0, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_CAP_STYLE,
+ g_param_spec_enum ("cap_style", NULL, NULL,
+ GDK_TYPE_CAP_STYLE,
+ GDK_CAP_BUTT,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_JOIN_STYLE,
+ g_param_spec_enum ("join_style", NULL, NULL,
+ GDK_TYPE_JOIN_STYLE,
+ GDK_JOIN_MITER,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_WIND,
+ g_param_spec_uint ("wind", NULL, NULL,
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_MITERLIMIT,
+ g_param_spec_double ("miterlimit", NULL, NULL,
+ 0.0, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_DASH,
+ g_param_spec_pointer ("dash", NULL, NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ object_class->destroy = gnome_canvas_shape_destroy;
+
+ item_class->update = gnome_canvas_shape_update;
+ item_class->realize = gnome_canvas_shape_realize;
+ item_class->unrealize = gnome_canvas_shape_unrealize;
+ item_class->draw = gnome_canvas_shape_draw;
+ item_class->point = gnome_canvas_shape_point;
+ item_class->render = gnome_canvas_shape_render;
+ item_class->bounds = gnome_canvas_shape_bounds;
+}
+
+static void
+gnome_canvas_shape_init (GnomeCanvasShape *shape)
+{
+ shape->priv = g_new (GnomeCanvasShapePriv, 1);
+
+ shape->priv->path = NULL;
+
+ shape->priv->scale = 1.0;
+
+ shape->priv->fill_set = FALSE;
+ shape->priv->outline_set = FALSE;
+ shape->priv->width_pixels = FALSE;
+
+ shape->priv->width = 1.0;
+
+ shape->priv->fill_rgba = 0x0000003f;
+ shape->priv->outline_rgba = 0x0000007f;
+
+ shape->priv->cap = GDK_CAP_BUTT;
+ shape->priv->join = GDK_JOIN_MITER;
+ shape->priv->wind = ART_WIND_RULE_ODDEVEN;
+ shape->priv->miterlimit = 10.43; /* X11 default */
+
+ shape->priv->dash.n_dash = 0;
+ shape->priv->dash.dash = NULL;
+
+ shape->priv->fill_svp = NULL;
+ shape->priv->outline_svp = NULL;
+
+ shape->priv->gdk = NULL;
+}
+
+static void
+gnome_canvas_shape_destroy (GtkObject *object)
+{
+ GnomeCanvasShape *shape;
+ GnomeCanvasShapePriv *priv;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_SHAPE (object));
+
+ shape = GNOME_CANVAS_SHAPE (object);
+
+ if (shape->priv) {
+ priv = shape->priv;
+ if (priv->gdk) gcbp_destroy_gdk (shape);
+
+ if (priv->path) gnome_canvas_path_def_unref (priv->path);
+
+ if (priv->dash.dash) g_free (priv->dash.dash);
+ if (priv->fill_svp) art_svp_free (priv->fill_svp);
+ if (priv->outline_svp) art_svp_free (priv->outline_svp);
+
+ g_free (shape->priv);
+ shape->priv = NULL;
+ }
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+/**
+ * gnome_canvas_shape_set_path_def:
+ * @shape: a GnomeCanvasShape
+ * @def: a GnomeCanvasPathDef
+ *
+ * This function sets the the GnomeCanvasPathDef used by the
+ * GnomeCanvasShape. Notice, that it does not request updates, as
+ * it is meant to be used from item implementations, from inside
+ * update queue.
+ */
+
+void
+gnome_canvas_shape_set_path_def (GnomeCanvasShape *shape, GnomeCanvasPathDef *def)
+{
+ GnomeCanvasShapePriv *priv;
+
+ g_return_if_fail (shape != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_SHAPE (shape));
+
+ priv = shape->priv;
+
+ if (priv->path) {
+ gnome_canvas_path_def_unref (priv->path);
+ priv->path = NULL;
+ }
+
+ if (def) {
+ priv->path = gnome_canvas_path_def_duplicate (def);
+ }
+}
+
+static void
+gnome_canvas_shape_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasShape *shape;
+ GnomeCanvasShapePriv *priv;
+ GnomeCanvasShapePrivGdk *gdk;
+ GdkColor color;
+ GdkColor *colorptr;
+ ArtVpathDash *dash;
+
+ item = GNOME_CANVAS_ITEM (object);
+ shape = GNOME_CANVAS_SHAPE (object);
+ priv = shape->priv;
+
+ if (!item->canvas->aa) {
+ gcbp_ensure_gdk (shape);
+ gdk = priv->gdk;
+ } else {
+ gdk = NULL;
+ }
+
+ switch (param_id) {
+ case PROP_FILL_COLOR:
+ if (gnome_canvas_get_color (item->canvas, g_value_get_string (value), &color)) {
+ priv->fill_set = TRUE;
+ priv->fill_rgba = get_rgba_from_color (&color);
+ if (gdk) gdk->fill_pixel = color.pixel;
+ } else if (priv->fill_set)
+ priv->fill_set = FALSE;
+ else
+ break;
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_FILL_COLOR_GDK:
+ colorptr = g_value_get_boxed (value);
+ if (colorptr != NULL) {
+ priv->fill_set = TRUE;
+ priv->fill_rgba = get_rgba_from_color (colorptr);
+ if (gdk) {
+ GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
+ GdkColor tmp = *colorptr;
+ gdk_rgb_find_color (colormap, &tmp);
+ gdk->fill_pixel = tmp.pixel;
+ }
+ } else if (priv->fill_set)
+ priv->fill_set = FALSE;
+ else
+ break;
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_FILL_COLOR_RGBA:
+ priv->fill_set = TRUE;
+ priv->fill_rgba = g_value_get_uint (value);
+ if (gdk) gdk->fill_pixel = get_pixel_from_rgba (item, priv->fill_rgba);
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_OUTLINE_COLOR:
+ if (gnome_canvas_get_color (item->canvas, g_value_get_string (value), &color)) {
+ priv->outline_set = TRUE;
+ priv->outline_rgba = get_rgba_from_color (&color);
+ if (gdk) gdk->outline_pixel = color.pixel;
+ } else if (priv->outline_set)
+ priv->outline_set = FALSE;
+ else
+ break;
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_OUTLINE_COLOR_GDK:
+ colorptr = g_value_get_boxed (value);
+ if (colorptr != NULL) {
+ priv->outline_set = TRUE;
+ priv->outline_rgba = get_rgba_from_color (colorptr);
+ if (gdk) {
+ GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
+ GdkColor tmp = *colorptr;
+ gdk_rgb_find_color (colormap, &tmp);
+ gdk->outline_pixel = tmp.pixel;
+ }
+ } else if (priv->outline_set)
+ priv->outline_set = FALSE;
+ else
+ break;
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_OUTLINE_COLOR_RGBA:
+ priv->outline_set = TRUE;
+ priv->outline_rgba = g_value_get_uint (value);
+ if (gdk) gdk->outline_pixel = get_pixel_from_rgba (item, priv->outline_rgba);
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_FILL_STIPPLE:
+ if (gdk) {
+ set_stipple (gdk->fill_gc, &gdk->fill_stipple, (GdkBitmap*) g_value_get_object (value), FALSE);
+ gnome_canvas_item_request_update (item);
+ }
+ break;
+
+ case PROP_OUTLINE_STIPPLE:
+ if (gdk) {
+ set_stipple (gdk->outline_gc, &gdk->outline_stipple, (GdkBitmap*) g_value_get_object (value), FALSE);
+ gnome_canvas_item_request_update (item);
+ }
+ break;
+
+ case PROP_WIDTH_PIXELS:
+ priv->width = g_value_get_uint (value);
+ priv->width_pixels = TRUE;
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_WIDTH_UNITS:
+ priv->width = fabs (g_value_get_double (value));
+ priv->width_pixels = FALSE;
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_WIND:
+ priv->wind = g_value_get_uint (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_CAP_STYLE:
+ priv->cap = g_value_get_enum (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_JOIN_STYLE:
+ priv->join = g_value_get_enum (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_MITERLIMIT:
+ priv->miterlimit = g_value_get_double (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_DASH:
+ dash = g_value_get_pointer (value);
+ if (priv->dash.dash) g_free (priv->dash.dash);
+ priv->dash.dash = NULL;
+
+ if (dash) {
+ priv->dash.offset = dash->offset;
+ priv->dash.n_dash = dash->n_dash;
+ if (dash->dash != NULL) {
+ priv->dash.dash = g_new (double, dash->n_dash);
+ memcpy (priv->dash.dash, dash->dash, dash->n_dash * sizeof (double));
+ }
+ }
+ gnome_canvas_item_request_update (item);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+/* Allocates a GdkColor structure filled with the specified pixel, and
+ * puts it into the specified value for returning it in the get_property
+ * method.
+ */
+
+static void
+get_color_value (GnomeCanvasShape *shape, gulong pixel, GValue *value)
+{
+ GnomeCanvas *canvas = GNOME_CANVAS_ITEM (shape)->canvas;
+ GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
+ GdkColor color;
+
+ gdk_colormap_query_color (colormap, pixel, &color);
+ g_value_set_boxed (value, &color);
+}
+
+/**
+ * gnome_canvas_shape_get_path_def:
+ * @shape: a GnomeCanvasShape
+ *
+ * This function returns the #GnomeCanvasPathDef that the shape
+ * currently uses. It adds a reference to the #GnomeCanvasPathDef and
+ * returns it, if there is not a #GnomeCanvasPathDef set for the shape
+ * it returns NULL.
+ *
+ * Returns: a #GnomeCanvasPathDef or NULL if none is set for the shape.
+ */
+
+GnomeCanvasPathDef *
+gnome_canvas_shape_get_path_def (GnomeCanvasShape *shape)
+{
+ GnomeCanvasShapePriv *priv;
+
+ g_return_val_if_fail (shape != NULL, NULL);
+ g_return_val_if_fail (GNOME_IS_CANVAS_SHAPE (shape), NULL);
+
+ priv = shape->priv;
+
+ if (priv->path) {
+ gnome_canvas_path_def_ref (priv->path);
+ return priv->path;
+ }
+
+ return NULL;
+}
+
+static void
+gnome_canvas_shape_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item = GNOME_CANVAS_ITEM (object);
+ GnomeCanvasShape *shape = GNOME_CANVAS_SHAPE (object);
+ GnomeCanvasShapePriv *priv = shape->priv;
+ GnomeCanvasShapePrivGdk *gdk;
+
+ if (!item->canvas->aa) {
+ gcbp_ensure_gdk (shape);
+ gdk = priv->gdk;
+ }
+ else {
+ gdk = NULL;
+ }
+
+ switch (param_id) {
+ case PROP_FILL_COLOR_GDK:
+ if (gdk) {
+ get_color_value (shape, gdk->fill_pixel, value);
+ } else {
+ get_color_value (shape, 0, value);
+ }
+ break;
+
+ case PROP_OUTLINE_COLOR_GDK:
+ if (gdk) {
+ get_color_value (shape, gdk->outline_pixel, value);
+ } else {
+ get_color_value (shape, 0, value);
+ }
+ break;
+
+ case PROP_FILL_COLOR_RGBA:
+ g_value_set_uint (value, priv->fill_rgba);
+ break;
+
+ case PROP_OUTLINE_COLOR_RGBA:
+ g_value_set_uint (value, priv->outline_rgba);
+ break;
+
+ case PROP_FILL_STIPPLE:
+ if (gdk) {
+ g_value_set_object (value, gdk->fill_stipple);
+ } else {
+ g_value_set_object (value, NULL);
+ }
+ break;
+
+ case PROP_OUTLINE_STIPPLE:
+ if (gdk) {
+ g_value_set_object (value, gdk->outline_stipple);
+ } else {
+ g_value_set_object (value, NULL);
+ }
+ break;
+
+ case PROP_WIND:
+ g_value_set_uint (value, priv->wind);
+ break;
+
+ case PROP_CAP_STYLE:
+ g_value_set_enum (value, priv->cap);
+ break;
+
+ case PROP_JOIN_STYLE:
+ g_value_set_enum (value, priv->join);
+ break;
+
+ case PROP_WIDTH_PIXELS:
+ g_value_set_uint (value, priv->width);
+ break;
+
+ case PROP_WIDTH_UNITS:
+ g_value_set_double (value, priv->width);
+ break;
+
+ case PROP_MITERLIMIT:
+ g_value_set_double (value, priv->miterlimit);
+ break;
+
+ case PROP_DASH:
+ g_value_set_pointer (value, &priv->dash);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gnome_canvas_shape_realize (GnomeCanvasItem *item)
+{
+ GnomeCanvasShape *shape;
+
+ shape = GNOME_CANVAS_SHAPE (item);
+
+ if (parent_class->realize)
+ (* parent_class->realize) (item);
+
+ if (!item->canvas->aa) {
+ gcbp_ensure_gdk (shape);
+
+ g_assert(item->canvas->layout.bin_window != NULL);
+
+ shape->priv->gdk->fill_gc = gdk_gc_new (item->canvas->layout.bin_window);
+ shape->priv->gdk->outline_gc = gdk_gc_new (item->canvas->layout.bin_window);
+ }
+}
+
+static void
+gnome_canvas_shape_unrealize (GnomeCanvasItem *item)
+{
+ GnomeCanvasShape *shape;
+
+ shape = GNOME_CANVAS_SHAPE (item);
+
+ if (!item->canvas->aa) {
+ g_assert (shape->priv->gdk != NULL);
+
+ g_object_unref (shape->priv->gdk->fill_gc);
+ shape->priv->gdk->fill_gc = NULL;
+
+ g_object_unref (shape->priv->gdk->outline_gc);
+ shape->priv->gdk->outline_gc = NULL;
+ }
+
+ if (parent_class->unrealize)
+ (* parent_class->unrealize) (item);
+}
+
+static void
+gnome_canvas_shape_render (GnomeCanvasItem *item,
+ GnomeCanvasBuf *buf)
+{
+ GnomeCanvasShape *shape;
+
+ shape = GNOME_CANVAS_SHAPE (item);
+
+ if (shape->priv->fill_svp != NULL)
+ gnome_canvas_render_svp (buf,
+ shape->priv->fill_svp,
+ shape->priv->fill_rgba);
+
+ if (shape->priv->outline_svp != NULL)
+ gnome_canvas_render_svp (buf,
+ shape->priv->outline_svp,
+ shape->priv->outline_rgba);
+}
+
+static void
+gnome_canvas_shape_draw (GnomeCanvasItem *item,
+ GdkDrawable *drawable,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ static GdkPoint * dpoints = NULL;
+ static gint num_dpoints = 0;
+
+ GnomeCanvasShape * shape;
+ GnomeCanvasShapePriv * priv;
+ GnomeCanvasShapePrivGdk * gdk;
+ gint i, pos, len;
+ GSList * l;
+
+ shape = GNOME_CANVAS_SHAPE (item);
+ priv = shape->priv;
+
+ /* We have to be realized, so gdk struct should exist! */
+
+ gdk = shape->priv->gdk;
+ g_assert (gdk != NULL);
+
+ /* Build temporary point list, translated by -x, -y */
+
+ if (dpoints == NULL) {
+ dpoints = g_new (GdkPoint, gdk->num_points);
+ num_dpoints = gdk->num_points;
+ } else if (num_dpoints < gdk->num_points) {
+ dpoints = g_renew (GdkPoint, dpoints, gdk->num_points);
+ num_dpoints = gdk->num_points;
+ }
+
+ for (i = 0; i < gdk->num_points; i++) {
+ dpoints[i].x = gdk->points[i].x - x;
+ dpoints[i].y = gdk->points[i].y - y;
+ }
+
+ if (priv->fill_set) {
+
+ /* Ensure, that we have mask and it is big enough */
+
+ gcbp_ensure_mask (shape, width, height);
+
+ /* Clear mask */
+
+ gdk_draw_rectangle (gdk->ctx->mask,
+ gdk->ctx->clear_gc,
+ TRUE,
+ 0, 0,
+ width, height);
+
+ /* Draw subpaths, using XOR gc */
+
+ pos = 0;
+
+ for (l = gdk->closed_paths; l != NULL; l = l->next) {
+ len = GPOINTER_TO_INT (l->data);
+
+ gdk_draw_polygon (gdk->ctx->mask,
+ gdk->ctx->xor_gc,
+ TRUE,
+ &dpoints[pos],
+ len);
+
+ pos += len;
+ }
+
+ /* Set bitmap to clipping mask */
+
+ gdk_gc_set_clip_mask (gdk->fill_gc, gdk->ctx->mask);
+
+ /* Stipple offset */
+
+ if (gdk->fill_stipple) gnome_canvas_set_stipple_origin (item->canvas, gdk->fill_gc);
+
+ /* Draw clipped rect to drawable */
+
+ gdk_draw_rectangle (drawable,
+ gdk->fill_gc,
+ TRUE,
+ 0, 0,
+ width, height);
+ }
+
+ if (priv->outline_set) {
+
+ /* Stipple offset */
+
+ if (gdk->outline_stipple) gnome_canvas_set_stipple_origin (item->canvas, gdk->outline_gc);
+ /* Draw subpaths */
+
+ pos = 0;
+
+ for (l = gdk->closed_paths; l != NULL; l = l->next) {
+ len = GPOINTER_TO_INT (l->data);
+
+ gdk_draw_polygon (drawable,
+ gdk->outline_gc,
+ FALSE,
+ &dpoints[pos],
+ len);
+
+ pos += len;
+ }
+
+ for (l = gdk->open_paths; l != NULL; l = l->next) {
+ len = GPOINTER_TO_INT (l->data);
+
+ gdk_draw_lines (drawable,
+ gdk->outline_gc,
+ &dpoints[pos],
+ len);
+
+ pos += len;
+ }
+ }
+}
+
+#define GDK_POINTS_BLOCK 32
+
+static void
+gnome_canvas_shape_ensure_gdk_points (GnomeCanvasShapePrivGdk *gdk, gint num)
+{
+ if (gdk->len_points < gdk->num_points + num) {
+ gdk->len_points = MAX (gdk->len_points + GDK_POINTS_BLOCK, gdk->len_points + num);
+ gdk->points = g_renew (GdkPoint, gdk->points, gdk->len_points);
+ }
+}
+
+static void
+gnome_canvas_shape_update_gdk (GnomeCanvasShape * shape, double * affine, ArtSVP * clip, int flags)
+{
+ GnomeCanvasShapePriv * priv;
+ GnomeCanvasShapePrivGdk * gdk;
+ int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+ gboolean bbox_set = FALSE;
+ gint width = 0; /* silence gcc */
+
+ g_assert (!((GnomeCanvasItem *) shape)->canvas->aa);
+
+ priv = shape->priv;
+ gdk = priv->gdk;
+ g_assert (gdk != NULL);
+
+ if (priv->outline_set) {
+ GdkLineStyle style;
+
+ if (priv->width_pixels) {
+ width = (int) floor (priv->width + 0.5);
+ /* Never select 0 pixels unless the user asked for it,
+ * since that is the X11 zero width lines are non-specified */
+ if (priv->width_pixels != 0 && width == 0) {
+ width = 1;
+ }
+ } else {
+ width = (int) floor ((priv->width * priv->scale) + 0.5);
+ /* Never select 0 pixels unless the user asked for it,
+ * since that is the X11 zero width lines are non-speciifed */
+ if (priv->width != 0 && width == 0) {
+ width = 1;
+ }
+ }
+
+ /* If dashed, set it in GdkGC */
+
+ if ((shape->priv->dash.dash != NULL) && (shape->priv->dash.n_dash > 0)) {
+ gint8 * dash_list;
+ gint i;
+
+ dash_list = g_new (gint8, shape->priv->dash.n_dash);
+
+ for (i = 0; i < priv->dash.n_dash; i++) {
+ dash_list[i] = (gint8) shape->priv->dash.dash[i];
+ }
+
+ gdk_gc_set_dashes (gdk->outline_gc,
+ (gint) priv->dash.offset,
+ dash_list,
+ priv->dash.n_dash);
+
+ g_free (dash_list);
+
+ style = GDK_LINE_ON_OFF_DASH;
+ } else {
+ style = GDK_LINE_SOLID;
+ }
+
+ /* Set line width, cap, join */
+ if(gdk->outline_gc) {
+
+ gdk_gc_set_line_attributes (gdk->outline_gc,
+ width,
+ style,
+ priv->cap,
+ priv->join);
+
+ /* Colors and stipples */
+ set_gc_foreground (gdk->outline_gc, gdk->outline_pixel);
+ set_stipple (gdk->outline_gc, &gdk->outline_stipple, gdk->outline_stipple, TRUE);
+ }
+ }
+
+ if (priv->fill_set) {
+
+ /* Colors and stipples */
+ if(gdk->fill_gc) {
+ set_gc_foreground (gdk->fill_gc, gdk->fill_pixel);
+ set_stipple (gdk->fill_gc, &gdk->fill_stipple, gdk->fill_stipple, TRUE);
+ }
+ }
+
+ /* Now the crazy part */
+
+ /* Free existing GdkPoint array */
+
+ if (gdk->points) {
+ g_free (gdk->points);
+ gdk->points = NULL;
+ gdk->len_points = 0;
+ gdk->num_points = 0;
+ }
+
+ /* Free subpath lists */
+
+ while (gdk->closed_paths) gdk->closed_paths = g_slist_remove (gdk->closed_paths, gdk->closed_paths->data);
+ while (gdk->open_paths) gdk->open_paths = g_slist_remove (gdk->open_paths, gdk->open_paths->data);
+
+ /* Calcualte new GdkPoints array and subpath lists */
+
+ if (priv->path) {
+ GnomeCanvasPathDef * apath, * cpath, * opath;
+ ArtBpath * abpath;
+ GSList * clist, * olist;
+ gint pos;
+
+#if 0
+ /* Allocate array */
+ gdk->num_points = gnome_canvas_path_def_length (priv->path) * 1000 - 1;
+ gdk->points = g_new (GdkPoint, gdk->num_points);
+ g_print ("Points %d\n", gdk->num_points);
+ /* Transform path */
+#endif
+
+ abpath = art_bpath_affine_transform (gnome_canvas_path_def_bpath (priv->path), affine);
+ apath = gnome_canvas_path_def_new_from_bpath (abpath);
+
+ /* Split path into open and closed parts */
+
+ cpath = gnome_canvas_path_def_closed_parts (apath);
+ opath = gnome_canvas_path_def_open_parts (apath);
+ gnome_canvas_path_def_unref (apath);
+
+ /* Split partial paths into subpaths */
+
+ clist = gnome_canvas_path_def_split (cpath);
+ gnome_canvas_path_def_unref (cpath);
+ olist = gnome_canvas_path_def_split (opath);
+ gnome_canvas_path_def_unref (opath);
+
+ pos = 0;
+
+ /* Fill GdkPoints and add subpaths to list: closed subpaths */
+
+ while (clist) {
+ GnomeCanvasPathDef * path;
+ ArtBpath * bpath;
+ ArtVpath * vpath;
+ gint len, i;
+
+ path = (GnomeCanvasPathDef *) clist->data;
+ bpath = gnome_canvas_path_def_bpath (path);
+ vpath = art_bez_path_to_vec (bpath, 0.1);
+ for (len = 0; vpath[len].code != ART_END; len++) ;
+
+ gnome_canvas_shape_ensure_gdk_points (gdk, len);
+ for (i = 0; i < len; i++) {
+ gdk->points[pos + i].x = (gint) floor (vpath[i].x + 0.5);
+ gdk->points[pos + i].y = (gint) floor (vpath[i].y + 0.5);
+
+ if (bbox_set) {
+ x1 = MIN (x1, gdk->points[pos + i].x);
+ x2 = MAX (x2, gdk->points[pos + i].x);
+ y1 = MIN (y1, gdk->points[pos + i].y);
+ y2 = MAX (y2, gdk->points[pos + i].y);
+ } else {
+ bbox_set = TRUE;
+ x1 = x2 = gdk->points[pos + i].x;
+ y1 = y2 = gdk->points[pos + i].y;
+ }
+ }
+ gdk->num_points += len;
+
+ art_free (vpath);
+
+ if (len > 0) {
+ pos += len;
+ gdk->closed_paths = g_slist_append (gdk->closed_paths, GINT_TO_POINTER (len));
+ }
+
+ gnome_canvas_path_def_unref (path);
+ clist = g_slist_remove (clist, clist->data);
+ }
+
+ /* Fill GdkPoints and add subpaths to list: open subpaths */
+
+ while (olist) {
+ GnomeCanvasPathDef * path;
+ ArtBpath * bpath;
+ ArtVpath * vpath;
+ gint len, i;
+
+ path = (GnomeCanvasPathDef *) olist->data;
+ bpath = gnome_canvas_path_def_bpath (path);
+ vpath = art_bez_path_to_vec (bpath, 0.1);
+ for (len = 0; vpath[len].code != ART_END; len++) ;
+
+ gnome_canvas_shape_ensure_gdk_points (gdk, len);
+ for (i = 0; i < len; i++) {
+ gdk->points[pos + i].x = (gint) floor (vpath[i].x + 0.5);
+ gdk->points[pos + i].y = (gint) floor (vpath[i].y + 0.5);
+
+ if (bbox_set) {
+ x1 = MIN (x1, gdk->points[pos + i].x);
+ x2 = MAX (x2, gdk->points[pos + i].x);
+ y1 = MIN (y1, gdk->points[pos + i].y);
+ y2 = MAX (y2, gdk->points[pos + i].y);
+ } else {
+ bbox_set = TRUE;
+ x1 = x2 = gdk->points[pos + i].x;
+ y1 = y2 = gdk->points[pos + i].y;
+ }
+ }
+ gdk->num_points += len;
+
+ art_free (vpath);
+
+ if (len > 0) {
+ pos += len;
+ gdk->open_paths = g_slist_append (gdk->open_paths, GINT_TO_POINTER (len));
+ }
+
+ gnome_canvas_path_def_unref (path);
+ olist = g_slist_remove (olist, olist->data);
+ }
+
+ }
+
+ if (bbox_set) {
+ if (priv->outline_set) {
+ int stroke_border = (priv->join == GDK_JOIN_MITER)
+ ? ceil (10.43*width/2) /* 10.43 is the miter limit for X11 */
+ : ceil (width/2);
+ x1 -= stroke_border;
+ x2 += stroke_border;
+ y1 -= stroke_border;
+ y2 += stroke_border;
+ }
+
+ gnome_canvas_update_bbox (GNOME_CANVAS_ITEM (shape),
+ x1, y1,
+ x2 + 1, y2 + 1);
+ }
+
+}
+
+static void
+gnome_canvas_shape_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+ GnomeCanvasShape * shape;
+ GnomeCanvasShapePriv * priv;
+ ArtSVP * svp;
+
+ shape = GNOME_CANVAS_SHAPE (item);
+
+ priv = shape->priv;
+
+ /* Common part */
+ if (parent_class->update) {
+ (* parent_class->update) (item, affine, clip_path, flags);
+ }
+
+ /* Outline width */
+ shape->priv->scale = art_affine_expansion (affine);
+
+ /* Reset bbox */
+ if (item->canvas->aa) {
+ gnome_canvas_item_reset_bounds (item);
+ }
+
+ /* Clipped fill SVP */
+
+ if ((priv->fill_set) && (priv->path) && (gnome_canvas_path_def_any_closed (priv->path))) {
+ GnomeCanvasPathDef * cpath;
+ ArtSvpWriter *swr;
+ ArtVpath *vpath;
+ ArtBpath *abp;
+ ArtSVP *svp2;
+
+ /* Get closed part of path */
+
+ cpath = gnome_canvas_path_def_closed_parts (shape->priv->path);
+ abp = art_bpath_affine_transform (gnome_canvas_path_def_bpath (cpath), affine);
+ gnome_canvas_path_def_unref (cpath);
+
+ /* Render, until SVP */
+
+ vpath = art_bez_path_to_vec (abp, 0.1);
+ art_free (abp);
+
+ svp = art_svp_from_vpath (vpath);
+ art_free (vpath);
+
+ swr = art_svp_writer_rewind_new (shape->priv->wind);
+ art_svp_intersector (svp, swr);
+
+ svp2 = art_svp_writer_rewind_reap (swr);
+ art_svp_free (svp);
+
+ if (item->canvas->aa) {
+ /* Update clipped path */
+ gnome_canvas_item_update_svp_clip (item,
+ &shape->priv->fill_svp,
+ svp2,
+ clip_path);
+ } else {
+ if (priv->fill_svp) {
+ art_svp_free (priv->fill_svp);
+ priv->fill_svp = NULL;
+ }
+ /* No clipping */
+ shape->priv->fill_svp = svp2;
+ }
+ }
+
+ if (priv->outline_set && priv->path && !gnome_canvas_path_def_is_empty (priv->path)) {
+ gdouble width;
+ ArtBpath * abp;
+ ArtVpath * vpath;
+
+ /* Set linewidth */
+
+ if (priv->width_pixels) {
+ width = priv->width;
+ } else {
+ width = priv->width * priv->scale;
+ }
+
+ if (width < 0.5) width = 0.5;
+
+ /* Render full path until vpath */
+
+ abp = art_bpath_affine_transform (gnome_canvas_path_def_bpath (priv->path), affine);
+
+ vpath = art_bez_path_to_vec (abp, 0.1);
+ art_free (abp);
+
+ /* If dashed, apply dash */
+
+ if (priv->dash.dash != NULL)
+ {
+ ArtVpath *old = vpath;
+
+ vpath = art_vpath_dash (old, &priv->dash);
+ art_free (old);
+ }
+
+ /* Stroke vpath to SVP */
+
+ svp = art_svp_vpath_stroke (vpath,
+ gnome_canvas_join_gdk_to_art (priv->join),
+ gnome_canvas_cap_gdk_to_art (priv->cap),
+ width,
+ priv->miterlimit,
+ 0.25);
+ art_free (vpath);
+
+ if (item->canvas->aa) {
+ /* Update clipped */
+ gnome_canvas_item_update_svp_clip (item, &priv->outline_svp, svp, clip_path);
+ } else {
+ if (priv->outline_svp) {
+ art_svp_free (priv->outline_svp);
+ priv->outline_svp = NULL;
+ }
+ /* No clipping (yet) */
+ shape->priv->outline_svp = svp;
+ }
+ }
+
+ /* Gdk requires additional handling */
+
+ if (!item->canvas->aa) {
+ gnome_canvas_shape_update_gdk (shape, affine, clip_path, flags);
+ }
+}
+
+static double
+gnome_canvas_shape_point (GnomeCanvasItem *item, double x, double y,
+ int cx, int cy, GnomeCanvasItem **actual_item)
+{
+ GnomeCanvasShape *shape;
+ double dist;
+ int wind;
+
+#if 0
+ /* fixme: This is just for debugging, canvas should ensure that */
+ /* fixme: IF YOU ARE SURE THAT IT IS CORRECT BEHAVIOUR, you can remove warning */
+ /* fixme: and make it to return silently */
+ g_return_val_if_fail (!item->canvas->need_update, 1e18);
+#endif
+
+ shape = GNOME_CANVAS_SHAPE (item);
+
+ /* todo: update? */
+ if (shape->priv->fill_set && shape->priv->fill_svp) {
+ wind = art_svp_point_wind (shape->priv->fill_svp, cx, cy);
+ if ((shape->priv->wind == ART_WIND_RULE_NONZERO) && (wind != 0)) {
+ *actual_item = item;
+ return 0.0;
+ }
+ if ((shape->priv->wind == ART_WIND_RULE_ODDEVEN) && ((wind & 0x1) != 0)) {
+ *actual_item = item;
+ return 0.0;
+ }
+ }
+
+ if (shape->priv->outline_set && shape->priv->outline_svp) {
+ wind = art_svp_point_wind (shape->priv->outline_svp, cx, cy);
+ if (wind) {
+ *actual_item = item;
+ return 0.0;
+ }
+ }
+
+ if (shape->priv->outline_set && shape->priv->outline_svp) {
+ dist = art_svp_point_dist (shape->priv->outline_svp, cx, cy);
+ } else if (shape->priv->fill_set && shape->priv->outline_svp) {
+ dist = art_svp_point_dist (shape->priv->fill_svp, cx, cy);
+ } else {
+ return 1e12;
+ }
+
+ *actual_item = item;
+
+ return dist;
+}
+
+/* Helpers */
+
+/* Get 32bit rgba color from GdkColor */
+
+static guint32
+get_rgba_from_color (GdkColor * color)
+{
+ return ((color->red & 0xff00) << 16) | ((color->green & 0xff00) << 8) | (color->blue & 0xff00) | 0xff;
+}
+
+/* Get Gdk pixel value from 32bit rgba color */
+
+static gulong
+get_pixel_from_rgba (GnomeCanvasItem *item, guint32 rgba_color)
+{
+ return gnome_canvas_get_color_pixel (item->canvas, rgba_color);
+}
+
+/* Convenience function to set a GC's foreground color to the specified pixel value */
+
+static void
+set_gc_foreground (GdkGC *gc, gulong pixel)
+{
+ GdkColor c;
+
+ g_assert (gc != NULL);
+
+ c.pixel = pixel;
+
+ gdk_gc_set_foreground (gc, &c);
+}
+
+/* Sets the stipple pattern for the specified gc */
+
+static void
+set_stipple (GdkGC *gc, GdkBitmap **internal_stipple, GdkBitmap *stipple, int reconfigure)
+{
+ if (*internal_stipple && !reconfigure)
+ g_object_unref (*internal_stipple);
+
+ *internal_stipple = stipple;
+ if (stipple && !reconfigure)
+ g_object_ref (stipple);
+
+ if (gc) {
+ if (stipple) {
+ gdk_gc_set_stipple (gc, stipple);
+ gdk_gc_set_fill (gc, GDK_STIPPLED);
+ } else
+ gdk_gc_set_fill (gc, GDK_SOLID);
+ }
+}
+
+/* Creates private Gdk struct, if not present */
+/* We cannot do it during ::init, as we have to know canvas */
+
+static void
+gcbp_ensure_gdk (GnomeCanvasShape * shape)
+{
+ g_assert (!((GnomeCanvasItem *) shape)->canvas->aa);
+
+ if (!shape->priv->gdk) {
+ GnomeCanvasShapePrivGdk * gdk;
+
+ gdk = g_new (GnomeCanvasShapePrivGdk, 1);
+
+ gdk->fill_pixel = get_pixel_from_rgba ((GnomeCanvasItem *) shape, shape->priv->fill_rgba);
+ gdk->outline_pixel = get_pixel_from_rgba ((GnomeCanvasItem *) shape, shape->priv->outline_rgba);
+
+ gdk->fill_stipple = NULL;
+ gdk->outline_stipple = NULL;
+
+ gdk->fill_gc = NULL;
+ gdk->outline_gc = NULL;
+
+ gdk->len_points = 0;
+ gdk->num_points = 0;
+ gdk->points = NULL;
+ gdk->closed_paths = NULL;
+ gdk->open_paths = NULL;
+
+ gdk->ctx = NULL;
+
+ shape->priv->gdk = gdk;
+ }
+}
+
+/* Destroy private Gdk struct */
+/* It is here, to make ::destroy implementation shorter :) */
+
+static void
+gcbp_destroy_gdk (GnomeCanvasShape * shape)
+{
+ GnomeCanvasShapePrivGdk * gdk;
+
+ g_assert (!((GnomeCanvasItem *)shape)->canvas->aa);
+
+ gdk = shape->priv->gdk;
+
+ if (gdk) {
+ g_assert (!gdk->fill_gc);
+ g_assert (!gdk->outline_gc);
+
+ if (gdk->fill_stipple)
+ g_object_unref (gdk->fill_stipple);
+
+ if (gdk->outline_stipple)
+ g_object_unref (gdk->outline_stipple);
+
+ if (gdk->points)
+ g_free (gdk->points);
+
+ while (gdk->closed_paths)
+ gdk->closed_paths = g_slist_remove (gdk->closed_paths, gdk->closed_paths->data);
+ while (gdk->open_paths)
+ gdk->open_paths = g_slist_remove (gdk->open_paths, gdk->open_paths->data);
+
+ if (gdk->ctx)
+ gcbp_draw_ctx_unref (gdk->ctx);
+
+ g_free (gdk);
+
+ shape->priv->gdk = NULL;
+ }
+}
+
+/*
+ * Ensure, that per-canvas Ctx struct is present and bitmaps are
+ * big enough, to mask full redraw area. Ctx is refcounted and
+ * defined as "BpathDrawCtx" data member on parent canvas
+ */
+
+static void
+gcbp_ensure_mask (GnomeCanvasShape * shape, gint width, gint height)
+{
+ GnomeCanvasShapePrivGdk * gdk;
+ GCBPDrawCtx * ctx;
+
+ gdk = shape->priv->gdk;
+ g_assert (gdk != NULL);
+ ctx = gdk->ctx;
+
+ if (!ctx) {
+ /* Ctx is not yet defined for us */
+
+ GnomeCanvas * canvas;
+
+ canvas = GNOME_CANVAS_ITEM (shape)->canvas;
+
+ ctx = g_object_get_data (G_OBJECT (canvas), "BpathDrawCtx");
+
+ if (!ctx) {
+ /* Ctx is not defined for parent canvas yet */
+
+ ctx = g_new (GCBPDrawCtx, 1);
+
+ ctx->refcount = 1;
+ ctx->canvas = canvas;
+ ctx->width = 0;
+ ctx->height = 0;
+
+ ctx->mask = NULL;
+ ctx->clip = NULL;
+
+ ctx->clear_gc = NULL;
+ ctx->xor_gc = NULL;
+
+ g_object_set_data (G_OBJECT (canvas), "BpathDrawCtx", ctx);
+
+ } else {
+ ctx->refcount++;
+ }
+
+ gdk->ctx = ctx;
+
+ }
+
+ /* Now we are sure, that ctx is present and properly refcounted */
+
+ if ((width > ctx->width) || (height > ctx->height)) {
+ /* Ctx is too small */
+
+ GdkWindow * window;
+
+ window = ((GtkWidget *) (((GnomeCanvasItem *) shape)->canvas))->window;
+
+ if (ctx->clear_gc) g_object_unref (ctx->clear_gc);
+ if (ctx->xor_gc) g_object_unref (ctx->xor_gc);
+ if (ctx->mask) g_object_unref (ctx->mask);
+ if (ctx->clip) g_object_unref (ctx->clip);
+
+ ctx->mask = gdk_pixmap_new (window, width, height, 1);
+ ctx->clip = NULL;
+
+ ctx->clear_gc = gdk_gc_new (ctx->mask);
+ gdk_gc_set_function (ctx->clear_gc, GDK_CLEAR);
+
+ ctx->xor_gc = gdk_gc_new (ctx->mask);
+ gdk_gc_set_function (ctx->xor_gc, GDK_INVERT);
+ }
+}
+
+/* It is cleaner to have it here, not in parent function */
+
+static void
+gcbp_draw_ctx_unref (GCBPDrawCtx * ctx)
+{
+ if (--ctx->refcount < 1) {
+ if (ctx->clear_gc)
+ g_object_unref (ctx->clear_gc);
+ if (ctx->xor_gc)
+ g_object_unref (ctx->xor_gc);
+
+ if (ctx->mask)
+ g_object_unref (ctx->mask);
+ if (ctx->clip)
+ g_object_unref (ctx->clip);
+
+ g_object_set_data (G_OBJECT (ctx->canvas), "BpathDrawCtx", NULL);
+ g_free (ctx);
+ }
+}
+
+static void
+gnome_canvas_shape_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
+{
+ GnomeCanvasShape * shape;
+ GnomeCanvasShapePriv * priv;
+ ArtDRect bbox;
+ ArtSVP * svp;
+
+ shape = GNOME_CANVAS_SHAPE (item);
+
+ priv = shape->priv;
+
+ bbox.x0 = *x1;
+ bbox.y0 = *y1;
+ bbox.x1 = *x2;
+ bbox.y1 = *y2;
+
+ if (priv->outline_set && priv->path && !gnome_canvas_path_def_is_empty (priv->path)) {
+ gdouble width;
+ ArtVpath * vpath;
+
+ /* Set linewidth */
+
+ if (priv->width_pixels) {
+ width = priv->width;
+ } else {
+ width = priv->width * priv->scale;
+ }
+
+ if (width < 0.5) width = 0.5;
+
+ /* Render full path until vpath */
+
+ vpath = art_bez_path_to_vec (gnome_canvas_path_def_bpath (priv->path), 0.1);
+
+ /* If dashed, apply dash */
+
+ if (priv->dash.dash != NULL)
+ {
+ ArtVpath *old = vpath;
+
+ vpath = art_vpath_dash (old, &priv->dash);
+ art_free (old);
+ }
+
+ /* Stroke vpath to SVP */
+
+ svp = art_svp_vpath_stroke (vpath,
+ gnome_canvas_join_gdk_to_art (priv->join),
+ gnome_canvas_cap_gdk_to_art (priv->cap),
+ width,
+ priv->miterlimit,
+ 0.25);
+ art_free (vpath);
+ art_drect_svp (&bbox, svp);
+ art_svp_free (svp);
+ } else if ((priv->fill_set) && (priv->path) && (gnome_canvas_path_def_any_closed (priv->path))) {
+ GnomeCanvasPathDef *cpath;
+ ArtSvpWriter *swr;
+ ArtVpath *vpath;
+ ArtSVP *svp2;
+
+ /* Get closed part of path */
+ cpath = gnome_canvas_path_def_closed_parts (shape->priv->path);
+ /* Render, until SVP */
+ vpath = art_bez_path_to_vec (gnome_canvas_path_def_bpath (cpath), 0.1);
+ gnome_canvas_path_def_unref (cpath);
+
+ svp = art_svp_from_vpath (vpath);
+ art_free (vpath);
+
+ swr = art_svp_writer_rewind_new (shape->priv->wind);
+ art_svp_intersector (svp, swr);
+
+ svp2 = art_svp_writer_rewind_reap (swr);
+ art_svp_free (svp);
+
+ art_drect_svp (&bbox, svp2);
+ art_svp_free (svp2);
+ }
+
+ *x1 = bbox.x0;
+ *y1 = bbox.y0;
+ *x2 = bbox.x1;
+ *y2 = bbox.y1;
+}