diff options
author | Benjamin Otte <otte@redhat.com> | 2010-10-15 07:25:40 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2010-10-30 01:50:00 +0800 |
commit | 24e39b9fb54cad437cc12b24e953be890519d86a (patch) | |
tree | 554da00fae5be782689f20ada6b3259c633663d5 /libgnomecanvas/gnome-canvas-shape.c | |
parent | 9c183ab12ae27089ce972e29aab7000c2edfd466 (diff) | |
download | gsoc2013-evolution-24e39b9fb54cad437cc12b24e953be890519d86a.tar gsoc2013-evolution-24e39b9fb54cad437cc12b24e953be890519d86a.tar.gz gsoc2013-evolution-24e39b9fb54cad437cc12b24e953be890519d86a.tar.bz2 gsoc2013-evolution-24e39b9fb54cad437cc12b24e953be890519d86a.tar.lz gsoc2013-evolution-24e39b9fb54cad437cc12b24e953be890519d86a.tar.xz gsoc2013-evolution-24e39b9fb54cad437cc12b24e953be890519d86a.tar.zst gsoc2013-evolution-24e39b9fb54cad437cc12b24e953be890519d86a.zip |
gnome-canvas: Rewrite GnomeCanvasShape to use Cairo
Dashing properties were commented out in the process. They are not used
inside Evolution.
Diffstat (limited to 'libgnomecanvas/gnome-canvas-shape.c')
-rw-r--r-- | libgnomecanvas/gnome-canvas-shape.c | 1070 |
1 files changed, 175 insertions, 895 deletions
diff --git a/libgnomecanvas/gnome-canvas-shape.c b/libgnomecanvas/gnome-canvas-shape.c index e033add5fe..f99b10b976 100644 --- a/libgnomecanvas/gnome-canvas-shape.c +++ b/libgnomecanvas/gnome-canvas-shape.c @@ -22,24 +22,12 @@ #include <string.h> #include <gtk/gtk.h> +#include <cairo-gobject.h> #include "gnome-canvas.h" #include "gnome-canvas-util.h" #include "gnome-canvas-shape.h" #include "gnome-canvas-shape-private.h" -#include "gnome-canvas-path-def.h" - -#include <libart_lgpl/art_rect.h> -#include <libart_lgpl/art_vpath.h> -#include <libart_lgpl/art_bpath.h> -#include <libart_lgpl/art_vpath_bpath.h> -#include <libart_lgpl/art_svp.h> -#include <libart_lgpl/art_svp_point.h> -#include <libart_lgpl/art_svp_vpath.h> -#include <libart_lgpl/art_vpath_dash.h> -#include <libart_lgpl/art_svp_wind.h> -#include <libart_lgpl/art_svp_intersect.h> -#include <libart_lgpl/art_rect_svp.h> enum { PROP_0, @@ -68,8 +56,6 @@ static void gnome_canvas_shape_get_property (GObject *object, GParamSpec *pspec); static void gnome_canvas_shape_update (GnomeCanvasItem *item, gdouble *affine, ArtSVP *clip_path, gint flags); -static void gnome_canvas_shape_realize (GnomeCanvasItem *item); -static void gnome_canvas_shape_unrealize (GnomeCanvasItem *item); static void gnome_canvas_shape_draw (GnomeCanvasItem *item, GdkDrawable *drawable, gint x, gint y, gint width, gint height); static GnomeCanvasItem *gnome_canvas_shape_point (GnomeCanvasItem *item, gdouble x, gdouble y, @@ -77,14 +63,6 @@ static GnomeCanvasItem *gnome_canvas_shape_point (GnomeCanvasItem *item, gdouble static void gnome_canvas_shape_bounds (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2); -static gulong get_pixel_from_rgba (GnomeCanvasItem *item, guint32 rgba_color); -static guint32 get_rgba_from_color (GdkColor * color); -static void set_gc_foreground (GdkGC *gc, gulong pixel); -static void gcbp_ensure_gdk (GnomeCanvasShape * bpath); -static void gcbp_destroy_gdk (GnomeCanvasShape * bpath); -static void gcbp_ensure_mask (GnomeCanvasShape * bpath, gint width, gint height); -static void gcbp_draw_ctx_unref (GCBPDrawCtx * ctx); - G_DEFINE_TYPE (GnomeCanvasShape, gnome_canvas_shape, GNOME_TYPE_CANVAS_ITEM) static void @@ -96,10 +74,6 @@ gnome_canvas_shape_class_init (GnomeCanvasShapeClass *class) gobject_class = (GObjectClass *) class; item_class = (GnomeCanvasItemClass *) class; - /* when this gets checked into libgnomeui, change the - GTK_TYPE_POINTER to GTK_TYPE_GNOME_CANVAS_SHAPE, and add an - entry to gnome-boxed.defs */ - gobject_class->set_property = gnome_canvas_shape_set_property; gobject_class->get_property = gnome_canvas_shape_get_property; @@ -112,10 +86,10 @@ gnome_canvas_shape_class_init (GnomeCanvasShapeClass *class) PROP_FILL_COLOR_GDK, g_param_spec_boxed ("fill_color_gdk", NULL, NULL, GDK_TYPE_COLOR, - (G_PARAM_READABLE | G_PARAM_WRITABLE))); + G_PARAM_WRITABLE)); g_object_class_install_property (gobject_class, PROP_FILL_COLOR_RGBA, - g_param_spec_uint ("fill_color_rgba", NULL, NULL, + g_param_spec_uint ("fill_rgba", NULL, NULL, 0, G_MAXUINT, 0, (G_PARAM_READABLE | G_PARAM_WRITABLE))); g_object_class_install_property (gobject_class, @@ -127,10 +101,10 @@ gnome_canvas_shape_class_init (GnomeCanvasShapeClass *class) PROP_OUTLINE_COLOR_GDK, g_param_spec_boxed ("outline_color_gdk", NULL, NULL, GDK_TYPE_COLOR, - (G_PARAM_READABLE | G_PARAM_WRITABLE))); + G_PARAM_WRITABLE)); g_object_class_install_property (gobject_class, PROP_OUTLINE_COLOR_RGBA, - g_param_spec_uint ("outline_color_rgba", NULL, NULL, + g_param_spec_uint ("outline_rgba", NULL, NULL, 0, G_MAXUINT, 0, (G_PARAM_READABLE | G_PARAM_WRITABLE))); g_object_class_install_property (gobject_class, @@ -141,34 +115,36 @@ gnome_canvas_shape_class_init (GnomeCanvasShapeClass *class) g_object_class_install_property (gobject_class, PROP_CAP_STYLE, g_param_spec_enum ("cap_style", NULL, NULL, - GDK_TYPE_CAP_STYLE, - GDK_CAP_BUTT, + CAIRO_GOBJECT_TYPE_LINE_CAP, + CAIRO_LINE_CAP_BUTT, (G_PARAM_READABLE | G_PARAM_WRITABLE))); g_object_class_install_property (gobject_class, PROP_JOIN_STYLE, g_param_spec_enum ("join_style", NULL, NULL, - GDK_TYPE_JOIN_STYLE, - GDK_JOIN_MITER, + CAIRO_GOBJECT_TYPE_LINE_JOIN, + CAIRO_LINE_JOIN_MITER, (G_PARAM_READABLE | G_PARAM_WRITABLE))); g_object_class_install_property (gobject_class, PROP_WIND, - g_param_spec_uint ("wind", NULL, NULL, - 0, G_MAXUINT, 0, + g_param_spec_enum ("wind", NULL, NULL, + CAIRO_GOBJECT_TYPE_FILL_RULE, + CAIRO_FILL_RULE_EVEN_ODD, (G_PARAM_READABLE | G_PARAM_WRITABLE))); g_object_class_install_property (gobject_class, PROP_MITERLIMIT, g_param_spec_double ("miterlimit", NULL, NULL, - 0.0, G_MAXDOUBLE, 0.0, + 0.0, G_MAXDOUBLE, 10.43, (G_PARAM_READABLE | G_PARAM_WRITABLE))); +#if 0 + /* XXX: Find a good way to pass dash properties in a property */ g_object_class_install_property (gobject_class, PROP_DASH, g_param_spec_pointer ("dash", NULL, NULL, (G_PARAM_READABLE | G_PARAM_WRITABLE))); +#endif item_class->destroy = gnome_canvas_shape_destroy; item_class->update = gnome_canvas_shape_update; - item_class->realize = gnome_canvas_shape_realize; - item_class->unrealize = gnome_canvas_shape_unrealize; item_class->draw = gnome_canvas_shape_draw; item_class->point = gnome_canvas_shape_point; item_class->bounds = gnome_canvas_shape_bounds; @@ -195,18 +171,13 @@ gnome_canvas_shape_init (GnomeCanvasShape *shape) shape->priv->fill_rgba = 0x0000003f; shape->priv->outline_rgba = 0x0000007f; - shape->priv->cap = GDK_CAP_BUTT; - shape->priv->join = GDK_JOIN_MITER; - shape->priv->wind = ART_WIND_RULE_ODDEVEN; + shape->priv->cap = CAIRO_LINE_CAP_BUTT; + shape->priv->join = CAIRO_LINE_JOIN_MITER; + shape->priv->wind = CAIRO_FILL_RULE_EVEN_ODD; shape->priv->miterlimit = 10.43; /* X11 default */ - shape->priv->dash.n_dash = 0; - shape->priv->dash.dash = NULL; - - shape->priv->fill_svp = NULL; - shape->priv->outline_svp = NULL; - - shape->priv->gdk = NULL; + shape->priv->n_dash = 0; + shape->priv->dash = NULL; } static void @@ -221,31 +192,25 @@ gnome_canvas_shape_destroy (GnomeCanvasItem *object) shape = GNOME_CANVAS_SHAPE (object); priv = shape->priv; - if (priv->gdk) gcbp_destroy_gdk (shape); + if (priv->path) cairo_path_destroy (priv->path); - if (priv->path) gnome_canvas_path_def_unref (priv->path); - - if (priv->dash.dash) g_free (priv->dash.dash); - if (priv->fill_svp) art_svp_free (priv->fill_svp); - if (priv->outline_svp) art_svp_free (priv->outline_svp); + g_free (priv->dash); if (GNOME_CANVAS_ITEM_CLASS (gnome_canvas_shape_parent_class)->destroy) GNOME_CANVAS_ITEM_CLASS (gnome_canvas_shape_parent_class)->destroy (object); } /** - * gnome_canvas_shape_set_path_def: + * gnome_canvas_shape_set_path: * @shape: a GnomeCanvasShape - * @def: a GnomeCanvasPathDef + * @path: a cairo path from a cairo_copy_path() call * - * This function sets the the GnomeCanvasPathDef used by the - * GnomeCanvasShape. Notice, that it does not request updates, as - * it is meant to be used from item implementations, from inside - * update queue. + * This function sets the the path used by the GnomeCanvasShape. + * Notice that it does not request updates, as it is meant to be used + * from item implementations, from inside update queue. */ - void -gnome_canvas_shape_set_path_def (GnomeCanvasShape *shape, GnomeCanvasPathDef *def) +gnome_canvas_shape_set_path (GnomeCanvasShape *shape, cairo_path_t *path) { GnomeCanvasShapePriv *priv; @@ -255,13 +220,15 @@ gnome_canvas_shape_set_path_def (GnomeCanvasShape *shape, GnomeCanvasPathDef *de priv = shape->priv; if (priv->path) { - gnome_canvas_path_def_unref (priv->path); + cairo_path_destroy (priv->path); priv->path = NULL; } +} - if (def) { - priv->path = gnome_canvas_path_def_duplicate (def); - } +static guint32 +get_rgba_from_color (GdkColor * color) +{ + return ((color->red & 0xff00) << 16) | ((color->green & 0xff00) << 8) | (color->blue & 0xff00) | 0xff; } static void @@ -273,24 +240,18 @@ gnome_canvas_shape_set_property (GObject *object, GnomeCanvasItem *item; GnomeCanvasShape *shape; GnomeCanvasShapePriv *priv; - GnomeCanvasShapePrivGdk *gdk; GdkColor color; GdkColor *colorptr; - ArtVpathDash *dash; item = GNOME_CANVAS_ITEM (object); shape = GNOME_CANVAS_SHAPE (object); priv = shape->priv; - gcbp_ensure_gdk (shape); - gdk = priv->gdk; - switch (param_id) { case PROP_FILL_COLOR: if (gnome_canvas_get_color (item->canvas, g_value_get_string (value), &color)) { priv->fill_set = TRUE; priv->fill_rgba = get_rgba_from_color (&color); - if (gdk) gdk->fill_pixel = color.pixel; } else if (priv->fill_set) priv->fill_set = FALSE; else @@ -304,12 +265,6 @@ gnome_canvas_shape_set_property (GObject *object, if (colorptr != NULL) { priv->fill_set = TRUE; priv->fill_rgba = get_rgba_from_color (colorptr); - if (gdk) { - GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas)); - GdkColor tmp = *colorptr; - gdk_rgb_find_color (colormap, &tmp); - gdk->fill_pixel = tmp.pixel; - } } else if (priv->fill_set) priv->fill_set = FALSE; else @@ -321,7 +276,6 @@ gnome_canvas_shape_set_property (GObject *object, case PROP_FILL_COLOR_RGBA: priv->fill_set = TRUE; priv->fill_rgba = g_value_get_uint (value); - if (gdk) gdk->fill_pixel = get_pixel_from_rgba (item, priv->fill_rgba); gnome_canvas_item_request_update (item); break; @@ -330,7 +284,6 @@ gnome_canvas_shape_set_property (GObject *object, if (gnome_canvas_get_color (item->canvas, g_value_get_string (value), &color)) { priv->outline_set = TRUE; priv->outline_rgba = get_rgba_from_color (&color); - if (gdk) gdk->outline_pixel = color.pixel; } else if (priv->outline_set) priv->outline_set = FALSE; else @@ -344,12 +297,6 @@ gnome_canvas_shape_set_property (GObject *object, if (colorptr != NULL) { priv->outline_set = TRUE; priv->outline_rgba = get_rgba_from_color (colorptr); - if (gdk) { - GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas)); - GdkColor tmp = *colorptr; - gdk_rgb_find_color (colormap, &tmp); - gdk->outline_pixel = tmp.pixel; - } } else if (priv->outline_set) priv->outline_set = FALSE; else @@ -361,7 +308,6 @@ gnome_canvas_shape_set_property (GObject *object, case PROP_OUTLINE_COLOR_RGBA: priv->outline_set = TRUE; priv->outline_rgba = g_value_get_uint (value); - if (gdk) gdk->outline_pixel = get_pixel_from_rgba (item, priv->outline_rgba); gnome_canvas_item_request_update (item); break; @@ -373,7 +319,7 @@ gnome_canvas_shape_set_property (GObject *object, break; case PROP_WIND: - priv->wind = g_value_get_uint (value); + priv->wind = g_value_get_enum (value); gnome_canvas_item_request_update (item); break; @@ -393,70 +339,33 @@ gnome_canvas_shape_set_property (GObject *object, break; case PROP_DASH: - dash = g_value_get_pointer (value); - if (priv->dash.dash) g_free (priv->dash.dash); - priv->dash.dash = NULL; - - if (dash) { - priv->dash.offset = dash->offset; - priv->dash.n_dash = dash->n_dash; - if (dash->dash != NULL) { - priv->dash.dash = g_new (double, dash->n_dash); - memcpy (priv->dash.dash, dash->dash, dash->n_dash * sizeof (gdouble)); - } - } - gnome_canvas_item_request_update (item); + /* XXX */ + g_assert_not_reached (); break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } -/* Allocates a GdkColor structure filled with the specified pixel, and - * puts it into the specified value for returning it in the get_property - * method. - */ - -static void -get_color_value (GnomeCanvasShape *shape, gulong pixel, GValue *value) -{ - GnomeCanvas *canvas = GNOME_CANVAS_ITEM (shape)->canvas; - GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas)); - GdkColor color; - - gdk_colormap_query_color (colormap, pixel, &color); - g_value_set_boxed (value, &color); -} - /** - * gnome_canvas_shape_get_path_def: + * gnome_canvas_shape_get_path: * @shape: a GnomeCanvasShape * - * This function returns the #GnomeCanvasPathDef that the shape - * currently uses. It adds a reference to the #GnomeCanvasPathDef and - * returns it, if there is not a #GnomeCanvasPathDef set for the shape + * This function returns the #cairo_path_t that the shape currently + * uses. If there is not a #GnomeCanvasPathDef set for the shape * it returns NULL. * - * Returns: a #GnomeCanvasPathDef or NULL if none is set for the shape. + * Returns: a #cairo_path_t or NULL if none is set for the shape. */ - -GnomeCanvasPathDef * -gnome_canvas_shape_get_path_def (GnomeCanvasShape *shape) +const cairo_path_t * +gnome_canvas_shape_get_path (GnomeCanvasShape *shape) { - GnomeCanvasShapePriv *priv; - g_return_val_if_fail (shape != NULL, NULL); g_return_val_if_fail (GNOME_IS_CANVAS_SHAPE (shape), NULL); - priv = shape->priv; - - if (priv->path) { - gnome_canvas_path_def_ref (priv->path); - return priv->path; - } - - return NULL; + return shape->priv->path; } static void @@ -467,27 +376,8 @@ gnome_canvas_shape_get_property (GObject *object, { GnomeCanvasShape *shape = GNOME_CANVAS_SHAPE (object); GnomeCanvasShapePriv *priv = shape->priv; - GnomeCanvasShapePrivGdk *gdk; - - gcbp_ensure_gdk (shape); - gdk = priv->gdk; switch (param_id) { - case PROP_FILL_COLOR_GDK: - if (gdk) { - get_color_value (shape, gdk->fill_pixel, value); - } else { - get_color_value (shape, 0, value); - } - break; - - case PROP_OUTLINE_COLOR_GDK: - if (gdk) { - get_color_value (shape, gdk->outline_pixel, value); - } else { - get_color_value (shape, 0, value); - } - break; case PROP_FILL_COLOR_RGBA: g_value_set_uint (value, priv->fill_rgba); @@ -518,7 +408,8 @@ gnome_canvas_shape_get_property (GObject *object, break; case PROP_DASH: - g_value_set_pointer (value, &priv->dash); + /* XXX */ + g_assert_not_reached (); break; default: @@ -527,392 +418,140 @@ gnome_canvas_shape_get_property (GObject *object, } } -static void -gnome_canvas_shape_realize (GnomeCanvasItem *item) +static gboolean +gnome_canvas_shape_setup_for_fill (GnomeCanvasShape *shape, cairo_t *cr) { - GnomeCanvasShape *shape; - GtkLayout *layout; - GdkWindow *bin_window; - - shape = GNOME_CANVAS_SHAPE (item); - - if (GNOME_CANVAS_ITEM_CLASS (gnome_canvas_shape_parent_class)->realize) - GNOME_CANVAS_ITEM_CLASS (gnome_canvas_shape_parent_class)->realize (item); + GnomeCanvasShapePriv *priv = shape->priv; - gcbp_ensure_gdk (shape); + if (!priv->fill_set) + return FALSE; - layout = GTK_LAYOUT (item->canvas); - bin_window = gtk_layout_get_bin_window (layout); + cairo_set_source_rgba (cr, + ((priv->fill_rgba >> 24) & 0xff) / 255.0, + ((priv->fill_rgba >> 16) & 0xff) / 255.0, + ((priv->fill_rgba >> 8) & 0xff) / 255.0, + ( priv->fill_rgba & 0xff) / 255.0); + cairo_set_fill_rule (cr, priv->wind); - g_assert (bin_window != NULL); - - shape->priv->gdk->fill_gc = gdk_gc_new (bin_window); - shape->priv->gdk->outline_gc = gdk_gc_new (bin_window); + return TRUE; } -static void -gnome_canvas_shape_unrealize (GnomeCanvasItem *item) +static gboolean +gnome_canvas_shape_setup_for_stroke (GnomeCanvasShape *shape, cairo_t *cr) { - GnomeCanvasShape *shape; - - shape = GNOME_CANVAS_SHAPE (item); - - g_assert (shape->priv->gdk != NULL); - - g_object_unref (shape->priv->gdk->fill_gc); - shape->priv->gdk->fill_gc = NULL; - - g_object_unref (shape->priv->gdk->outline_gc); - shape->priv->gdk->outline_gc = NULL; - - if (GNOME_CANVAS_ITEM_CLASS (gnome_canvas_shape_parent_class)->unrealize) - GNOME_CANVAS_ITEM_CLASS (gnome_canvas_shape_parent_class)->unrealize (item); + GnomeCanvasShapePriv *priv = shape->priv; + + if (!priv->outline_set) + return FALSE; + + cairo_set_source_rgba (cr, + ((priv->outline_rgba >> 24) & 0xff) / 255.0, + ((priv->outline_rgba >> 16) & 0xff) / 255.0, + ((priv->outline_rgba >> 8) & 0xff) / 255.0, + ( priv->outline_rgba & 0xff) / 255.0); + cairo_set_line_width (cr, priv->line_width); + cairo_set_line_cap (cr, priv->cap); + cairo_set_line_join (cr, priv->join); + cairo_set_miter_limit (cr, priv->miterlimit); + cairo_set_dash (cr, priv->dash, priv->n_dash, priv->dash_offset); + + return TRUE; } static void gnome_canvas_shape_draw (GnomeCanvasItem *item, - GdkDrawable *drawable, - gint x, - gint y, - gint width, - gint height) + GdkDrawable *drawable, + gint x, + gint y, + gint width, + gint height) { - static GdkPoint * dpoints = NULL; - static gint num_dpoints = 0; - GnomeCanvasShape * shape; - GnomeCanvasShapePriv * priv; - GnomeCanvasShapePrivGdk * gdk; - gint i, pos, len; - GSList * l; + cairo_matrix_t matrix; + cairo_t *cr; shape = GNOME_CANVAS_SHAPE (item); - priv = shape->priv; - - /* We have to be realized, so gdk struct should exist! */ - - gdk = shape->priv->gdk; - g_assert (gdk != NULL); - - /* Build temporary point list, translated by -x, -y */ - - if (dpoints == NULL) { - dpoints = g_new (GdkPoint, gdk->num_points); - num_dpoints = gdk->num_points; - } else if (num_dpoints < gdk->num_points) { - dpoints = g_renew (GdkPoint, dpoints, gdk->num_points); - num_dpoints = gdk->num_points; - } - - for (i = 0; i < gdk->num_points; i++) { - dpoints[i].x = gdk->points[i].x - x; - dpoints[i].y = gdk->points[i].y - y; - } - - if (priv->fill_set) { - - /* Ensure, that we have mask and it is big enough */ - - gcbp_ensure_mask (shape, width, height); + cr = gdk_cairo_create (drawable); + gnome_canvas_item_i2c_matrix (item, &matrix); + if (cairo_matrix_invert (&matrix)) + return; + cairo_transform (cr, &matrix); + cairo_append_path (cr, shape->priv->path); - /* Clear mask */ + if (gnome_canvas_shape_setup_for_fill (shape, cr)) + cairo_fill_preserve (cr); - gdk_draw_rectangle (gdk->ctx->mask, - gdk->ctx->clear_gc, - TRUE, - 0, 0, - width, height); + if (gnome_canvas_shape_setup_for_stroke (shape, cr)) + cairo_stroke_preserve (cr); - /* Draw subpaths, using XOR gc */ - - pos = 0; - - for (l = gdk->closed_paths; l != NULL; l = l->next) { - len = GPOINTER_TO_INT (l->data); - - gdk_draw_polygon (gdk->ctx->mask, - gdk->ctx->xor_gc, - TRUE, - &dpoints[pos], - len); - - pos += len; - } - - /* Set bitmap to clipping mask */ - - gdk_gc_set_clip_mask (gdk->fill_gc, gdk->ctx->mask); - - /* Draw clipped rect to drawable */ - - gdk_draw_rectangle (drawable, - gdk->fill_gc, - TRUE, - 0, 0, - width, height); - } - - if (priv->outline_set) { - - /* Draw subpaths */ - - pos = 0; - - for (l = gdk->closed_paths; l != NULL; l = l->next) { - len = GPOINTER_TO_INT (l->data); - - gdk_draw_polygon (drawable, - gdk->outline_gc, - FALSE, - &dpoints[pos], - len); - - pos += len; - } - - for (l = gdk->open_paths; l != NULL; l = l->next) { - len = GPOINTER_TO_INT (l->data); - - gdk_draw_lines (drawable, - gdk->outline_gc, - &dpoints[pos], - len); - - pos += len; - } - } + cairo_destroy (cr); } -#define GDK_POINTS_BLOCK 32 - static void -gnome_canvas_shape_ensure_gdk_points (GnomeCanvasShapePrivGdk *gdk, gint num) +my_cairo_matrix_transform_rectangle (const cairo_matrix_t *matrix, + double *x1, double *y1, double *x2, double *y2) { - if (gdk->len_points < gdk->num_points + num) { - gdk->len_points = MAX (gdk->len_points + GDK_POINTS_BLOCK, gdk->len_points + num); - gdk->points = g_renew (GdkPoint, gdk->points, gdk->len_points); - } + double maxx, maxy, minx, miny; + double tmpx, tmpy; + + tmpx = *x1; + tmpy = *y1; + cairo_matrix_transform_point (matrix, &tmpx, &tmpy); + minx = maxx = tmpx; + miny = maxy = tmpy; + + tmpx = *x2; + tmpy = *y1; + cairo_matrix_transform_point (matrix, &tmpx, &tmpy); + minx = MIN (minx, tmpx); + maxx = MAX (maxx, tmpx); + miny = MIN (miny, tmpy); + maxy = MAX (maxy, tmpy); + + tmpx = *x2; + tmpy = *y2; + cairo_matrix_transform_point (matrix, &tmpx, &tmpy); + minx = MIN (minx, tmpx); + maxx = MAX (maxx, tmpx); + miny = MIN (miny, tmpy); + maxy = MAX (maxy, tmpy); + + tmpx = *x1; + tmpy = *y2; + cairo_matrix_transform_point (matrix, &tmpx, &tmpy); + minx = MIN (minx, tmpx); + maxx = MAX (maxx, tmpx); + miny = MIN (miny, tmpy); + maxy = MAX (maxy, tmpy); + + *x1 = minx; + *x2 = maxx; + *y1 = miny; + *y2 = maxy; } static void -gnome_canvas_shape_update_gdk (GnomeCanvasShape * shape, gdouble * affine, ArtSVP * clip, gint flags) +gnome_canvas_shape_bounds (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2) { + GnomeCanvasShape * shape; GnomeCanvasShapePriv * priv; - GnomeCanvasShapePrivGdk * gdk; - gint x1 = 0, y1 = 0, x2 = 0, y2 = 0; - gboolean bbox_set = FALSE; - gint width = 0; /* silence gcc */ + cairo_t *cr; + shape = GNOME_CANVAS_SHAPE (item); priv = shape->priv; - gdk = priv->gdk; - g_assert (gdk != NULL); - - if (priv->outline_set) { - GdkLineStyle style; - - width = (gint) floor ((priv->line_width * priv->scale) + 0.5); - /* Never select 0 pixels unless the user asked for it, - * since that is the X11 zero width lines are non-speciifed */ - if (priv->line_width != 0 && width == 0) { - width = 1; - } - - /* If dashed, set it in GdkGC */ - - if ((shape->priv->dash.dash != NULL) && (shape->priv->dash.n_dash > 0)) { - gint8 * dash_list; - gint i; - - dash_list = g_new (gint8, shape->priv->dash.n_dash); - - for (i = 0; i < priv->dash.n_dash; i++) { - dash_list[i] = (gint8) shape->priv->dash.dash[i]; - } - - gdk_gc_set_dashes (gdk->outline_gc, - (gint) priv->dash.offset, - dash_list, - priv->dash.n_dash); - - g_free (dash_list); - style = GDK_LINE_ON_OFF_DASH; - } else { - style = GDK_LINE_SOLID; - } + cr = gnome_canvas_cairo_create_scratch (); + cairo_append_path (cr, shape->priv->path); - /* Set line width, cap, join */ - if (gdk->outline_gc) { - - gdk_gc_set_line_attributes (gdk->outline_gc, - width, - style, - priv->cap, - priv->join); - - set_gc_foreground (gdk->outline_gc, gdk->outline_pixel); - } - } - - if (priv->fill_set) { - - if (gdk->fill_gc) { - set_gc_foreground (gdk->fill_gc, gdk->fill_pixel); - } - } - - /* Now the crazy part */ - - /* Free existing GdkPoint array */ - - if (gdk->points) { - g_free (gdk->points); - gdk->points = NULL; - gdk->len_points = 0; - gdk->num_points = 0; - } - - /* Free subpath lists */ - - while (gdk->closed_paths) gdk->closed_paths = g_slist_remove (gdk->closed_paths, gdk->closed_paths->data); - while (gdk->open_paths) gdk->open_paths = g_slist_remove (gdk->open_paths, gdk->open_paths->data); - - /* Calcualte new GdkPoints array and subpath lists */ - - if (priv->path) { - GnomeCanvasPathDef * apath, * cpath, * opath; - ArtBpath * abpath; - GSList * clist, * olist; - gint pos; - -#if 0 - /* Allocate array */ - gdk->num_points = gnome_canvas_path_def_length (priv->path) * 1000 - 1; - gdk->points = g_new (GdkPoint, gdk->num_points); - g_print ("Points %d\n", gdk->num_points); - /* Transform path */ -#endif - - abpath = art_bpath_affine_transform (gnome_canvas_path_def_bpath (priv->path), affine); - apath = gnome_canvas_path_def_new_from_bpath (abpath); - - /* Split path into open and closed parts */ - - cpath = gnome_canvas_path_def_closed_parts (apath); - opath = gnome_canvas_path_def_open_parts (apath); - gnome_canvas_path_def_unref (apath); - - /* Split partial paths into subpaths */ - - clist = gnome_canvas_path_def_split (cpath); - gnome_canvas_path_def_unref (cpath); - olist = gnome_canvas_path_def_split (opath); - gnome_canvas_path_def_unref (opath); - - pos = 0; - - /* Fill GdkPoints and add subpaths to list: closed subpaths */ - - while (clist) { - GnomeCanvasPathDef * path; - ArtBpath * bpath; - ArtVpath * vpath; - gint len, i; - - path = (GnomeCanvasPathDef *) clist->data; - bpath = gnome_canvas_path_def_bpath (path); - vpath = art_bez_path_to_vec (bpath, 0.1); - for (len = 0; vpath[len].code != ART_END; len++); - - gnome_canvas_shape_ensure_gdk_points (gdk, len); - for (i = 0; i < len; i++) { - gdk->points[pos + i].x = (gint) floor (vpath[i].x + 0.5); - gdk->points[pos + i].y = (gint) floor (vpath[i].y + 0.5); - - if (bbox_set) { - x1 = MIN (x1, gdk->points[pos + i].x); - x2 = MAX (x2, gdk->points[pos + i].x); - y1 = MIN (y1, gdk->points[pos + i].y); - y2 = MAX (y2, gdk->points[pos + i].y); - } else { - bbox_set = TRUE; - x1 = x2 = gdk->points[pos + i].x; - y1 = y2 = gdk->points[pos + i].y; - } - } - gdk->num_points += len; - - art_free (vpath); - - if (len > 0) { - pos += len; - gdk->closed_paths = g_slist_append (gdk->closed_paths, GINT_TO_POINTER (len)); - } - - gnome_canvas_path_def_unref (path); - clist = g_slist_remove (clist, clist->data); - } - - /* Fill GdkPoints and add subpaths to list: open subpaths */ - - while (olist) { - GnomeCanvasPathDef * path; - ArtBpath * bpath; - ArtVpath * vpath; - gint len, i; - - path = (GnomeCanvasPathDef *) olist->data; - bpath = gnome_canvas_path_def_bpath (path); - vpath = art_bez_path_to_vec (bpath, 0.1); - for (len = 0; vpath[len].code != ART_END; len++); - - gnome_canvas_shape_ensure_gdk_points (gdk, len); - for (i = 0; i < len; i++) { - gdk->points[pos + i].x = (gint) floor (vpath[i].x + 0.5); - gdk->points[pos + i].y = (gint) floor (vpath[i].y + 0.5); - - if (bbox_set) { - x1 = MIN (x1, gdk->points[pos + i].x); - x2 = MAX (x2, gdk->points[pos + i].x); - y1 = MIN (y1, gdk->points[pos + i].y); - y2 = MAX (y2, gdk->points[pos + i].y); - } else { - bbox_set = TRUE; - x1 = x2 = gdk->points[pos + i].x; - y1 = y2 = gdk->points[pos + i].y; - } - } - gdk->num_points += len; - - art_free (vpath); - - if (len > 0) { - pos += len; - gdk->open_paths = g_slist_append (gdk->open_paths, GINT_TO_POINTER (len)); - } - - gnome_canvas_path_def_unref (path); - olist = g_slist_remove (olist, olist->data); - } - - } - - if (bbox_set) { - if (priv->outline_set) { - gint stroke_border = (priv->join == GDK_JOIN_MITER) - ? ceil (10.43*width/2) /* 10.43 is the miter limit for X11 */ - : ceil (width/2); - x1 -= stroke_border; - x2 += stroke_border; - y1 -= stroke_border; - y2 += stroke_border; - } - - gnome_canvas_update_bbox (GNOME_CANVAS_ITEM (shape), - x1, y1, - x2 + 1, y2 + 1); - } + if (gnome_canvas_shape_setup_for_stroke (shape, cr)) + cairo_stroke_extents (cr, x1, x2, y1, y2); + else if (gnome_canvas_shape_setup_for_fill (shape, cr)) + cairo_fill_extents (cr, x1, x2, y1, y2); + else { + *x1 = *x2 = *y1 = *y2 = 0; + } + cairo_destroy (cr); } static void @@ -920,410 +559,51 @@ gnome_canvas_shape_update (GnomeCanvasItem *item, gdouble *affine, ArtSVP *clip_ { GnomeCanvasShape * shape; GnomeCanvasShapePriv * priv; - ArtSVP * svp; + double x1, x2, y1, y2; + cairo_matrix_t matrix; shape = GNOME_CANVAS_SHAPE (item); priv = shape->priv; /* Common part */ - if (GNOME_CANVAS_ITEM_CLASS (gnome_canvas_shape_parent_class)->update) { + if (GNOME_CANVAS_ITEM_CLASS (gnome_canvas_shape_parent_class)->update) GNOME_CANVAS_ITEM_CLASS (gnome_canvas_shape_parent_class)->update (item, affine, clip_path, flags); - } - - /* Outline width */ - shape->priv->scale = art_affine_expansion (affine); - - /* Clipped fill SVP */ - - if ((priv->fill_set) && (priv->path) && (gnome_canvas_path_def_any_closed (priv->path))) { - GnomeCanvasPathDef * cpath; - ArtSvpWriter *swr; - ArtVpath *vpath; - ArtBpath *abp; - ArtSVP *svp2; - - /* Get closed part of path */ - - cpath = gnome_canvas_path_def_closed_parts (shape->priv->path); - abp = art_bpath_affine_transform (gnome_canvas_path_def_bpath (cpath), affine); - gnome_canvas_path_def_unref (cpath); - - /* Render, until SVP */ - - vpath = art_bez_path_to_vec (abp, 0.1); - art_free (abp); - - svp = art_svp_from_vpath (vpath); - art_free (vpath); - swr = art_svp_writer_rewind_new (shape->priv->wind); - art_svp_intersector (svp, swr); + gnome_canvas_shape_bounds (item, &x1, &x2, &y1, &y2); + gnome_canvas_item_i2w_matrix (item, &matrix); - svp2 = art_svp_writer_rewind_reap (swr); - art_svp_free (svp); - - if (priv->fill_svp) { - art_svp_free (priv->fill_svp); - priv->fill_svp = NULL; - } - /* No clipping */ - shape->priv->fill_svp = svp2; - } - - if (priv->outline_set && priv->path && !gnome_canvas_path_def_is_empty (priv->path)) { - gdouble width; - ArtBpath * abp; - ArtVpath * vpath; - - /* Set linewidth */ - - width = priv->line_width * priv->scale; - - if (width < 0.5) width = 0.5; - - /* Render full path until vpath */ - - abp = art_bpath_affine_transform (gnome_canvas_path_def_bpath (priv->path), affine); - - vpath = art_bez_path_to_vec (abp, 0.1); - art_free (abp); - - /* If dashed, apply dash */ - - if (priv->dash.dash != NULL) - { - ArtVpath *old = vpath; - - vpath = art_vpath_dash (old, &priv->dash); - art_free (old); - } - - /* Stroke vpath to SVP */ - - svp = art_svp_vpath_stroke (vpath, - gnome_canvas_join_gdk_to_art (priv->join), - gnome_canvas_cap_gdk_to_art (priv->cap), - width, - priv->miterlimit, - 0.25); - art_free (vpath); - - if (priv->outline_svp) { - art_svp_free (priv->outline_svp); - priv->outline_svp = NULL; - } - /* No clipping (yet) */ - shape->priv->outline_svp = svp; - } - - /* Gdk requires additional handling */ - gnome_canvas_shape_update_gdk (shape, affine, clip_path, flags); + my_cairo_matrix_transform_rectangle (&matrix, &x1, &y1, &x2, &y2); + gnome_canvas_update_bbox (GNOME_CANVAS_ITEM (shape), + floor (x1), floor (y1), + ceil (x2), ceil (y2)); } static GnomeCanvasItem * gnome_canvas_shape_point (GnomeCanvasItem *item, gdouble x, gdouble y, - gint cx, gint cy) -{ - GnomeCanvasShape *shape; - gint wind; - -#if 0 - /* fixme: This is just for debugging, canvas should ensure that */ - /* fixme: IF YOU ARE SURE THAT IT IS CORRECT BEHAVIOUR, you can remove warning */ - /* fixme: and make it to return silently */ - g_return_val_if_fail (!item->canvas->need_update, 1e18); -#endif - - shape = GNOME_CANVAS_SHAPE (item); - - /* todo: update? */ - if (shape->priv->fill_set && shape->priv->fill_svp) { - wind = art_svp_point_wind (shape->priv->fill_svp, cx, cy); - if ((shape->priv->wind == ART_WIND_RULE_NONZERO) && (wind != 0)) - return item; - if ((shape->priv->wind == ART_WIND_RULE_ODDEVEN) && ((wind & 0x1) != 0)) - return item; - } - - if (shape->priv->outline_set && shape->priv->outline_svp) { - wind = art_svp_point_wind (shape->priv->outline_svp, cx, cy); - if (wind) - return item; - } - - return NULL; -} - -/* Helpers */ - -/* Get 32bit rgba color from GdkColor */ - -static guint32 -get_rgba_from_color (GdkColor * color) -{ - return ((color->red & 0xff00) << 16) | ((color->green & 0xff00) << 8) | (color->blue & 0xff00) | 0xff; -} - -/* Get Gdk pixel value from 32bit rgba color */ - -static gulong -get_pixel_from_rgba (GnomeCanvasItem *item, guint32 rgba_color) -{ - return gnome_canvas_get_color_pixel (item->canvas, rgba_color); -} - -/* Convenience function to set a GC's foreground color to the specified pixel value */ - -static void -set_gc_foreground (GdkGC *gc, gulong pixel) -{ - GdkColor c; - - g_assert (gc != NULL); - - c.pixel = pixel; - - gdk_gc_set_foreground (gc, &c); -} - -/* Creates private Gdk struct, if not present */ -/* We cannot do it during ::init, as we have to know canvas */ - -static void -gcbp_ensure_gdk (GnomeCanvasShape * shape) -{ - if (!shape->priv->gdk) { - GnomeCanvasShapePrivGdk * gdk; - - gdk = g_new (GnomeCanvasShapePrivGdk, 1); - - gdk->fill_pixel = get_pixel_from_rgba ((GnomeCanvasItem *) shape, shape->priv->fill_rgba); - gdk->outline_pixel = get_pixel_from_rgba ((GnomeCanvasItem *) shape, shape->priv->outline_rgba); - - gdk->fill_gc = NULL; - gdk->outline_gc = NULL; - - gdk->len_points = 0; - gdk->num_points = 0; - gdk->points = NULL; - gdk->closed_paths = NULL; - gdk->open_paths = NULL; - - gdk->ctx = NULL; - - shape->priv->gdk = gdk; - } -} - -/* Destroy private Gdk struct */ -/* It is here, to make ::destroy implementation shorter :) */ - -static void -gcbp_destroy_gdk (GnomeCanvasShape * shape) -{ - GnomeCanvasShapePrivGdk * gdk; - - gdk = shape->priv->gdk; - - if (gdk) { - g_assert (!gdk->fill_gc); - g_assert (!gdk->outline_gc); - - if (gdk->points) - g_free (gdk->points); - - while (gdk->closed_paths) - gdk->closed_paths = g_slist_remove (gdk->closed_paths, gdk->closed_paths->data); - while (gdk->open_paths) - gdk->open_paths = g_slist_remove (gdk->open_paths, gdk->open_paths->data); - - if (gdk->ctx) - gcbp_draw_ctx_unref (gdk->ctx); - - g_free (gdk); - - shape->priv->gdk = NULL; - } -} - -/* - * Ensure, that per-canvas Ctx struct is present and bitmaps are - * big enough, to mask full redraw area. Ctx is refcounted and - * defined as "BpathDrawCtx" data member on parent canvas - */ - -static void -gcbp_ensure_mask (GnomeCanvasShape * shape, gint width, gint height) -{ - GnomeCanvasShapePrivGdk * gdk; - GCBPDrawCtx * ctx; - - gdk = shape->priv->gdk; - g_assert (gdk != NULL); - ctx = gdk->ctx; - - if (!ctx) { - /* Ctx is not yet defined for us */ - - GnomeCanvas * canvas; - - canvas = GNOME_CANVAS_ITEM (shape)->canvas; - - ctx = g_object_get_data (G_OBJECT (canvas), "BpathDrawCtx"); - - if (!ctx) { - /* Ctx is not defined for parent canvas yet */ - - ctx = g_new (GCBPDrawCtx, 1); - - ctx->refcount = 1; - ctx->canvas = canvas; - ctx->width = 0; - ctx->height = 0; - - ctx->mask = NULL; - ctx->clip = NULL; - - ctx->clear_gc = NULL; - ctx->xor_gc = NULL; - - g_object_set_data (G_OBJECT (canvas), "BpathDrawCtx", ctx); - - } else { - ctx->refcount++; - } - - gdk->ctx = ctx; - - } - - /* Now we are sure, that ctx is present and properly refcounted */ - - if ((width > ctx->width) || (height > ctx->height)) { - /* Ctx is too small */ - GtkWidget *widget; - GdkWindow * window; - - widget = GTK_WIDGET (GNOME_CANVAS_ITEM (shape)->canvas); - window = gtk_widget_get_window (widget); - - if (ctx->clear_gc) g_object_unref (ctx->clear_gc); - if (ctx->xor_gc) g_object_unref (ctx->xor_gc); - if (ctx->mask) g_object_unref (ctx->mask); - if (ctx->clip) g_object_unref (ctx->clip); - - ctx->mask = gdk_pixmap_new (window, width, height, 1); - ctx->clip = NULL; - - ctx->clear_gc = gdk_gc_new (ctx->mask); - gdk_gc_set_function (ctx->clear_gc, GDK_CLEAR); - - ctx->xor_gc = gdk_gc_new (ctx->mask); - gdk_gc_set_function (ctx->xor_gc, GDK_INVERT); - } -} - -/* It is cleaner to have it here, not in parent function */ - -static void -gcbp_draw_ctx_unref (GCBPDrawCtx * ctx) -{ - if (--ctx->refcount < 1) { - if (ctx->clear_gc) - g_object_unref (ctx->clear_gc); - if (ctx->xor_gc) - g_object_unref (ctx->xor_gc); - - if (ctx->mask) - g_object_unref (ctx->mask); - if (ctx->clip) - g_object_unref (ctx->clip); - - g_object_set_data (G_OBJECT (ctx->canvas), "BpathDrawCtx", NULL); - g_free (ctx); - } -} - -static void -gnome_canvas_shape_bounds (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2) + gint cx, gint cy) { GnomeCanvasShape * shape; - GnomeCanvasShapePriv * priv; - ArtDRect bbox; - ArtSVP * svp; + cairo_t *cr; shape = GNOME_CANVAS_SHAPE (item); - priv = shape->priv; - - bbox.x0 = *x1; - bbox.y0 = *y1; - bbox.x1 = *x2; - bbox.y1 = *y2; - - if (priv->outline_set && priv->path && !gnome_canvas_path_def_is_empty (priv->path)) { - gdouble width; - ArtVpath * vpath; - - /* Set linewidth */ - - width = priv->line_width * priv->scale; - - if (width < 0.5) width = 0.5; - - /* Render full path until vpath */ - - vpath = art_bez_path_to_vec (gnome_canvas_path_def_bpath (priv->path), 0.1); + cr = gnome_canvas_cairo_create_scratch (); + cairo_append_path (cr, shape->priv->path); - /* If dashed, apply dash */ + if (gnome_canvas_shape_setup_for_fill (shape, cr) && + cairo_in_fill (cr, x, y)) { + cairo_destroy (cr); + return item; + } - if (priv->dash.dash != NULL) - { - ArtVpath *old = vpath; + if (gnome_canvas_shape_setup_for_stroke (shape, cr) && + cairo_in_stroke (cr, x, y)) { + cairo_destroy (cr); + return item; + } - vpath = art_vpath_dash (old, &priv->dash); - art_free (old); - } - - /* Stroke vpath to SVP */ - - svp = art_svp_vpath_stroke (vpath, - gnome_canvas_join_gdk_to_art (priv->join), - gnome_canvas_cap_gdk_to_art (priv->cap), - width, - priv->miterlimit, - 0.25); - art_free (vpath); - art_drect_svp (&bbox, svp); - art_svp_free (svp); - } else if ((priv->fill_set) && (priv->path) && (gnome_canvas_path_def_any_closed (priv->path))) { - GnomeCanvasPathDef *cpath; - ArtSvpWriter *swr; - ArtVpath *vpath; - ArtSVP *svp2; - - /* Get closed part of path */ - cpath = gnome_canvas_path_def_closed_parts (shape->priv->path); - /* Render, until SVP */ - vpath = art_bez_path_to_vec (gnome_canvas_path_def_bpath (cpath), 0.1); - gnome_canvas_path_def_unref (cpath); - - svp = art_svp_from_vpath (vpath); - art_free (vpath); - - swr = art_svp_writer_rewind_new (shape->priv->wind); - art_svp_intersector (svp, swr); - - svp2 = art_svp_writer_rewind_reap (swr); - art_svp_free (svp); - - art_drect_svp (&bbox, svp2); - art_svp_free (svp2); - } + cairo_destroy (cr); - *x1 = bbox.x0; - *y1 = bbox.y0; - *x2 = bbox.x1; - *y2 = bbox.y1; + return NULL; } |