remove unused and useless "src" argument for a number of Region property modifying...
[ardour.git] / libs / gnomecanvas / libgnomecanvas / gnome-canvas-shape.c
1 /* Generic bezier shape item for GnomeCanvasWidget.  Most code taken
2  * from gnome-canvas-bpath but made into a shape item.
3  *
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.
7  *
8  * Copyright (C) 1998,1999 The Free Software Foundation
9  *
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>
16  */
17
18 /* These includes are set up for standalone compile. If/when this codebase
19    is integrated into libgnomeui, the includes will need to change. */
20
21 #include <math.h>
22 #include <string.h>
23
24 #include <gtk/gtk.h>
25 #include "gnome-canvas.h"
26 #include "gnome-canvas-util.h"
27
28 #include "gnome-canvas-shape.h"
29 #include "gnome-canvas-shape-private.h"
30 #include "gnome-canvas-path-def.h"
31
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>
43
44 enum {
45         PROP_0,
46         PROP_FILL_COLOR,
47         PROP_FILL_COLOR_GDK,
48         PROP_FILL_COLOR_RGBA,
49         PROP_OUTLINE_COLOR,
50         PROP_OUTLINE_COLOR_GDK,
51         PROP_OUTLINE_COLOR_RGBA,
52         PROP_FILL_STIPPLE,
53         PROP_OUTLINE_STIPPLE,
54         PROP_WIDTH_PIXELS,
55         PROP_WIDTH_UNITS,
56         PROP_CAP_STYLE,
57         PROP_JOIN_STYLE,
58         PROP_WIND,
59         PROP_MITERLIMIT,
60         PROP_DASH
61 };
62
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,
67                                              guint                  param_id,
68                                              const GValue          *value,
69                                              GParamSpec            *pspec);
70 static void gnome_canvas_shape_get_property (GObject               *object,
71                                              guint                  param_id,
72                                              GValue                *value,
73                                              GParamSpec            *pspec);
74
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);
85
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);
94
95 static GnomeCanvasItemClass *parent_class;
96
97 GType
98 gnome_canvas_shape_get_type (void)
99 {
100         static GType shape_type;
101
102         if (!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),
111                         0,                      /* n_preallocs */
112                         (GInstanceInitFunc) gnome_canvas_shape_init,
113                         NULL                    /* value_table */
114                 };
115
116                 shape_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasShape",
117                                                      &object_info, 0);
118         }
119
120         return shape_type;
121 }
122
123 static void
124 gnome_canvas_shape_class_init (GnomeCanvasShapeClass *class)
125 {
126         GObjectClass         *gobject_class;
127         GtkObjectClass       *object_class;
128         GnomeCanvasItemClass *item_class;
129
130         gobject_class = (GObjectClass *) class;
131         object_class = (GtkObjectClass *) class;
132         item_class = (GnomeCanvasItemClass *) class;
133
134         parent_class = g_type_class_peek_parent (class);
135
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 */
139
140         gobject_class->set_property = gnome_canvas_shape_set_property;
141         gobject_class->get_property = gnome_canvas_shape_get_property;
142
143
144
145         g_object_class_install_property (gobject_class,
146                                          PROP_FILL_COLOR,
147                                          g_param_spec_string ("fill_color", NULL, NULL,
148                                                               NULL,
149                                                               (G_PARAM_WRITABLE)));
150         g_object_class_install_property (gobject_class,
151                                          PROP_FILL_COLOR_GDK,
152                                          g_param_spec_boxed ("fill_color_gdk", NULL, NULL,
153                                                              GDK_TYPE_COLOR,
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,
158                                                             0, G_MAXUINT, 0,
159                                                             (G_PARAM_READABLE | G_PARAM_WRITABLE)));
160         g_object_class_install_property (gobject_class,
161                                          PROP_OUTLINE_COLOR,
162                                          g_param_spec_string ("outline_color", NULL, NULL,
163                                                               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,
168                                                              GDK_TYPE_COLOR,
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,
173                                                             0, G_MAXUINT, 0,
174                                                             (G_PARAM_READABLE | G_PARAM_WRITABLE)));
175         g_object_class_install_property (gobject_class,
176                                          PROP_FILL_STIPPLE,
177                                          g_param_spec_object ("fill_stipple", NULL, NULL,
178                                                               GDK_TYPE_DRAWABLE,
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,
183                                                               GDK_TYPE_DRAWABLE,
184                                                               (G_PARAM_READABLE | G_PARAM_WRITABLE)));
185         g_object_class_install_property (gobject_class,
186                                          PROP_WIDTH_PIXELS,
187                                          g_param_spec_uint ("width_pixels", NULL, NULL,
188                                                             0, G_MAXUINT, 0,
189                                                             (G_PARAM_READABLE | G_PARAM_WRITABLE)));
190         g_object_class_install_property (gobject_class,
191                                          PROP_WIDTH_UNITS,
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,
196                                          PROP_CAP_STYLE,
197                                          g_param_spec_enum ("cap_style", NULL, NULL,
198                                                             GDK_TYPE_CAP_STYLE,
199                                                             GDK_CAP_BUTT,
200                                                             (G_PARAM_READABLE | G_PARAM_WRITABLE)));
201         g_object_class_install_property (gobject_class,
202                                          PROP_JOIN_STYLE,
203                                          g_param_spec_enum ("join_style", NULL, NULL,
204                                                             GDK_TYPE_JOIN_STYLE,
205                                                             GDK_JOIN_MITER,
206                                                             (G_PARAM_READABLE | G_PARAM_WRITABLE)));
207         g_object_class_install_property (gobject_class,
208                                          PROP_WIND,
209                                          g_param_spec_uint ("wind", NULL, NULL,
210                                                             0, G_MAXUINT, 0,
211                                                             (G_PARAM_READABLE | G_PARAM_WRITABLE)));
212         g_object_class_install_property (gobject_class,
213                                          PROP_MITERLIMIT,
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,
218                                          PROP_DASH,
219                                          g_param_spec_pointer ("dash", NULL, NULL,
220                                                                (G_PARAM_READABLE | G_PARAM_WRITABLE)));
221
222         object_class->destroy = gnome_canvas_shape_destroy;
223
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;
231 }
232
233 static void
234 gnome_canvas_shape_init (GnomeCanvasShape *shape)
235 {
236         shape->priv = g_new (GnomeCanvasShapePriv, 1);
237
238         shape->priv->path = NULL;
239
240         shape->priv->scale = 1.0;
241
242         shape->priv->fill_set = FALSE;
243         shape->priv->outline_set = FALSE;
244         shape->priv->width_pixels = FALSE;
245
246         shape->priv->width = 1.0;
247
248         shape->priv->fill_rgba = 0x0000003f;
249         shape->priv->outline_rgba = 0x0000007f;
250
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 */
255
256         shape->priv->dash.n_dash = 0;
257         shape->priv->dash.dash = NULL;
258
259         shape->priv->fill_svp = NULL;
260         shape->priv->outline_svp = NULL;
261
262         shape->priv->gdk = NULL;
263 }
264
265 static void
266 gnome_canvas_shape_destroy (GtkObject *object)
267 {
268         GnomeCanvasShape *shape;
269         GnomeCanvasShapePriv *priv;
270
271         g_return_if_fail (object != NULL);
272         g_return_if_fail (GNOME_IS_CANVAS_SHAPE (object));
273
274         shape = GNOME_CANVAS_SHAPE (object);
275
276         if (shape->priv) {
277                 priv = shape->priv;
278                 if (priv->gdk) gcbp_destroy_gdk (shape);
279
280                 if (priv->path) gnome_canvas_path_def_unref (priv->path);
281
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);
285                 
286                 g_free (shape->priv);
287                 shape->priv = NULL;
288         }
289
290         if (GTK_OBJECT_CLASS (parent_class)->destroy)
291                 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
292 }
293
294 /**
295  * gnome_canvas_shape_set_path_def:
296  * @shape: a GnomeCanvasShape
297  * @def: a GnomeCanvasPathDef 
298  *
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
302  * update queue.
303  */
304  
305 void
306 gnome_canvas_shape_set_path_def (GnomeCanvasShape *shape, GnomeCanvasPathDef *def) 
307 {
308         GnomeCanvasShapePriv *priv;
309
310         g_return_if_fail (shape != NULL);
311         g_return_if_fail (GNOME_IS_CANVAS_SHAPE (shape));
312
313         priv = shape->priv;
314
315         if (priv->path) {
316                 gnome_canvas_path_def_unref (priv->path);
317                 priv->path = NULL;
318         }
319
320         if (def) {
321                 priv->path = gnome_canvas_path_def_duplicate (def);
322         }
323 }
324
325 static void
326 gnome_canvas_shape_set_property (GObject      *object,
327                                  guint         param_id,
328                                  const GValue *value,
329                                  GParamSpec   *pspec)
330 {
331         GnomeCanvasItem         *item;
332         GnomeCanvasShape        *shape;
333         GnomeCanvasShapePriv    *priv;
334         GnomeCanvasShapePrivGdk *gdk;
335         GdkColor                 color;
336         GdkColor                *colorptr;
337         ArtVpathDash            *dash;
338
339         item = GNOME_CANVAS_ITEM (object);
340         shape = GNOME_CANVAS_SHAPE (object);
341         priv = shape->priv;
342
343         if (!item->canvas->aa) {
344                 gcbp_ensure_gdk (shape);
345                 gdk = priv->gdk;
346         } else {
347                 gdk = NULL;
348         }
349
350         switch (param_id) {
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;
358                 else
359                         break;
360
361                 gnome_canvas_item_request_update (item);
362                 break;
363
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);
369                         if (gdk) {
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;
374                         }
375                 } else if (priv->fill_set)
376                         priv->fill_set = FALSE;
377                 else
378                         break;
379
380                 gnome_canvas_item_request_update (item);
381                 break;
382
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);
387
388                 gnome_canvas_item_request_update (item);
389                 break;
390
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;
398                 else
399                         break;
400
401                 gnome_canvas_item_request_update (item);
402                 break;
403
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);
409                         if (gdk) {
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;
414                         }
415                 } else if (priv->outline_set)
416                         priv->outline_set = FALSE;
417                 else
418                         break;
419
420                 gnome_canvas_item_request_update (item);
421                 break;
422
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);
427
428                 gnome_canvas_item_request_update (item);
429                 break;
430
431         case PROP_FILL_STIPPLE:
432                 if (gdk) {
433                         set_stipple (gdk->fill_gc, &gdk->fill_stipple, (GdkBitmap*) g_value_get_object (value), FALSE);
434                         gnome_canvas_item_request_update (item);
435                 }
436                 break;
437
438         case PROP_OUTLINE_STIPPLE:
439                 if (gdk) {
440                         set_stipple (gdk->outline_gc, &gdk->outline_stipple, (GdkBitmap*) g_value_get_object (value), FALSE);
441                         gnome_canvas_item_request_update (item);
442                 }
443                 break;
444
445         case PROP_WIDTH_PIXELS:
446                 priv->width = g_value_get_uint (value);
447                 priv->width_pixels = TRUE;
448
449                 gnome_canvas_item_request_update (item);
450                 break;
451
452         case PROP_WIDTH_UNITS:
453                 priv->width = fabs (g_value_get_double (value));
454                 priv->width_pixels = FALSE;
455
456                 gnome_canvas_item_request_update (item);
457                 break;
458
459         case PROP_WIND:
460                 priv->wind = g_value_get_uint (value);
461                 gnome_canvas_item_request_update (item);
462                 break;
463
464         case PROP_CAP_STYLE:
465                 priv->cap = g_value_get_enum (value);
466                 gnome_canvas_item_request_update (item);
467                 break;
468
469         case PROP_JOIN_STYLE:
470                 priv->join = g_value_get_enum (value);
471                 gnome_canvas_item_request_update (item);
472                 break;
473         
474         case PROP_MITERLIMIT:
475                 priv->miterlimit = g_value_get_double (value);
476                 gnome_canvas_item_request_update (item);
477                 break;
478
479         case PROP_DASH:
480                 dash = g_value_get_pointer (value);
481                 if (priv->dash.dash) g_free (priv->dash.dash);
482                 priv->dash.dash = NULL;
483
484                 if (dash) {
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));
490                         }
491                 }
492                 gnome_canvas_item_request_update (item);
493                 break;
494         default:
495                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
496                 break;
497         }
498 }
499
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 
502  * method.
503  */
504
505 static void
506 get_color_value (GnomeCanvasShape *shape, gulong pixel, GValue *value)
507 {
508         GnomeCanvas *canvas = GNOME_CANVAS_ITEM (shape)->canvas;
509         GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
510         GdkColor color;
511
512         gdk_colormap_query_color (colormap, pixel, &color);
513         g_value_set_boxed (value, &color);
514 }
515
516 /**
517  * gnome_canvas_shape_get_path_def:
518  * @shape: a GnomeCanvasShape
519  *
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
523  * it returns NULL.
524  *
525  * Returns: a #GnomeCanvasPathDef or NULL if none is set for the shape.
526  */
527  
528 GnomeCanvasPathDef *
529 gnome_canvas_shape_get_path_def (GnomeCanvasShape *shape)
530 {
531         GnomeCanvasShapePriv *priv;
532         
533         g_return_val_if_fail (shape != NULL, NULL);
534         g_return_val_if_fail (GNOME_IS_CANVAS_SHAPE (shape), NULL);
535
536         priv = shape->priv;
537
538         if (priv->path) {
539                 gnome_canvas_path_def_ref (priv->path);
540                 return priv->path;
541         }
542         
543         return NULL;
544 }
545
546 static void
547 gnome_canvas_shape_get_property (GObject     *object,
548                                  guint        param_id,
549                                  GValue      *value,
550                                  GParamSpec  *pspec)
551 {
552         GnomeCanvasItem         *item = GNOME_CANVAS_ITEM (object);
553         GnomeCanvasShape        *shape = GNOME_CANVAS_SHAPE (object);
554         GnomeCanvasShapePriv    *priv = shape->priv;
555         GnomeCanvasShapePrivGdk *gdk;
556
557         if (!item->canvas->aa) {
558                 gcbp_ensure_gdk (shape);
559                 gdk = priv->gdk;
560         }
561         else {
562                 gdk = NULL;
563         }
564
565         switch (param_id) {
566         case PROP_FILL_COLOR_GDK:
567                 if (gdk) {
568                         get_color_value (shape, gdk->fill_pixel, value);
569                 } else {
570                         get_color_value (shape, 0, value);
571                 }
572                 break;
573                 
574         case PROP_OUTLINE_COLOR_GDK:
575                 if (gdk) {
576                         get_color_value (shape, gdk->outline_pixel, value);
577                 } else {
578                         get_color_value (shape, 0, value);
579                 }
580                 break;
581
582         case PROP_FILL_COLOR_RGBA:
583                 g_value_set_uint (value, priv->fill_rgba);
584                 break;
585
586         case PROP_OUTLINE_COLOR_RGBA:
587                 g_value_set_uint (value, priv->outline_rgba);
588                 break;
589
590         case PROP_FILL_STIPPLE:
591                 if (gdk) {
592                         g_value_set_object (value, gdk->fill_stipple);
593                 } else {
594                         g_value_set_object (value, NULL);
595                 }
596                 break;
597
598         case PROP_OUTLINE_STIPPLE:
599                 if (gdk) {
600                         g_value_set_object (value, gdk->outline_stipple);
601                 } else {
602                         g_value_set_object (value, NULL);
603                 }
604                 break;
605
606         case PROP_WIND:
607                 g_value_set_uint (value, priv->wind);
608                 break;
609
610         case PROP_CAP_STYLE:
611                 g_value_set_enum (value, priv->cap);
612                 break;
613
614         case PROP_JOIN_STYLE:
615                 g_value_set_enum (value, priv->join);
616                 break;
617
618         case PROP_WIDTH_PIXELS:
619                 g_value_set_uint (value, priv->width);
620                 break;
621
622         case PROP_WIDTH_UNITS:
623                 g_value_set_double (value, priv->width);
624                 break;
625
626         case PROP_MITERLIMIT:
627                 g_value_set_double (value, priv->miterlimit);
628                 break;
629
630         case PROP_DASH:
631                 g_value_set_pointer (value, &priv->dash);
632                 break;
633                 
634         default:
635                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
636                 break;
637         }
638 }
639
640 static void
641 gnome_canvas_shape_realize (GnomeCanvasItem *item)
642 {
643         GnomeCanvasShape *shape;
644
645         shape = GNOME_CANVAS_SHAPE (item);
646
647         if (parent_class->realize)
648                 (* parent_class->realize) (item);
649
650         if (!item->canvas->aa) {
651                 gcbp_ensure_gdk (shape);
652
653                 g_assert(item->canvas->layout.bin_window != NULL);
654
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);
657         }
658 }
659
660 static void
661 gnome_canvas_shape_unrealize (GnomeCanvasItem *item)
662 {
663         GnomeCanvasShape *shape;
664
665         shape = GNOME_CANVAS_SHAPE (item);
666
667         if (!item->canvas->aa) {
668                 g_assert (shape->priv->gdk != NULL);
669
670                 g_object_unref (shape->priv->gdk->fill_gc);
671                 shape->priv->gdk->fill_gc = NULL;
672
673                 g_object_unref (shape->priv->gdk->outline_gc);
674                 shape->priv->gdk->outline_gc = NULL;
675         }
676
677         if (parent_class->unrealize)
678                 (* parent_class->unrealize) (item);
679 }
680
681 static void
682 gnome_canvas_shape_render (GnomeCanvasItem *item,
683                              GnomeCanvasBuf *buf)
684 {
685         GnomeCanvasShape *shape;
686
687         shape = GNOME_CANVAS_SHAPE (item);
688
689         if (shape->priv->fill_svp != NULL)
690                 gnome_canvas_render_svp (buf,
691                         shape->priv->fill_svp,
692                         shape->priv->fill_rgba);
693
694         if (shape->priv->outline_svp != NULL)
695                 gnome_canvas_render_svp (buf,
696                         shape->priv->outline_svp,
697                         shape->priv->outline_rgba);
698 }
699
700 static void
701 gnome_canvas_shape_draw (GnomeCanvasItem *item,
702         GdkDrawable *drawable,
703         int x,
704         int y,
705         int width,
706         int height)
707 {
708         static GdkPoint * dpoints = NULL;
709         static gint num_dpoints = 0;
710
711         GnomeCanvasShape * shape;
712         GnomeCanvasShapePriv * priv;
713         GnomeCanvasShapePrivGdk * gdk;
714         gint i, pos, len;
715         GSList * l;
716
717         shape = GNOME_CANVAS_SHAPE (item);
718         priv = shape->priv;
719
720         /* We have to be realized, so gdk struct should exist! */
721
722         gdk = shape->priv->gdk;
723         g_assert (gdk != NULL);
724
725         /* Build temporary point list, translated by -x, -y */
726
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;
733         }
734
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;
738         }
739
740         if (priv->fill_set) {
741
742                 /* Ensure, that we have mask and it is big enough */
743
744                 gcbp_ensure_mask (shape, width, height);
745
746                 /* Clear mask */
747
748                 gdk_draw_rectangle (gdk->ctx->mask,
749                         gdk->ctx->clear_gc,
750                         TRUE,
751                         0, 0,
752                         width, height);
753
754                 /* Draw subpaths, using XOR gc */
755
756                 pos = 0;
757
758                 for (l = gdk->closed_paths; l != NULL; l = l->next) {
759                         len = GPOINTER_TO_INT (l->data);
760
761                         gdk_draw_polygon (gdk->ctx->mask,
762                                 gdk->ctx->xor_gc,
763                                 TRUE,
764                                 &dpoints[pos],
765                                 len);
766
767                         pos += len;
768                 }
769
770                 /* Set bitmap to clipping mask */
771
772                 gdk_gc_set_clip_mask (gdk->fill_gc, gdk->ctx->mask);
773
774                 /* Stipple offset */
775
776                 if (gdk->fill_stipple) gnome_canvas_set_stipple_origin (item->canvas, gdk->fill_gc);
777
778                 /* Draw clipped rect to drawable */
779
780                 gdk_draw_rectangle (drawable,
781                         gdk->fill_gc,
782                         TRUE,
783                         0, 0,
784                         width, height);
785         }
786
787         if (priv->outline_set) {
788
789                 /* Stipple offset */
790
791                 if (gdk->outline_stipple) gnome_canvas_set_stipple_origin (item->canvas, gdk->outline_gc);
792                 /* Draw subpaths */
793
794                 pos = 0;
795
796                 for (l = gdk->closed_paths; l != NULL; l = l->next) {
797                         len = GPOINTER_TO_INT (l->data);
798
799                         gdk_draw_polygon (drawable,
800                                           gdk->outline_gc,
801                                           FALSE,
802                                           &dpoints[pos],
803                                           len);
804
805                         pos += len;
806                 }
807
808                 for (l = gdk->open_paths; l != NULL; l = l->next) {
809                         len = GPOINTER_TO_INT (l->data);
810
811                         gdk_draw_lines (drawable,
812                                         gdk->outline_gc,
813                                         &dpoints[pos],
814                                         len);
815
816                         pos += len;
817                 }
818         }
819 }
820
821 #define GDK_POINTS_BLOCK 32
822
823 static void
824 gnome_canvas_shape_ensure_gdk_points (GnomeCanvasShapePrivGdk *gdk, gint num)
825 {
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);
829         }
830 }
831
832 static void
833 gnome_canvas_shape_update_gdk (GnomeCanvasShape * shape, double * affine, ArtSVP * clip, int flags)
834 {
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 */
840         
841         g_assert (!((GnomeCanvasItem *) shape)->canvas->aa);
842
843         priv = shape->priv;
844         gdk = priv->gdk;
845         g_assert (gdk != NULL);
846
847         if (priv->outline_set) {
848                 GdkLineStyle style;
849
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) {
855                                 width = 1;
856                         }
857                 } else {
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) {
862                                 width = 1;
863                         }
864                 }
865
866                 /* If dashed, set it in GdkGC */
867
868                 if ((shape->priv->dash.dash != NULL) && (shape->priv->dash.n_dash > 0)) {
869                         gint8 * dash_list;
870                         gint i;
871
872                         dash_list = g_new (gint8, shape->priv->dash.n_dash);
873
874                         for (i = 0; i < priv->dash.n_dash; i++) {
875                                 dash_list[i] = (gint8) shape->priv->dash.dash[i];
876                         }
877
878                         gdk_gc_set_dashes (gdk->outline_gc,
879                                 (gint) priv->dash.offset,
880                                 dash_list,
881                                 priv->dash.n_dash);
882
883                         g_free (dash_list);
884
885                         style = GDK_LINE_ON_OFF_DASH;
886                 } else {
887                         style = GDK_LINE_SOLID;
888                 }
889
890                 /* Set line width, cap, join */
891                 if(gdk->outline_gc) {
892                         
893                         gdk_gc_set_line_attributes (gdk->outline_gc,
894                                                     width,
895                                                     style,
896                                                     priv->cap,
897                                                     priv->join);
898                         
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);
902                 }
903         }
904
905         if (priv->fill_set) {
906
907                 /* Colors and stipples */
908                 if(gdk->fill_gc) {
909                         set_gc_foreground (gdk->fill_gc, gdk->fill_pixel);
910                         set_stipple (gdk->fill_gc, &gdk->fill_stipple, gdk->fill_stipple, TRUE);
911                 }
912         }
913
914         /* Now the crazy part */
915
916         /* Free existing GdkPoint array */
917
918         if (gdk->points) {
919                 g_free (gdk->points);
920                 gdk->points = NULL;
921                 gdk->len_points = 0;
922                 gdk->num_points = 0;
923         }
924
925         /* Free subpath lists */
926
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);
929
930         /* Calcualte new GdkPoints array and subpath lists */
931
932         if (priv->path) {
933                 GnomeCanvasPathDef * apath, * cpath, * opath;
934                 ArtBpath * abpath;
935                 GSList * clist, * olist;
936                 gint pos;
937
938 #if 0
939                 /* Allocate array */
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);
943                 /* Transform path */
944 #endif
945
946                 abpath = art_bpath_affine_transform (gnome_canvas_path_def_bpath (priv->path), affine);
947                 apath = gnome_canvas_path_def_new_from_bpath (abpath);
948
949                 /* Split path into open and closed parts */
950
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);
954
955                 /* Split partial paths into subpaths */
956
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);
961
962                 pos = 0;
963
964                 /* Fill GdkPoints and add subpaths to list: closed subpaths */
965
966                 while (clist) {
967                         GnomeCanvasPathDef * path;
968                         ArtBpath * bpath;
969                         ArtVpath * vpath;
970                         gint len, i;
971
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++) ;
976
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);
981
982                                 if (bbox_set) {
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);
987                                 } else {
988                                         bbox_set = TRUE;
989                                         x1 = x2 = gdk->points[pos + i].x;
990                                         y1 = y2 = gdk->points[pos + i].y;
991                                 }
992                         }
993                         gdk->num_points += len;
994
995                         art_free (vpath);
996
997                         if (len > 0) {
998                                 pos += len;
999                                 gdk->closed_paths = g_slist_append (gdk->closed_paths, GINT_TO_POINTER (len));
1000                         }
1001
1002                         gnome_canvas_path_def_unref (path);
1003                         clist = g_slist_remove (clist, clist->data);
1004                 }
1005
1006                 /* Fill GdkPoints and add subpaths to list: open subpaths */
1007
1008                 while (olist) {
1009                         GnomeCanvasPathDef * path;
1010                         ArtBpath * bpath;
1011                         ArtVpath * vpath;
1012                         gint len, i;
1013
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++) ;
1018
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);
1023                                 
1024                                 if (bbox_set) {
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);
1029                                 } else {
1030                                         bbox_set = TRUE;
1031                                         x1 = x2 = gdk->points[pos + i].x;
1032                                         y1 = y2 = gdk->points[pos + i].y;
1033                                 }
1034                         }
1035                         gdk->num_points += len;
1036
1037                         art_free (vpath);
1038
1039                         if (len > 0) {
1040                                 pos += len;
1041                                 gdk->open_paths = g_slist_append (gdk->open_paths, GINT_TO_POINTER (len));
1042                         }
1043
1044                         gnome_canvas_path_def_unref (path);
1045                         olist = g_slist_remove (olist, olist->data);
1046                 }
1047
1048         }
1049
1050         if (bbox_set) {
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 */
1054                                 : ceil (width/2);
1055                         x1 -= stroke_border;
1056                         x2 += stroke_border;
1057                         y1 -= stroke_border;
1058                         y2 += stroke_border;
1059                 }
1060                 
1061                 gnome_canvas_update_bbox (GNOME_CANVAS_ITEM (shape),
1062                                           x1, y1,
1063                                           x2 + 1, y2 + 1);
1064         }
1065         
1066 }
1067
1068 static void
1069 gnome_canvas_shape_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
1070 {
1071         GnomeCanvasShape * shape;
1072         GnomeCanvasShapePriv * priv;
1073         ArtSVP * svp;
1074
1075         shape = GNOME_CANVAS_SHAPE (item);
1076
1077         priv = shape->priv;
1078
1079         /* Common part */
1080         if (parent_class->update) {
1081                 (* parent_class->update) (item, affine, clip_path, flags);
1082         }
1083
1084         /* Outline width */
1085         shape->priv->scale = art_affine_expansion (affine);
1086
1087         /* Reset bbox */
1088         if (item->canvas->aa) {
1089                 gnome_canvas_item_reset_bounds (item);
1090         }
1091         
1092         /* Clipped fill SVP */
1093
1094         if ((priv->fill_set) && (priv->path) && (gnome_canvas_path_def_any_closed (priv->path))) {
1095                 GnomeCanvasPathDef * cpath;
1096                 ArtSvpWriter *swr;
1097                 ArtVpath *vpath;
1098                 ArtBpath *abp;
1099                 ArtSVP *svp2;
1100
1101                 /* Get closed part of path */
1102
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);
1106
1107                 /* Render, until SVP */
1108
1109                 vpath = art_bez_path_to_vec (abp, 0.1);
1110                 art_free (abp);
1111
1112                 svp = art_svp_from_vpath (vpath);
1113                 art_free (vpath);
1114
1115                 swr = art_svp_writer_rewind_new (shape->priv->wind);
1116                 art_svp_intersector (svp, swr);
1117
1118                 svp2 = art_svp_writer_rewind_reap (swr);
1119                 art_svp_free (svp);
1120
1121                 if (item->canvas->aa) {
1122                         /* Update clipped path */
1123                         gnome_canvas_item_update_svp_clip (item,
1124                                                            &shape->priv->fill_svp,
1125                                                            svp2,
1126                                                            clip_path);
1127                 } else {
1128                         if (priv->fill_svp) {
1129                                 art_svp_free (priv->fill_svp);
1130                                 priv->fill_svp = NULL;
1131                         }
1132                         /* No clipping */
1133                         shape->priv->fill_svp = svp2;
1134                 }
1135         }
1136
1137         if (priv->outline_set && priv->path && !gnome_canvas_path_def_is_empty (priv->path)) {
1138                 gdouble width;
1139                 ArtBpath * abp;
1140                 ArtVpath * vpath;
1141
1142                 /* Set linewidth */
1143
1144                 if (priv->width_pixels) {
1145                         width = priv->width;
1146                 } else {
1147                         width = priv->width * priv->scale;
1148                 }
1149                 
1150                 if (width < 0.5) width = 0.5;
1151                 
1152                 /* Render full path until vpath */
1153
1154                 abp = art_bpath_affine_transform (gnome_canvas_path_def_bpath (priv->path), affine);
1155
1156                 vpath = art_bez_path_to_vec (abp, 0.1);
1157                 art_free (abp);
1158
1159                 /* If dashed, apply dash */
1160
1161                 if (priv->dash.dash != NULL)
1162                 {
1163                         ArtVpath *old = vpath;
1164                         
1165                         vpath = art_vpath_dash (old, &priv->dash);
1166                         art_free (old);
1167                 }
1168                 
1169                 /* Stroke vpath to SVP */
1170
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),
1174                                             width,
1175                                             priv->miterlimit,
1176                                             0.25);
1177                 art_free (vpath);
1178
1179                 if (item->canvas->aa) {
1180                         /* Update clipped */
1181                         gnome_canvas_item_update_svp_clip (item, &priv->outline_svp, svp, clip_path);
1182                 } else {
1183                         if (priv->outline_svp) {
1184                                 art_svp_free (priv->outline_svp);
1185                                 priv->outline_svp = NULL;
1186                         }
1187                         /* No clipping (yet) */
1188                         shape->priv->outline_svp = svp;
1189                 }
1190         }
1191
1192         /* Gdk requires additional handling */
1193         
1194         if (!item->canvas->aa) {
1195                 gnome_canvas_shape_update_gdk (shape, affine, clip_path, flags);
1196         }
1197 }
1198
1199 static double
1200 gnome_canvas_shape_point (GnomeCanvasItem *item, double x, double y,
1201                             int cx, int cy, GnomeCanvasItem **actual_item)
1202 {
1203         GnomeCanvasShape *shape;
1204         double dist;
1205         int wind;
1206
1207 #if 0
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);
1212 #endif
1213
1214         shape = GNOME_CANVAS_SHAPE (item);
1215
1216         /* todo: update? */
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;
1221                         return 0.0;
1222                 }
1223                 if ((shape->priv->wind == ART_WIND_RULE_ODDEVEN) && ((wind & 0x1) != 0)) {
1224                         *actual_item = item;
1225                         return 0.0;
1226                 }
1227         }
1228
1229         if (shape->priv->outline_set && shape->priv->outline_svp) {
1230                 wind = art_svp_point_wind (shape->priv->outline_svp, cx, cy);
1231                 if (wind) {
1232                         *actual_item = item;
1233                         return 0.0;
1234                 }
1235         }
1236
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);
1241         } else {
1242                 return 1e12;
1243         }
1244
1245         *actual_item = item;
1246
1247         return dist;
1248 }
1249
1250 /* Helpers */
1251
1252 /* Get 32bit rgba color from GdkColor */
1253
1254 static guint32
1255 get_rgba_from_color (GdkColor * color)
1256 {
1257         return ((color->red & 0xff00) << 16) | ((color->green & 0xff00) << 8) | (color->blue & 0xff00) | 0xff;
1258 }
1259
1260 /* Get Gdk pixel value from 32bit rgba color */
1261
1262 static gulong
1263 get_pixel_from_rgba (GnomeCanvasItem *item, guint32 rgba_color)
1264 {
1265         return gnome_canvas_get_color_pixel (item->canvas, rgba_color);
1266 }
1267
1268 /* Convenience function to set a GC's foreground color to the specified pixel value */
1269
1270 static void
1271 set_gc_foreground (GdkGC *gc, gulong pixel)
1272 {
1273         GdkColor c;
1274
1275         g_assert (gc != NULL);
1276
1277         c.pixel = pixel;
1278
1279         gdk_gc_set_foreground (gc, &c);
1280 }
1281
1282 /* Sets the stipple pattern for the specified gc */
1283
1284 static void
1285 set_stipple (GdkGC *gc, GdkBitmap **internal_stipple, GdkBitmap *stipple, int reconfigure)
1286 {
1287         if (*internal_stipple && !reconfigure)
1288                 g_object_unref (*internal_stipple);
1289
1290         *internal_stipple = stipple;
1291         if (stipple && !reconfigure)
1292                 g_object_ref (stipple);
1293
1294         if (gc) {
1295                 if (stipple) {
1296                         gdk_gc_set_stipple (gc, stipple);
1297                         gdk_gc_set_fill (gc, GDK_STIPPLED);
1298                 } else
1299                         gdk_gc_set_fill (gc, GDK_SOLID);
1300         }
1301 }
1302
1303 /* Creates private Gdk struct, if not present */
1304 /* We cannot do it during ::init, as we have to know canvas */
1305
1306 static void
1307 gcbp_ensure_gdk (GnomeCanvasShape * shape)
1308 {
1309         g_assert (!((GnomeCanvasItem *) shape)->canvas->aa);
1310
1311         if (!shape->priv->gdk) {
1312                 GnomeCanvasShapePrivGdk * gdk;
1313
1314                 gdk = g_new (GnomeCanvasShapePrivGdk, 1);
1315
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);
1318
1319                 gdk->fill_stipple = NULL;
1320                 gdk->outline_stipple = NULL;
1321
1322                 gdk->fill_gc = NULL;
1323                 gdk->outline_gc = NULL;
1324
1325                 gdk->len_points = 0;
1326                 gdk->num_points = 0;
1327                 gdk->points = NULL;
1328                 gdk->closed_paths = NULL;
1329                 gdk->open_paths = NULL;
1330
1331                 gdk->ctx = NULL;
1332
1333                 shape->priv->gdk = gdk;
1334         }
1335 }
1336
1337 /* Destroy private Gdk struct */
1338 /* It is here, to make ::destroy implementation shorter :) */
1339
1340 static void
1341 gcbp_destroy_gdk (GnomeCanvasShape * shape)
1342 {
1343         GnomeCanvasShapePrivGdk * gdk;
1344
1345         g_assert (!((GnomeCanvasItem *)shape)->canvas->aa);
1346
1347         gdk = shape->priv->gdk;
1348
1349         if (gdk) {
1350                 g_assert (!gdk->fill_gc);
1351                 g_assert (!gdk->outline_gc);
1352
1353                 if (gdk->fill_stipple)
1354                         g_object_unref (gdk->fill_stipple);
1355
1356                 if (gdk->outline_stipple)
1357                         g_object_unref (gdk->outline_stipple);
1358
1359                 if (gdk->points)
1360                         g_free (gdk->points);
1361
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);
1366
1367                 if (gdk->ctx)
1368                         gcbp_draw_ctx_unref (gdk->ctx);
1369
1370                 g_free (gdk);
1371
1372                 shape->priv->gdk = NULL;
1373         }
1374 }
1375
1376 /*
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
1380  */
1381
1382 static void
1383 gcbp_ensure_mask (GnomeCanvasShape * shape, gint width, gint height)
1384 {
1385         GnomeCanvasShapePrivGdk * gdk;
1386         GCBPDrawCtx * ctx;
1387
1388         gdk = shape->priv->gdk;
1389         g_assert (gdk != NULL);
1390         ctx = gdk->ctx;
1391
1392         if (!ctx) {
1393                 /* Ctx is not yet defined for us */
1394
1395                 GnomeCanvas * canvas;
1396
1397                 canvas = GNOME_CANVAS_ITEM (shape)->canvas;
1398
1399                 ctx = g_object_get_data (G_OBJECT (canvas), "BpathDrawCtx");
1400
1401                 if (!ctx) {
1402                         /* Ctx is not defined for parent canvas yet */
1403
1404                         ctx = g_new (GCBPDrawCtx, 1);
1405
1406                         ctx->refcount = 1;
1407                         ctx->canvas = canvas;
1408                         ctx->width = 0;
1409                         ctx->height = 0;
1410
1411                         ctx->mask = NULL;
1412                         ctx->clip = NULL;
1413
1414                         ctx->clear_gc = NULL;
1415                         ctx->xor_gc = NULL;
1416
1417                         g_object_set_data (G_OBJECT (canvas), "BpathDrawCtx", ctx);
1418
1419                 } else {
1420                         ctx->refcount++;
1421                 }
1422
1423                 gdk->ctx = ctx;
1424
1425         }
1426
1427         /* Now we are sure, that ctx is present and properly refcounted */
1428
1429         if ((width > ctx->width) || (height > ctx->height)) {
1430                 /* Ctx is too small */
1431
1432                 GdkWindow * window;
1433
1434                 window = ((GtkWidget *) (((GnomeCanvasItem *) shape)->canvas))->window;
1435
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);
1440
1441                 ctx->mask = gdk_pixmap_new (window, width, height, 1);
1442                 ctx->clip = NULL;
1443
1444                 ctx->clear_gc = gdk_gc_new (ctx->mask);
1445                 gdk_gc_set_function (ctx->clear_gc, GDK_CLEAR);
1446
1447                 ctx->xor_gc = gdk_gc_new (ctx->mask);
1448                 gdk_gc_set_function (ctx->xor_gc, GDK_INVERT);
1449         }
1450 }
1451
1452 /* It is cleaner to have it here, not in parent function */
1453
1454 static void
1455 gcbp_draw_ctx_unref (GCBPDrawCtx * ctx)
1456 {
1457         if (--ctx->refcount < 1) {
1458                 if (ctx->clear_gc)
1459                         g_object_unref (ctx->clear_gc);
1460                 if (ctx->xor_gc)
1461                         g_object_unref (ctx->xor_gc);
1462
1463                 if (ctx->mask)
1464                         g_object_unref (ctx->mask);
1465                 if (ctx->clip)
1466                         g_object_unref (ctx->clip);
1467                 
1468                 g_object_set_data (G_OBJECT (ctx->canvas), "BpathDrawCtx", NULL);
1469                 g_free (ctx);
1470         }
1471 }
1472
1473 static void
1474 gnome_canvas_shape_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1475 {
1476         GnomeCanvasShape * shape;
1477         GnomeCanvasShapePriv * priv;
1478         ArtDRect bbox;
1479         ArtSVP * svp;
1480
1481         shape = GNOME_CANVAS_SHAPE (item);
1482
1483         priv = shape->priv;
1484
1485         bbox.x0 = *x1;
1486         bbox.y0 = *y1;
1487         bbox.x1 = *x2;
1488         bbox.y1 = *y2;
1489
1490         if (priv->outline_set && priv->path && !gnome_canvas_path_def_is_empty (priv->path)) {
1491                 gdouble width;
1492                 ArtVpath * vpath;
1493
1494                 /* Set linewidth */
1495
1496                 if (priv->width_pixels) {
1497                         width = priv->width;
1498                 } else {
1499                         width = priv->width * priv->scale;
1500                 }
1501                 
1502                 if (width < 0.5) width = 0.5;
1503                 
1504                 /* Render full path until vpath */
1505
1506                 vpath = art_bez_path_to_vec (gnome_canvas_path_def_bpath (priv->path), 0.1);
1507
1508                 /* If dashed, apply dash */
1509
1510                 if (priv->dash.dash != NULL)
1511                 {
1512                         ArtVpath *old = vpath;
1513                         
1514                         vpath = art_vpath_dash (old, &priv->dash);
1515                         art_free (old);
1516                 }
1517                 
1518                 /* Stroke vpath to SVP */
1519
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),
1523                                             width,
1524                                             priv->miterlimit,
1525                                             0.25);
1526                 art_free (vpath);
1527                 art_drect_svp (&bbox, svp);
1528                 art_svp_free (svp);
1529         } else if ((priv->fill_set) && (priv->path) && (gnome_canvas_path_def_any_closed (priv->path))) {
1530                 GnomeCanvasPathDef *cpath;
1531                 ArtSvpWriter *swr;
1532                 ArtVpath *vpath;
1533                 ArtSVP *svp2;
1534
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);
1540
1541                 svp = art_svp_from_vpath (vpath);
1542                 art_free (vpath);
1543                 
1544                 swr = art_svp_writer_rewind_new (shape->priv->wind);
1545                 art_svp_intersector (svp, swr);
1546                 
1547                 svp2 = art_svp_writer_rewind_reap (swr);
1548                 art_svp_free (svp);
1549   
1550                 art_drect_svp (&bbox, svp2);
1551                 art_svp_free (svp2);
1552         }
1553
1554         *x1 = bbox.x0;
1555         *y1 = bbox.y0;
1556         *x2 = bbox.x1;
1557         *y2 = bbox.y1;
1558 }