#define GNOME_CANVAS_CLIPGROUP_C /* Clipping group for GnomeCanvas * * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties. * * Copyright (C) 1998,1999 The Free Software Foundation * * Author: * Lauris Kaplinski */ /* These includes are set up for standalone compile. If/when this codebase is integrated into libgnomeui, the includes will need to change. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gnome-canvas.h" #include "gnome-canvas-util.h" #include "gnome-canvas-clipgroup.h" enum { PROP_0, PROP_PATH, PROP_WIND }; static void gnome_canvas_clipgroup_class_init (GnomeCanvasClipgroupClass *klass); static void gnome_canvas_clipgroup_init (GnomeCanvasClipgroup *clipgroup); static void gnome_canvas_clipgroup_destroy (GnomeCanvasItem *object); static void gnome_canvas_clipgroup_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void gnome_canvas_clipgroup_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec); static void gnome_canvas_clipgroup_update (GnomeCanvasItem *item, gdouble *affine, ArtSVP *clip_path, gint flags); /* * Generic clipping stuff * * This is somewhat slow and memory-hungry - we add extra * composition, extra SVP render and allocate 65536 * bytes for each clip level. It could be done more * efficently per-object basis - but to make clipping * universal, there is no alternative to double * buffering (although it should be done into RGBA * buffer by other method than ::render to make global * opacity possible). * Using art-render could possibly optimize that a bit, * although I am not sure. */ static GnomeCanvasGroupClass *parent_class; GType gnome_canvas_clipgroup_get_type (void) { static GType clipgroup_type; if (!clipgroup_type) { const GTypeInfo object_info = { sizeof (GnomeCanvasClipgroupClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gnome_canvas_clipgroup_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (GnomeCanvasClipgroup), 0, /* n_preallocs */ (GInstanceInitFunc) gnome_canvas_clipgroup_init, NULL /* value_table */ }; clipgroup_type = g_type_register_static (GNOME_TYPE_CANVAS_GROUP, "GnomeCanvasClipgroup", &object_info, 0); } return clipgroup_type; } static void gnome_canvas_clipgroup_class_init (GnomeCanvasClipgroupClass *klass) { GObjectClass *gobject_class; GnomeCanvasItemClass *item_class; gobject_class = (GObjectClass *) klass; item_class = (GnomeCanvasItemClass *) klass; parent_class = g_type_class_ref (GNOME_TYPE_CANVAS_GROUP); gobject_class->set_property = gnome_canvas_clipgroup_set_property; gobject_class->get_property = gnome_canvas_clipgroup_get_property; item_class->destroy = gnome_canvas_clipgroup_destroy; item_class->update = gnome_canvas_clipgroup_update; g_object_class_install_property (gobject_class, PROP_PATH, g_param_spec_pointer ("path", NULL, NULL, (G_PARAM_READABLE | G_PARAM_WRITABLE))); g_object_class_install_property (gobject_class, PROP_WIND, g_param_spec_uint ("wind", NULL, NULL, 0, G_MAXUINT, 0, (G_PARAM_READABLE | G_PARAM_WRITABLE))); } static void gnome_canvas_clipgroup_init (GnomeCanvasClipgroup *clipgroup) { clipgroup->path = NULL; clipgroup->wind = ART_WIND_RULE_NONZERO; /* default winding rule */ clipgroup->svp = NULL; } static void gnome_canvas_clipgroup_destroy (GnomeCanvasItem *object) { GnomeCanvasClipgroup *clipgroup; g_return_if_fail (object != NULL); g_return_if_fail (GNOME_IS_CANVAS_CLIPGROUP (object)); clipgroup = GNOME_CANVAS_CLIPGROUP (object); if (clipgroup->path) { gnome_canvas_path_def_unref (clipgroup->path); clipgroup->path = NULL; } if (clipgroup->svp) { art_svp_free (clipgroup->svp); clipgroup->svp = NULL; } if (GNOME_CANVAS_ITEM_CLASS (parent_class)->destroy) GNOME_CANVAS_ITEM_CLASS (parent_class)->destroy (object); } static void gnome_canvas_clipgroup_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { GnomeCanvasItem *item; GnomeCanvasClipgroup *cgroup; GnomeCanvasPathDef *gpp; item = GNOME_CANVAS_ITEM (object); cgroup = GNOME_CANVAS_CLIPGROUP (object); switch (param_id) { case PROP_PATH: gpp = g_value_get_pointer (value); if (cgroup->path) { gnome_canvas_path_def_unref (cgroup->path); cgroup->path = NULL; } if (gpp != NULL) { cgroup->path = gnome_canvas_path_def_closed_parts (gpp); } gnome_canvas_item_request_update (item); break; case PROP_WIND: cgroup->wind = g_value_get_uint (value); gnome_canvas_item_request_update (item); break; default: break; } } static void gnome_canvas_clipgroup_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { GnomeCanvasClipgroup * cgroup; cgroup = GNOME_CANVAS_CLIPGROUP (object); switch (param_id) { case PROP_PATH: g_value_set_pointer (value, cgroup->path); break; case PROP_WIND: g_value_set_uint (value, cgroup->wind); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } static void gnome_canvas_clipgroup_update (GnomeCanvasItem *item, gdouble *affine, ArtSVP *clip_path, gint flags) { GnomeCanvasClipgroup *clipgroup; ArtSvpWriter *swr; ArtBpath *bp; ArtBpath *bpath; ArtVpath *vpath; ArtSVP *svp, *svp1, *svp2; clipgroup = GNOME_CANVAS_CLIPGROUP (item); if (clipgroup->svp) { art_svp_free (clipgroup->svp); clipgroup->svp = NULL; } if (clipgroup->path) { bp = gnome_canvas_path_def_bpath (clipgroup->path); bpath = art_bpath_affine_transform (bp, affine); vpath = art_bez_path_to_vec (bpath, 0.25); art_free (bpath); svp1 = art_svp_from_vpath (vpath); art_free (vpath); swr = art_svp_writer_rewind_new (clipgroup->wind); art_svp_intersector (svp1, swr); svp2 = art_svp_writer_rewind_reap (swr); art_svp_free (svp1); if (clip_path != NULL) { svp = art_svp_intersect (svp2, clip_path); art_svp_free (svp2); } else { svp = svp2; } clipgroup->svp = svp; } if (GNOME_CANVAS_ITEM_CLASS (parent_class)->update) (GNOME_CANVAS_ITEM_CLASS (parent_class)->update) (item, affine, NULL, flags); if (clipgroup->svp) { ArtDRect cbox; art_drect_svp (&cbox, clipgroup->svp); item->x1 = MAX (item->x1, cbox.x0 - 1.0); item->y1 = MAX (item->y1, cbox.y0 - 1.0); item->x2 = MIN (item->x2, cbox.x1 + 1.0); item->y2 = MIN (item->y2, cbox.y1 + 1.0); } }