1 /* Generic bezier shape item for GnomeCanvasWidget. Most code taken
2 * from gnome-canvas-bpath but made into a shape item.
4 * GnomeCanvas is basically a port of the Tk toolkit's most excellent
5 * canvas widget. Tk is copyrighted by the Regents of the University
6 * of California, Sun Microsystems, and other parties.
8 * Copyright (C) 1998,1999 The Free Software Foundation
10 * Authors: Federico Mena <federico@nuclecu.unam.mx>
11 * Raph Levien <raph@acm.org>
12 * Lauris Kaplinski <lauris@ximian.com>
13 * Miguel de Icaza <miguel@kernel.org>
14 * Cody Russell <bratsche@gnome.org>
15 * Rusty Conover <rconover@bangtail.net>
18 /* These includes are set up for standalone compile. If/when this codebase
19 is integrated into libgnomeui, the includes will need to change. */
25 #include "gnome-canvas.h"
26 #include "gnome-canvas-util.h"
28 #include "gnome-canvas-shape.h"
29 #include "gnome-canvas-shape-private.h"
30 #include "gnome-canvas-path-def.h"
32 #include <libart_lgpl/art_rect.h>
33 #include <libart_lgpl/art_vpath.h>
34 #include <libart_lgpl/art_bpath.h>
35 #include <libart_lgpl/art_vpath_bpath.h>
36 #include <libart_lgpl/art_svp.h>
37 #include <libart_lgpl/art_svp_point.h>
38 #include <libart_lgpl/art_svp_vpath.h>
39 #include <libart_lgpl/art_vpath_dash.h>
40 #include <libart_lgpl/art_svp_wind.h>
41 #include <libart_lgpl/art_svp_intersect.h>
42 #include <libart_lgpl/art_rect_svp.h>
50 PROP_OUTLINE_COLOR_GDK,
51 PROP_OUTLINE_COLOR_RGBA,
63 static void gnome_canvas_shape_class_init (GnomeCanvasShapeClass *class);
64 static void gnome_canvas_shape_init (GnomeCanvasShape *bpath);
65 static void gnome_canvas_shape_destroy (GtkObject *object);
66 static void gnome_canvas_shape_set_property (GObject *object,
70 static void gnome_canvas_shape_get_property (GObject *object,
75 static void gnome_canvas_shape_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
76 static void gnome_canvas_shape_realize (GnomeCanvasItem *item);
77 static void gnome_canvas_shape_unrealize (GnomeCanvasItem *item);
78 static void gnome_canvas_shape_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
79 int x, int y, int width, int height);
80 static double gnome_canvas_shape_point (GnomeCanvasItem *item, double x, double y,
81 int cx, int cy, GnomeCanvasItem **actual_item);
82 static void gnome_canvas_shape_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
83 static void gnome_canvas_shape_bounds (GnomeCanvasItem *item,
84 double *x1, double *y1, double *x2, double *y2);
86 static gulong get_pixel_from_rgba (GnomeCanvasItem *item, guint32 rgba_color);
87 static guint32 get_rgba_from_color (GdkColor * color);
88 static void set_gc_foreground (GdkGC *gc, gulong pixel);
89 static void gcbp_ensure_gdk (GnomeCanvasShape * bpath);
90 static void gcbp_destroy_gdk (GnomeCanvasShape * bpath);
91 static void set_stipple (GdkGC *gc, GdkBitmap **internal_stipple, GdkBitmap *stipple, int reconfigure);
92 static void gcbp_ensure_mask (GnomeCanvasShape * bpath, gint width, gint height);
93 static void gcbp_draw_ctx_unref (GCBPDrawCtx * ctx);
95 static GnomeCanvasItemClass *parent_class;
98 gnome_canvas_shape_get_type (void)
100 static GType shape_type;
103 const GTypeInfo object_info = {
104 sizeof (GnomeCanvasShapeClass),
105 (GBaseInitFunc) NULL,
106 (GBaseFinalizeFunc) NULL,
107 (GClassInitFunc) gnome_canvas_shape_class_init,
108 (GClassFinalizeFunc) NULL,
109 NULL, /* class_data */
110 sizeof (GnomeCanvasShape),
112 (GInstanceInitFunc) gnome_canvas_shape_init,
113 NULL /* value_table */
116 shape_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasShape",
124 gnome_canvas_shape_class_init (GnomeCanvasShapeClass *class)
126 GObjectClass *gobject_class;
127 GtkObjectClass *object_class;
128 GnomeCanvasItemClass *item_class;
130 gobject_class = (GObjectClass *) class;
131 object_class = (GtkObjectClass *) class;
132 item_class = (GnomeCanvasItemClass *) class;
134 parent_class = g_type_class_peek_parent (class);
136 /* when this gets checked into libgnomeui, change the
137 GTK_TYPE_POINTER to GTK_TYPE_GNOME_CANVAS_SHAPE, and add an
138 entry to gnome-boxed.defs */
140 gobject_class->set_property = gnome_canvas_shape_set_property;
141 gobject_class->get_property = gnome_canvas_shape_get_property;
145 g_object_class_install_property (gobject_class,
147 g_param_spec_string ("fill_color", NULL, NULL,
149 (G_PARAM_WRITABLE)));
150 g_object_class_install_property (gobject_class,
152 g_param_spec_boxed ("fill_color_gdk", NULL, NULL,
154 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
155 g_object_class_install_property (gobject_class,
156 PROP_FILL_COLOR_RGBA,
157 g_param_spec_uint ("fill_color_rgba", NULL, NULL,
159 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
160 g_object_class_install_property (gobject_class,
162 g_param_spec_string ("outline_color", NULL, NULL,
164 (G_PARAM_WRITABLE)));
165 g_object_class_install_property (gobject_class,
166 PROP_OUTLINE_COLOR_GDK,
167 g_param_spec_boxed ("outline_color_gdk", NULL, NULL,
169 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
170 g_object_class_install_property (gobject_class,
171 PROP_OUTLINE_COLOR_RGBA,
172 g_param_spec_uint ("outline_color_rgba", NULL, NULL,
174 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
175 g_object_class_install_property (gobject_class,
177 g_param_spec_object ("fill_stipple", NULL, NULL,
179 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
180 g_object_class_install_property (gobject_class,
181 PROP_OUTLINE_STIPPLE,
182 g_param_spec_object ("outline_stipple", NULL, NULL,
184 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
185 g_object_class_install_property (gobject_class,
187 g_param_spec_uint ("width_pixels", NULL, NULL,
189 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
190 g_object_class_install_property (gobject_class,
192 g_param_spec_double ("width_units", NULL, NULL,
193 0.0, G_MAXDOUBLE, 0.0,
194 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
195 g_object_class_install_property (gobject_class,
197 g_param_spec_enum ("cap_style", NULL, NULL,
200 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
201 g_object_class_install_property (gobject_class,
203 g_param_spec_enum ("join_style", NULL, NULL,
206 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
207 g_object_class_install_property (gobject_class,
209 g_param_spec_uint ("wind", NULL, NULL,
211 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
212 g_object_class_install_property (gobject_class,
214 g_param_spec_double ("miterlimit", NULL, NULL,
215 0.0, G_MAXDOUBLE, 0.0,
216 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
217 g_object_class_install_property (gobject_class,
219 g_param_spec_pointer ("dash", NULL, NULL,
220 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
222 object_class->destroy = gnome_canvas_shape_destroy;
224 item_class->update = gnome_canvas_shape_update;
225 item_class->realize = gnome_canvas_shape_realize;
226 item_class->unrealize = gnome_canvas_shape_unrealize;
227 item_class->draw = gnome_canvas_shape_draw;
228 item_class->point = gnome_canvas_shape_point;
229 item_class->render = gnome_canvas_shape_render;
230 item_class->bounds = gnome_canvas_shape_bounds;
234 gnome_canvas_shape_init (GnomeCanvasShape *shape)
236 shape->priv = g_new (GnomeCanvasShapePriv, 1);
238 shape->priv->path = NULL;
240 shape->priv->scale = 1.0;
242 shape->priv->fill_set = FALSE;
243 shape->priv->outline_set = FALSE;
244 shape->priv->width_pixels = FALSE;
246 shape->priv->width = 1.0;
248 shape->priv->fill_rgba = 0x0000003f;
249 shape->priv->outline_rgba = 0x0000007f;
251 shape->priv->cap = GDK_CAP_BUTT;
252 shape->priv->join = GDK_JOIN_MITER;
253 shape->priv->wind = ART_WIND_RULE_ODDEVEN;
254 shape->priv->miterlimit = 10.43; /* X11 default */
256 shape->priv->dash.n_dash = 0;
257 shape->priv->dash.dash = NULL;
259 shape->priv->fill_svp = NULL;
260 shape->priv->outline_svp = NULL;
262 shape->priv->gdk = NULL;
266 gnome_canvas_shape_destroy (GtkObject *object)
268 GnomeCanvasShape *shape;
269 GnomeCanvasShapePriv *priv;
271 g_return_if_fail (object != NULL);
272 g_return_if_fail (GNOME_IS_CANVAS_SHAPE (object));
274 shape = GNOME_CANVAS_SHAPE (object);
278 if (priv->gdk) gcbp_destroy_gdk (shape);
280 if (priv->path) gnome_canvas_path_def_unref (priv->path);
282 if (priv->dash.dash) g_free (priv->dash.dash);
283 if (priv->fill_svp) art_svp_free (priv->fill_svp);
284 if (priv->outline_svp) art_svp_free (priv->outline_svp);
286 g_free (shape->priv);
290 if (GTK_OBJECT_CLASS (parent_class)->destroy)
291 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
295 * gnome_canvas_shape_set_path_def:
296 * @shape: a GnomeCanvasShape
297 * @def: a GnomeCanvasPathDef
299 * This function sets the the GnomeCanvasPathDef used by the
300 * GnomeCanvasShape. Notice, that it does not request updates, as
301 * it is meant to be used from item implementations, from inside
306 gnome_canvas_shape_set_path_def (GnomeCanvasShape *shape, GnomeCanvasPathDef *def)
308 GnomeCanvasShapePriv *priv;
310 g_return_if_fail (shape != NULL);
311 g_return_if_fail (GNOME_IS_CANVAS_SHAPE (shape));
316 gnome_canvas_path_def_unref (priv->path);
321 priv->path = gnome_canvas_path_def_duplicate (def);
326 gnome_canvas_shape_set_property (GObject *object,
331 GnomeCanvasItem *item;
332 GnomeCanvasShape *shape;
333 GnomeCanvasShapePriv *priv;
334 GnomeCanvasShapePrivGdk *gdk;
339 item = GNOME_CANVAS_ITEM (object);
340 shape = GNOME_CANVAS_SHAPE (object);
343 if (!item->canvas->aa) {
344 gcbp_ensure_gdk (shape);
351 case PROP_FILL_COLOR:
352 if (gnome_canvas_get_color (item->canvas, g_value_get_string (value), &color)) {
353 priv->fill_set = TRUE;
354 priv->fill_rgba = get_rgba_from_color (&color);
355 if (gdk) gdk->fill_pixel = color.pixel;
356 } else if (priv->fill_set)
357 priv->fill_set = FALSE;
361 gnome_canvas_item_request_update (item);
364 case PROP_FILL_COLOR_GDK:
365 colorptr = g_value_get_boxed (value);
366 if (colorptr != NULL) {
367 priv->fill_set = TRUE;
368 priv->fill_rgba = get_rgba_from_color (colorptr);
370 GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
371 GdkColor tmp = *colorptr;
372 gdk_rgb_find_color (colormap, &tmp);
373 gdk->fill_pixel = tmp.pixel;
375 } else if (priv->fill_set)
376 priv->fill_set = FALSE;
380 gnome_canvas_item_request_update (item);
383 case PROP_FILL_COLOR_RGBA:
384 priv->fill_set = TRUE;
385 priv->fill_rgba = g_value_get_uint (value);
386 if (gdk) gdk->fill_pixel = get_pixel_from_rgba (item, priv->fill_rgba);
388 gnome_canvas_item_request_update (item);
391 case PROP_OUTLINE_COLOR:
392 if (gnome_canvas_get_color (item->canvas, g_value_get_string (value), &color)) {
393 priv->outline_set = TRUE;
394 priv->outline_rgba = get_rgba_from_color (&color);
395 if (gdk) gdk->outline_pixel = color.pixel;
396 } else if (priv->outline_set)
397 priv->outline_set = FALSE;
401 gnome_canvas_item_request_update (item);
404 case PROP_OUTLINE_COLOR_GDK:
405 colorptr = g_value_get_boxed (value);
406 if (colorptr != NULL) {
407 priv->outline_set = TRUE;
408 priv->outline_rgba = get_rgba_from_color (colorptr);
410 GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
411 GdkColor tmp = *colorptr;
412 gdk_rgb_find_color (colormap, &tmp);
413 gdk->outline_pixel = tmp.pixel;
415 } else if (priv->outline_set)
416 priv->outline_set = FALSE;
420 gnome_canvas_item_request_update (item);
423 case PROP_OUTLINE_COLOR_RGBA:
424 priv->outline_set = TRUE;
425 priv->outline_rgba = g_value_get_uint (value);
426 if (gdk) gdk->outline_pixel = get_pixel_from_rgba (item, priv->outline_rgba);
428 gnome_canvas_item_request_update (item);
431 case PROP_FILL_STIPPLE:
433 set_stipple (gdk->fill_gc, &gdk->fill_stipple, (GdkBitmap*) g_value_get_object (value), FALSE);
434 gnome_canvas_item_request_update (item);
438 case PROP_OUTLINE_STIPPLE:
440 set_stipple (gdk->outline_gc, &gdk->outline_stipple, (GdkBitmap*) g_value_get_object (value), FALSE);
441 gnome_canvas_item_request_update (item);
445 case PROP_WIDTH_PIXELS:
446 priv->width = g_value_get_uint (value);
447 priv->width_pixels = TRUE;
449 gnome_canvas_item_request_update (item);
452 case PROP_WIDTH_UNITS:
453 priv->width = fabs (g_value_get_double (value));
454 priv->width_pixels = FALSE;
456 gnome_canvas_item_request_update (item);
460 priv->wind = g_value_get_uint (value);
461 gnome_canvas_item_request_update (item);
465 priv->cap = g_value_get_enum (value);
466 gnome_canvas_item_request_update (item);
469 case PROP_JOIN_STYLE:
470 priv->join = g_value_get_enum (value);
471 gnome_canvas_item_request_update (item);
474 case PROP_MITERLIMIT:
475 priv->miterlimit = g_value_get_double (value);
476 gnome_canvas_item_request_update (item);
480 dash = g_value_get_pointer (value);
481 if (priv->dash.dash) g_free (priv->dash.dash);
482 priv->dash.dash = NULL;
485 priv->dash.offset = dash->offset;
486 priv->dash.n_dash = dash->n_dash;
487 if (dash->dash != NULL) {
488 priv->dash.dash = g_new (double, dash->n_dash);
489 memcpy (priv->dash.dash, dash->dash, dash->n_dash * sizeof (double));
492 gnome_canvas_item_request_update (item);
495 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
500 /* Allocates a GdkColor structure filled with the specified pixel, and
501 * puts it into the specified value for returning it in the get_property
506 get_color_value (GnomeCanvasShape *shape, gulong pixel, GValue *value)
508 GnomeCanvas *canvas = GNOME_CANVAS_ITEM (shape)->canvas;
509 GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
512 gdk_colormap_query_color (colormap, pixel, &color);
513 g_value_set_boxed (value, &color);
517 * gnome_canvas_shape_get_path_def:
518 * @shape: a GnomeCanvasShape
520 * This function returns the #GnomeCanvasPathDef that the shape
521 * currently uses. It adds a reference to the #GnomeCanvasPathDef and
522 * returns it, if there is not a #GnomeCanvasPathDef set for the shape
525 * Returns: a #GnomeCanvasPathDef or NULL if none is set for the shape.
529 gnome_canvas_shape_get_path_def (GnomeCanvasShape *shape)
531 GnomeCanvasShapePriv *priv;
533 g_return_val_if_fail (shape != NULL, NULL);
534 g_return_val_if_fail (GNOME_IS_CANVAS_SHAPE (shape), NULL);
539 gnome_canvas_path_def_ref (priv->path);
547 gnome_canvas_shape_get_property (GObject *object,
552 GnomeCanvasItem *item = GNOME_CANVAS_ITEM (object);
553 GnomeCanvasShape *shape = GNOME_CANVAS_SHAPE (object);
554 GnomeCanvasShapePriv *priv = shape->priv;
555 GnomeCanvasShapePrivGdk *gdk;
557 if (!item->canvas->aa) {
558 gcbp_ensure_gdk (shape);
566 case PROP_FILL_COLOR_GDK:
568 get_color_value (shape, gdk->fill_pixel, value);
570 get_color_value (shape, 0, value);
574 case PROP_OUTLINE_COLOR_GDK:
576 get_color_value (shape, gdk->outline_pixel, value);
578 get_color_value (shape, 0, value);
582 case PROP_FILL_COLOR_RGBA:
583 g_value_set_uint (value, priv->fill_rgba);
586 case PROP_OUTLINE_COLOR_RGBA:
587 g_value_set_uint (value, priv->outline_rgba);
590 case PROP_FILL_STIPPLE:
592 g_value_set_object (value, gdk->fill_stipple);
594 g_value_set_object (value, NULL);
598 case PROP_OUTLINE_STIPPLE:
600 g_value_set_object (value, gdk->outline_stipple);
602 g_value_set_object (value, NULL);
607 g_value_set_uint (value, priv->wind);
611 g_value_set_enum (value, priv->cap);
614 case PROP_JOIN_STYLE:
615 g_value_set_enum (value, priv->join);
618 case PROP_WIDTH_PIXELS:
619 g_value_set_uint (value, priv->width);
622 case PROP_WIDTH_UNITS:
623 g_value_set_double (value, priv->width);
626 case PROP_MITERLIMIT:
627 g_value_set_double (value, priv->miterlimit);
631 g_value_set_pointer (value, &priv->dash);
635 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
641 gnome_canvas_shape_realize (GnomeCanvasItem *item)
643 GnomeCanvasShape *shape;
645 shape = GNOME_CANVAS_SHAPE (item);
647 if (parent_class->realize)
648 (* parent_class->realize) (item);
650 if (!item->canvas->aa) {
651 gcbp_ensure_gdk (shape);
653 g_assert(item->canvas->layout.bin_window != NULL);
655 shape->priv->gdk->fill_gc = gdk_gc_new (item->canvas->layout.bin_window);
656 shape->priv->gdk->outline_gc = gdk_gc_new (item->canvas->layout.bin_window);
661 gnome_canvas_shape_unrealize (GnomeCanvasItem *item)
663 GnomeCanvasShape *shape;
665 shape = GNOME_CANVAS_SHAPE (item);
667 if (!item->canvas->aa) {
668 g_assert (shape->priv->gdk != NULL);
670 g_object_unref (shape->priv->gdk->fill_gc);
671 shape->priv->gdk->fill_gc = NULL;
673 g_object_unref (shape->priv->gdk->outline_gc);
674 shape->priv->gdk->outline_gc = NULL;
677 if (parent_class->unrealize)
678 (* parent_class->unrealize) (item);
682 gnome_canvas_shape_render (GnomeCanvasItem *item,
685 GnomeCanvasShape *shape;
687 shape = GNOME_CANVAS_SHAPE (item);
689 if (shape->priv->fill_svp != NULL)
690 gnome_canvas_render_svp (buf,
691 shape->priv->fill_svp,
692 shape->priv->fill_rgba);
694 if (shape->priv->outline_svp != NULL)
695 gnome_canvas_render_svp (buf,
696 shape->priv->outline_svp,
697 shape->priv->outline_rgba);
701 gnome_canvas_shape_draw (GnomeCanvasItem *item,
702 GdkDrawable *drawable,
708 static GdkPoint * dpoints = NULL;
709 static gint num_dpoints = 0;
711 GnomeCanvasShape * shape;
712 GnomeCanvasShapePriv * priv;
713 GnomeCanvasShapePrivGdk * gdk;
717 shape = GNOME_CANVAS_SHAPE (item);
720 /* We have to be realized, so gdk struct should exist! */
722 gdk = shape->priv->gdk;
723 g_assert (gdk != NULL);
725 /* Build temporary point list, translated by -x, -y */
727 if (dpoints == NULL) {
728 dpoints = g_new (GdkPoint, gdk->num_points);
729 num_dpoints = gdk->num_points;
730 } else if (num_dpoints < gdk->num_points) {
731 dpoints = g_renew (GdkPoint, dpoints, gdk->num_points);
732 num_dpoints = gdk->num_points;
735 for (i = 0; i < gdk->num_points; i++) {
736 dpoints[i].x = gdk->points[i].x - x;
737 dpoints[i].y = gdk->points[i].y - y;
740 if (priv->fill_set) {
742 /* Ensure, that we have mask and it is big enough */
744 gcbp_ensure_mask (shape, width, height);
748 gdk_draw_rectangle (gdk->ctx->mask,
754 /* Draw subpaths, using XOR gc */
758 for (l = gdk->closed_paths; l != NULL; l = l->next) {
759 len = GPOINTER_TO_INT (l->data);
761 gdk_draw_polygon (gdk->ctx->mask,
770 /* Set bitmap to clipping mask */
772 gdk_gc_set_clip_mask (gdk->fill_gc, gdk->ctx->mask);
776 if (gdk->fill_stipple) gnome_canvas_set_stipple_origin (item->canvas, gdk->fill_gc);
778 /* Draw clipped rect to drawable */
780 gdk_draw_rectangle (drawable,
787 if (priv->outline_set) {
791 if (gdk->outline_stipple) gnome_canvas_set_stipple_origin (item->canvas, gdk->outline_gc);
796 for (l = gdk->closed_paths; l != NULL; l = l->next) {
797 len = GPOINTER_TO_INT (l->data);
799 gdk_draw_polygon (drawable,
808 for (l = gdk->open_paths; l != NULL; l = l->next) {
809 len = GPOINTER_TO_INT (l->data);
811 gdk_draw_lines (drawable,
821 #define GDK_POINTS_BLOCK 32
824 gnome_canvas_shape_ensure_gdk_points (GnomeCanvasShapePrivGdk *gdk, gint num)
826 if (gdk->len_points < gdk->num_points + num) {
827 gdk->len_points = MAX (gdk->len_points + GDK_POINTS_BLOCK, gdk->len_points + num);
828 gdk->points = g_renew (GdkPoint, gdk->points, gdk->len_points);
833 gnome_canvas_shape_update_gdk (GnomeCanvasShape * shape, double * affine, ArtSVP * clip, int flags)
835 GnomeCanvasShapePriv * priv;
836 GnomeCanvasShapePrivGdk * gdk;
837 int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
838 gboolean bbox_set = FALSE;
839 gint width = 0; /* silence gcc */
841 g_assert (!((GnomeCanvasItem *) shape)->canvas->aa);
845 g_assert (gdk != NULL);
847 if (priv->outline_set) {
850 if (priv->width_pixels) {
851 width = (int) floor (priv->width + 0.5);
852 /* Never select 0 pixels unless the user asked for it,
853 * since that is the X11 zero width lines are non-specified */
854 if (priv->width_pixels != 0 && width == 0) {
858 width = (int) floor ((priv->width * priv->scale) + 0.5);
859 /* Never select 0 pixels unless the user asked for it,
860 * since that is the X11 zero width lines are non-speciifed */
861 if (priv->width != 0 && width == 0) {
866 /* If dashed, set it in GdkGC */
868 if ((shape->priv->dash.dash != NULL) && (shape->priv->dash.n_dash > 0)) {
872 dash_list = g_new (gint8, shape->priv->dash.n_dash);
874 for (i = 0; i < priv->dash.n_dash; i++) {
875 dash_list[i] = (gint8) shape->priv->dash.dash[i];
878 gdk_gc_set_dashes (gdk->outline_gc,
879 (gint) priv->dash.offset,
885 style = GDK_LINE_ON_OFF_DASH;
887 style = GDK_LINE_SOLID;
890 /* Set line width, cap, join */
891 if(gdk->outline_gc) {
893 gdk_gc_set_line_attributes (gdk->outline_gc,
899 /* Colors and stipples */
900 set_gc_foreground (gdk->outline_gc, gdk->outline_pixel);
901 set_stipple (gdk->outline_gc, &gdk->outline_stipple, gdk->outline_stipple, TRUE);
905 if (priv->fill_set) {
907 /* Colors and stipples */
909 set_gc_foreground (gdk->fill_gc, gdk->fill_pixel);
910 set_stipple (gdk->fill_gc, &gdk->fill_stipple, gdk->fill_stipple, TRUE);
914 /* Now the crazy part */
916 /* Free existing GdkPoint array */
919 g_free (gdk->points);
925 /* Free subpath lists */
927 while (gdk->closed_paths) gdk->closed_paths = g_slist_remove (gdk->closed_paths, gdk->closed_paths->data);
928 while (gdk->open_paths) gdk->open_paths = g_slist_remove (gdk->open_paths, gdk->open_paths->data);
930 /* Calcualte new GdkPoints array and subpath lists */
933 GnomeCanvasPathDef * apath, * cpath, * opath;
935 GSList * clist, * olist;
940 gdk->num_points = gnome_canvas_path_def_length (priv->path) * 1000 - 1;
941 gdk->points = g_new (GdkPoint, gdk->num_points);
942 g_print ("Points %d\n", gdk->num_points);
946 abpath = art_bpath_affine_transform (gnome_canvas_path_def_bpath (priv->path), affine);
947 apath = gnome_canvas_path_def_new_from_bpath (abpath);
949 /* Split path into open and closed parts */
951 cpath = gnome_canvas_path_def_closed_parts (apath);
952 opath = gnome_canvas_path_def_open_parts (apath);
953 gnome_canvas_path_def_unref (apath);
955 /* Split partial paths into subpaths */
957 clist = gnome_canvas_path_def_split (cpath);
958 gnome_canvas_path_def_unref (cpath);
959 olist = gnome_canvas_path_def_split (opath);
960 gnome_canvas_path_def_unref (opath);
964 /* Fill GdkPoints and add subpaths to list: closed subpaths */
967 GnomeCanvasPathDef * path;
972 path = (GnomeCanvasPathDef *) clist->data;
973 bpath = gnome_canvas_path_def_bpath (path);
974 vpath = art_bez_path_to_vec (bpath, 0.1);
975 for (len = 0; vpath[len].code != ART_END; len++) ;
977 gnome_canvas_shape_ensure_gdk_points (gdk, len);
978 for (i = 0; i < len; i++) {
979 gdk->points[pos + i].x = (gint) floor (vpath[i].x + 0.5);
980 gdk->points[pos + i].y = (gint) floor (vpath[i].y + 0.5);
983 x1 = MIN (x1, gdk->points[pos + i].x);
984 x2 = MAX (x2, gdk->points[pos + i].x);
985 y1 = MIN (y1, gdk->points[pos + i].y);
986 y2 = MAX (y2, gdk->points[pos + i].y);
989 x1 = x2 = gdk->points[pos + i].x;
990 y1 = y2 = gdk->points[pos + i].y;
993 gdk->num_points += len;
999 gdk->closed_paths = g_slist_append (gdk->closed_paths, GINT_TO_POINTER (len));
1002 gnome_canvas_path_def_unref (path);
1003 clist = g_slist_remove (clist, clist->data);
1006 /* Fill GdkPoints and add subpaths to list: open subpaths */
1009 GnomeCanvasPathDef * path;
1014 path = (GnomeCanvasPathDef *) olist->data;
1015 bpath = gnome_canvas_path_def_bpath (path);
1016 vpath = art_bez_path_to_vec (bpath, 0.1);
1017 for (len = 0; vpath[len].code != ART_END; len++) ;
1019 gnome_canvas_shape_ensure_gdk_points (gdk, len);
1020 for (i = 0; i < len; i++) {
1021 gdk->points[pos + i].x = (gint) floor (vpath[i].x + 0.5);
1022 gdk->points[pos + i].y = (gint) floor (vpath[i].y + 0.5);
1025 x1 = MIN (x1, gdk->points[pos + i].x);
1026 x2 = MAX (x2, gdk->points[pos + i].x);
1027 y1 = MIN (y1, gdk->points[pos + i].y);
1028 y2 = MAX (y2, gdk->points[pos + i].y);
1031 x1 = x2 = gdk->points[pos + i].x;
1032 y1 = y2 = gdk->points[pos + i].y;
1035 gdk->num_points += len;
1041 gdk->open_paths = g_slist_append (gdk->open_paths, GINT_TO_POINTER (len));
1044 gnome_canvas_path_def_unref (path);
1045 olist = g_slist_remove (olist, olist->data);
1051 if (priv->outline_set) {
1052 int stroke_border = (priv->join == GDK_JOIN_MITER)
1053 ? ceil (10.43*width/2) /* 10.43 is the miter limit for X11 */
1055 x1 -= stroke_border;
1056 x2 += stroke_border;
1057 y1 -= stroke_border;
1058 y2 += stroke_border;
1061 gnome_canvas_update_bbox (GNOME_CANVAS_ITEM (shape),
1069 gnome_canvas_shape_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
1071 GnomeCanvasShape * shape;
1072 GnomeCanvasShapePriv * priv;
1075 shape = GNOME_CANVAS_SHAPE (item);
1080 if (parent_class->update) {
1081 (* parent_class->update) (item, affine, clip_path, flags);
1085 shape->priv->scale = art_affine_expansion (affine);
1088 if (item->canvas->aa) {
1089 gnome_canvas_item_reset_bounds (item);
1092 /* Clipped fill SVP */
1094 if ((priv->fill_set) && (priv->path) && (gnome_canvas_path_def_any_closed (priv->path))) {
1095 GnomeCanvasPathDef * cpath;
1101 /* Get closed part of path */
1103 cpath = gnome_canvas_path_def_closed_parts (shape->priv->path);
1104 abp = art_bpath_affine_transform (gnome_canvas_path_def_bpath (cpath), affine);
1105 gnome_canvas_path_def_unref (cpath);
1107 /* Render, until SVP */
1109 vpath = art_bez_path_to_vec (abp, 0.1);
1112 svp = art_svp_from_vpath (vpath);
1115 swr = art_svp_writer_rewind_new (shape->priv->wind);
1116 art_svp_intersector (svp, swr);
1118 svp2 = art_svp_writer_rewind_reap (swr);
1121 if (item->canvas->aa) {
1122 /* Update clipped path */
1123 gnome_canvas_item_update_svp_clip (item,
1124 &shape->priv->fill_svp,
1128 if (priv->fill_svp) {
1129 art_svp_free (priv->fill_svp);
1130 priv->fill_svp = NULL;
1133 shape->priv->fill_svp = svp2;
1137 if (priv->outline_set && priv->path && !gnome_canvas_path_def_is_empty (priv->path)) {
1144 if (priv->width_pixels) {
1145 width = priv->width;
1147 width = priv->width * priv->scale;
1150 if (width < 0.5) width = 0.5;
1152 /* Render full path until vpath */
1154 abp = art_bpath_affine_transform (gnome_canvas_path_def_bpath (priv->path), affine);
1156 vpath = art_bez_path_to_vec (abp, 0.1);
1159 /* If dashed, apply dash */
1161 if (priv->dash.dash != NULL)
1163 ArtVpath *old = vpath;
1165 vpath = art_vpath_dash (old, &priv->dash);
1169 /* Stroke vpath to SVP */
1171 svp = art_svp_vpath_stroke (vpath,
1172 gnome_canvas_join_gdk_to_art (priv->join),
1173 gnome_canvas_cap_gdk_to_art (priv->cap),
1179 if (item->canvas->aa) {
1180 /* Update clipped */
1181 gnome_canvas_item_update_svp_clip (item, &priv->outline_svp, svp, clip_path);
1183 if (priv->outline_svp) {
1184 art_svp_free (priv->outline_svp);
1185 priv->outline_svp = NULL;
1187 /* No clipping (yet) */
1188 shape->priv->outline_svp = svp;
1192 /* Gdk requires additional handling */
1194 if (!item->canvas->aa) {
1195 gnome_canvas_shape_update_gdk (shape, affine, clip_path, flags);
1200 gnome_canvas_shape_point (GnomeCanvasItem *item, double x, double y,
1201 int cx, int cy, GnomeCanvasItem **actual_item)
1203 GnomeCanvasShape *shape;
1208 /* fixme: This is just for debugging, canvas should ensure that */
1209 /* fixme: IF YOU ARE SURE THAT IT IS CORRECT BEHAVIOUR, you can remove warning */
1210 /* fixme: and make it to return silently */
1211 g_return_val_if_fail (!item->canvas->need_update, 1e18);
1214 shape = GNOME_CANVAS_SHAPE (item);
1217 if (shape->priv->fill_set && shape->priv->fill_svp) {
1218 wind = art_svp_point_wind (shape->priv->fill_svp, cx, cy);
1219 if ((shape->priv->wind == ART_WIND_RULE_NONZERO) && (wind != 0)) {
1220 *actual_item = item;
1223 if ((shape->priv->wind == ART_WIND_RULE_ODDEVEN) && ((wind & 0x1) != 0)) {
1224 *actual_item = item;
1229 if (shape->priv->outline_set && shape->priv->outline_svp) {
1230 wind = art_svp_point_wind (shape->priv->outline_svp, cx, cy);
1232 *actual_item = item;
1237 if (shape->priv->outline_set && shape->priv->outline_svp) {
1238 dist = art_svp_point_dist (shape->priv->outline_svp, cx, cy);
1239 } else if (shape->priv->fill_set && shape->priv->outline_svp) {
1240 dist = art_svp_point_dist (shape->priv->fill_svp, cx, cy);
1245 *actual_item = item;
1252 /* Get 32bit rgba color from GdkColor */
1255 get_rgba_from_color (GdkColor * color)
1257 return ((color->red & 0xff00) << 16) | ((color->green & 0xff00) << 8) | (color->blue & 0xff00) | 0xff;
1260 /* Get Gdk pixel value from 32bit rgba color */
1263 get_pixel_from_rgba (GnomeCanvasItem *item, guint32 rgba_color)
1265 return gnome_canvas_get_color_pixel (item->canvas, rgba_color);
1268 /* Convenience function to set a GC's foreground color to the specified pixel value */
1271 set_gc_foreground (GdkGC *gc, gulong pixel)
1275 g_assert (gc != NULL);
1279 gdk_gc_set_foreground (gc, &c);
1282 /* Sets the stipple pattern for the specified gc */
1285 set_stipple (GdkGC *gc, GdkBitmap **internal_stipple, GdkBitmap *stipple, int reconfigure)
1287 if (*internal_stipple && !reconfigure)
1288 g_object_unref (*internal_stipple);
1290 *internal_stipple = stipple;
1291 if (stipple && !reconfigure)
1292 g_object_ref (stipple);
1296 gdk_gc_set_stipple (gc, stipple);
1297 gdk_gc_set_fill (gc, GDK_STIPPLED);
1299 gdk_gc_set_fill (gc, GDK_SOLID);
1303 /* Creates private Gdk struct, if not present */
1304 /* We cannot do it during ::init, as we have to know canvas */
1307 gcbp_ensure_gdk (GnomeCanvasShape * shape)
1309 g_assert (!((GnomeCanvasItem *) shape)->canvas->aa);
1311 if (!shape->priv->gdk) {
1312 GnomeCanvasShapePrivGdk * gdk;
1314 gdk = g_new (GnomeCanvasShapePrivGdk, 1);
1316 gdk->fill_pixel = get_pixel_from_rgba ((GnomeCanvasItem *) shape, shape->priv->fill_rgba);
1317 gdk->outline_pixel = get_pixel_from_rgba ((GnomeCanvasItem *) shape, shape->priv->outline_rgba);
1319 gdk->fill_stipple = NULL;
1320 gdk->outline_stipple = NULL;
1322 gdk->fill_gc = NULL;
1323 gdk->outline_gc = NULL;
1325 gdk->len_points = 0;
1326 gdk->num_points = 0;
1328 gdk->closed_paths = NULL;
1329 gdk->open_paths = NULL;
1333 shape->priv->gdk = gdk;
1337 /* Destroy private Gdk struct */
1338 /* It is here, to make ::destroy implementation shorter :) */
1341 gcbp_destroy_gdk (GnomeCanvasShape * shape)
1343 GnomeCanvasShapePrivGdk * gdk;
1345 g_assert (!((GnomeCanvasItem *)shape)->canvas->aa);
1347 gdk = shape->priv->gdk;
1350 g_assert (!gdk->fill_gc);
1351 g_assert (!gdk->outline_gc);
1353 if (gdk->fill_stipple)
1354 g_object_unref (gdk->fill_stipple);
1356 if (gdk->outline_stipple)
1357 g_object_unref (gdk->outline_stipple);
1360 g_free (gdk->points);
1362 while (gdk->closed_paths)
1363 gdk->closed_paths = g_slist_remove (gdk->closed_paths, gdk->closed_paths->data);
1364 while (gdk->open_paths)
1365 gdk->open_paths = g_slist_remove (gdk->open_paths, gdk->open_paths->data);
1368 gcbp_draw_ctx_unref (gdk->ctx);
1372 shape->priv->gdk = NULL;
1377 * Ensure, that per-canvas Ctx struct is present and bitmaps are
1378 * big enough, to mask full redraw area. Ctx is refcounted and
1379 * defined as "BpathDrawCtx" data member on parent canvas
1383 gcbp_ensure_mask (GnomeCanvasShape * shape, gint width, gint height)
1385 GnomeCanvasShapePrivGdk * gdk;
1388 gdk = shape->priv->gdk;
1389 g_assert (gdk != NULL);
1393 /* Ctx is not yet defined for us */
1395 GnomeCanvas * canvas;
1397 canvas = GNOME_CANVAS_ITEM (shape)->canvas;
1399 ctx = g_object_get_data (G_OBJECT (canvas), "BpathDrawCtx");
1402 /* Ctx is not defined for parent canvas yet */
1404 ctx = g_new (GCBPDrawCtx, 1);
1407 ctx->canvas = canvas;
1414 ctx->clear_gc = NULL;
1417 g_object_set_data (G_OBJECT (canvas), "BpathDrawCtx", ctx);
1427 /* Now we are sure, that ctx is present and properly refcounted */
1429 if ((width > ctx->width) || (height > ctx->height)) {
1430 /* Ctx is too small */
1434 window = ((GtkWidget *) (((GnomeCanvasItem *) shape)->canvas))->window;
1436 if (ctx->clear_gc) g_object_unref (ctx->clear_gc);
1437 if (ctx->xor_gc) g_object_unref (ctx->xor_gc);
1438 if (ctx->mask) g_object_unref (ctx->mask);
1439 if (ctx->clip) g_object_unref (ctx->clip);
1441 ctx->mask = gdk_pixmap_new (window, width, height, 1);
1444 ctx->clear_gc = gdk_gc_new (ctx->mask);
1445 gdk_gc_set_function (ctx->clear_gc, GDK_CLEAR);
1447 ctx->xor_gc = gdk_gc_new (ctx->mask);
1448 gdk_gc_set_function (ctx->xor_gc, GDK_INVERT);
1452 /* It is cleaner to have it here, not in parent function */
1455 gcbp_draw_ctx_unref (GCBPDrawCtx * ctx)
1457 if (--ctx->refcount < 1) {
1459 g_object_unref (ctx->clear_gc);
1461 g_object_unref (ctx->xor_gc);
1464 g_object_unref (ctx->mask);
1466 g_object_unref (ctx->clip);
1468 g_object_set_data (G_OBJECT (ctx->canvas), "BpathDrawCtx", NULL);
1474 gnome_canvas_shape_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1476 GnomeCanvasShape * shape;
1477 GnomeCanvasShapePriv * priv;
1481 shape = GNOME_CANVAS_SHAPE (item);
1490 if (priv->outline_set && priv->path && !gnome_canvas_path_def_is_empty (priv->path)) {
1496 if (priv->width_pixels) {
1497 width = priv->width;
1499 width = priv->width * priv->scale;
1502 if (width < 0.5) width = 0.5;
1504 /* Render full path until vpath */
1506 vpath = art_bez_path_to_vec (gnome_canvas_path_def_bpath (priv->path), 0.1);
1508 /* If dashed, apply dash */
1510 if (priv->dash.dash != NULL)
1512 ArtVpath *old = vpath;
1514 vpath = art_vpath_dash (old, &priv->dash);
1518 /* Stroke vpath to SVP */
1520 svp = art_svp_vpath_stroke (vpath,
1521 gnome_canvas_join_gdk_to_art (priv->join),
1522 gnome_canvas_cap_gdk_to_art (priv->cap),
1527 art_drect_svp (&bbox, svp);
1529 } else if ((priv->fill_set) && (priv->path) && (gnome_canvas_path_def_any_closed (priv->path))) {
1530 GnomeCanvasPathDef *cpath;
1535 /* Get closed part of path */
1536 cpath = gnome_canvas_path_def_closed_parts (shape->priv->path);
1537 /* Render, until SVP */
1538 vpath = art_bez_path_to_vec (gnome_canvas_path_def_bpath (cpath), 0.1);
1539 gnome_canvas_path_def_unref (cpath);
1541 svp = art_svp_from_vpath (vpath);
1544 swr = art_svp_writer_rewind_new (shape->priv->wind);
1545 art_svp_intersector (svp, swr);
1547 svp2 = art_svp_writer_rewind_reap (swr);
1550 art_drect_svp (&bbox, svp2);
1551 art_svp_free (svp2);