/* * GooCanvas. Copyright (C) 2005 Damon Chaplin. * Released under the GNU LGPL license. See COPYING for details. * * goocanvasutils.c - utility functions. */ /** * SECTION:goocanvasutils * @Title: GooCanvas Types * @Short_Description: types used in GooCanvas. * * This section describes the types used throughout GooCanvas. */ #include #include #include "goocanvasutils.h" /* Glib doesn't provide a g_ptr_array_index() so we need our own one. */ void goo_canvas_util_ptr_array_insert (GPtrArray *ptr_array, gpointer data, gint index) { gint i; /* Add the pointer at the end so there is enough room. */ g_ptr_array_add (ptr_array, data); /* If index is -1, we are done. */ if (index == -1) return; /* Move the other pointers to make room for the new one. */ for (i = ptr_array->len - 1; i > index; i--) ptr_array->pdata[i] = ptr_array->pdata[i - 1]; /* Put the new element in its proper place. */ ptr_array->pdata[index] = data; } /* Glib doesn't provide a g_ptr_array_move() so we need our own one. */ void goo_canvas_util_ptr_array_move (GPtrArray *ptr_array, gint old_index, gint new_index) { gpointer data; gint i; data = ptr_array->pdata[old_index]; if (new_index > old_index) { /* Move the pointers down one place. */ for (i = old_index; i < new_index; i++) ptr_array->pdata[i] = ptr_array->pdata[i + 1]; } else { /* Move the pointers up one place. */ for (i = old_index; i > new_index; i--) ptr_array->pdata[i] = ptr_array->pdata[i - 1]; } ptr_array->pdata[new_index] = data; } /* Glib doesn't provide a g_ptr_array_move() so we need our own one. */ gint goo_canvas_util_ptr_array_find_index (GPtrArray *ptr_array, gpointer data) { gint i; for (i = 0; i < ptr_array->len; i++) { if (ptr_array->pdata[i] == data) return i; } return -1; } /* * Enum types. */ GType goo_canvas_pointer_events_get_type (void) { static GType etype = 0; if (etype == 0) { static const GFlagsValue values[] = { { GOO_CANVAS_EVENTS_VISIBLE_MASK, "GOO_CANVAS_EVENTS_VISIBLE_MASK", "visible-mask" }, { GOO_CANVAS_EVENTS_PAINTED_MASK, "GOO_CANVAS_EVENTS_PAINTED_MASK", "painted-mask" }, { GOO_CANVAS_EVENTS_FILL_MASK, "GOO_CANVAS_EVENTS_FILL_MASK", "fill-mask" }, { GOO_CANVAS_EVENTS_STROKE_MASK, "GOO_CANVAS_EVENTS_STROKE_MASK", "stroke-mask" }, { GOO_CANVAS_EVENTS_NONE, "GOO_CANVAS_EVENTS_NONE", "none" }, { GOO_CANVAS_EVENTS_VISIBLE_PAINTED, "GOO_CANVAS_EVENTS_VISIBLE_PAINTED", "visible-painted" }, { GOO_CANVAS_EVENTS_VISIBLE_FILL, "GOO_CANVAS_EVENTS_VISIBLE_FILL", "visible-fill" }, { GOO_CANVAS_EVENTS_VISIBLE_STROKE, "GOO_CANVAS_EVENTS_VISIBLE_STROKE", "visible-stroke" }, { GOO_CANVAS_EVENTS_VISIBLE, "GOO_CANVAS_EVENTS_VISIBLE", "visible" }, { GOO_CANVAS_EVENTS_PAINTED, "GOO_CANVAS_EVENTS_PAINTED", "painted" }, { GOO_CANVAS_EVENTS_FILL, "GOO_CANVAS_EVENTS_FILL", "fill" }, { GOO_CANVAS_EVENTS_STROKE, "GOO_CANVAS_EVENTS_STROKE", "stroke" }, { GOO_CANVAS_EVENTS_ALL, "GOO_CANVAS_EVENTS_ALL", "all" }, { 0, NULL, NULL } }; etype = g_flags_register_static ("GooCanvasPointerEvents", values); } return etype; } GType goo_canvas_item_visibility_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { { GOO_CANVAS_ITEM_VISIBLE, "GOO_CANVAS_ITEM_VISIBLE", "visible" }, { GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD, "GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD", "visible-above-threshold" }, { GOO_CANVAS_ITEM_INVISIBLE, "GOO_CANVAS_ITEM_INVISIBLE", "invisible" }, { 0, NULL, NULL } }; etype = g_enum_register_static ("GooCanvasItemVisibility", values); } return etype; } /* * Cairo utilities. */ cairo_surface_t* goo_canvas_cairo_surface_from_pixbuf (GdkPixbuf *pixbuf) { gint width = gdk_pixbuf_get_width (pixbuf); gint height = gdk_pixbuf_get_height (pixbuf); guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf); int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf); int n_channels = gdk_pixbuf_get_n_channels (pixbuf); guchar *cairo_pixels; cairo_format_t format; cairo_surface_t *surface; static const cairo_user_data_key_t key; int j; if (n_channels == 3) format = CAIRO_FORMAT_RGB24; else format = CAIRO_FORMAT_ARGB32; cairo_pixels = g_malloc (4 * width * height); surface = cairo_image_surface_create_for_data ((unsigned char *)cairo_pixels, format, width, height, 4 * width); cairo_surface_set_user_data (surface, &key, cairo_pixels, (cairo_destroy_func_t)g_free); for (j = height; j; j--) { guchar *p = gdk_pixels; guchar *q = cairo_pixels; if (n_channels == 3) { guchar *end = p + 3 * width; while (p < end) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN q[0] = p[2]; q[1] = p[1]; q[2] = p[0]; #else q[1] = p[0]; q[2] = p[1]; q[3] = p[2]; #endif p += 3; q += 4; } } else { guchar *end = p + 4 * width; guint t1,t2,t3; #define MULT(d,c,a,t) G_STMT_START { t = c * a; d = ((t >> 8) + t) >> 8; } G_STMT_END while (p < end) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN MULT(q[0], p[2], p[3], t1); MULT(q[1], p[1], p[3], t2); MULT(q[2], p[0], p[3], t3); q[3] = p[3]; #else q[0] = p[3]; MULT(q[1], p[0], p[3], t1); MULT(q[2], p[1], p[3], t2); MULT(q[3], p[2], p[3], t3); #endif p += 4; q += 4; } #undef MULT } gdk_pixels += gdk_rowstride; cairo_pixels += 4 * width; } return surface; } cairo_pattern_t* goo_canvas_cairo_pattern_from_pixbuf (GdkPixbuf *pixbuf) { cairo_surface_t *surface; cairo_pattern_t *pattern; surface = goo_canvas_cairo_surface_from_pixbuf (pixbuf); pattern = cairo_pattern_create_for_surface (surface); cairo_surface_destroy (surface); return pattern; } /* * Cairo types. */ GType goo_cairo_pattern_get_type (void) { static GType cairo_pattern_type = 0; if (cairo_pattern_type == 0) cairo_pattern_type = g_boxed_type_register_static ("GooCairoPattern", (GBoxedCopyFunc) cairo_pattern_reference, (GBoxedFreeFunc) cairo_pattern_destroy); return cairo_pattern_type; } GType goo_cairo_fill_rule_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { { CAIRO_FILL_RULE_WINDING, "CAIRO_FILL_RULE_WINDING", "winding" }, { CAIRO_FILL_RULE_EVEN_ODD, "CAIRO_FILL_RULE_EVEN_ODD", "even-odd" }, { 0, NULL, NULL } }; etype = g_enum_register_static ("GooCairoFillRule", values); } return etype; } GType goo_cairo_operator_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { { CAIRO_OPERATOR_CLEAR, "CAIRO_OPERATOR_CLEAR", "clear" }, { CAIRO_OPERATOR_SOURCE, "CAIRO_OPERATOR_SOURCE", "source" }, { CAIRO_OPERATOR_OVER, "CAIRO_OPERATOR_OVER", "over" }, { CAIRO_OPERATOR_IN, "CAIRO_OPERATOR_IN", "in" }, { CAIRO_OPERATOR_OUT, "CAIRO_OPERATOR_OUT", "out" }, { CAIRO_OPERATOR_ATOP, "CAIRO_OPERATOR_ATOP", "atop" }, { CAIRO_OPERATOR_DEST, "CAIRO_OPERATOR_DEST", "dest" }, { CAIRO_OPERATOR_DEST_OVER, "CAIRO_OPERATOR_DEST_OVER", "dest-over" }, { CAIRO_OPERATOR_DEST_IN, "CAIRO_OPERATOR_DEST_IN", "dest-in" }, { CAIRO_OPERATOR_DEST_OUT, "CAIRO_OPERATOR_DEST_OUT", "dest-out" }, { CAIRO_OPERATOR_DEST_ATOP, "CAIRO_OPERATOR_DEST_ATOP", "dest-atop" }, { CAIRO_OPERATOR_XOR, "CAIRO_OPERATOR_XOR", "xor" }, { CAIRO_OPERATOR_ADD, "CAIRO_OPERATOR_ADD", "add" }, { CAIRO_OPERATOR_SATURATE, "CAIRO_OPERATOR_SATURATE", "saturate" }, { 0, NULL, NULL } }; etype = g_enum_register_static ("GooCairoOperator", values); } return etype; } GType goo_cairo_antialias_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { { CAIRO_ANTIALIAS_DEFAULT, "CAIRO_ANTIALIAS_DEFAULT", "default" }, { CAIRO_ANTIALIAS_NONE, "CAIRO_ANTIALIAS_NONE", "none" }, { CAIRO_ANTIALIAS_GRAY, "CAIRO_ANTIALIAS_GRAY", "gray" }, { CAIRO_ANTIALIAS_SUBPIXEL, "CAIRO_ANTIALIAS_SUBPIXEL", "subpixel" }, { 0, NULL, NULL } }; etype = g_enum_register_static ("GooCairoAntialias", values); } return etype; } GType goo_cairo_line_cap_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { { CAIRO_LINE_CAP_BUTT, "CAIRO_LINE_CAP_BUTT", "butt" }, { CAIRO_LINE_CAP_ROUND, "CAIRO_LINE_CAP_ROUND", "round" }, { CAIRO_LINE_CAP_SQUARE, "CAIRO_LINE_CAP_SQUARE", "square" }, { 0, NULL, NULL } }; etype = g_enum_register_static ("GooCairoLineCap", values); } return etype; } GType goo_cairo_line_join_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { { CAIRO_LINE_JOIN_MITER, "CAIRO_LINE_JOIN_MITER", "miter" }, { CAIRO_LINE_JOIN_ROUND, "CAIRO_LINE_JOIN_ROUND", "round" }, { CAIRO_LINE_JOIN_BEVEL, "CAIRO_LINE_JOIN_BEVEL", "bevel" }, { 0, NULL, NULL } }; etype = g_enum_register_static ("GooCairoLineJoin", values); } return etype; } /** * goo_canvas_line_dash_ref: * @dash: a #GooCanvasLineDash. * * Increments the reference count of the dash pattern. * * Returns: the dash pattern. **/ GooCanvasLineDash* goo_canvas_line_dash_ref (GooCanvasLineDash *dash) { if (dash) dash->ref_count++; return dash; } /** * goo_canvas_line_dash_unref: * @dash: a #GooCanvasLineDash. * * Decrements the reference count of the dash pattern. If it falls to 0 * it is freed. **/ void goo_canvas_line_dash_unref (GooCanvasLineDash *dash) { if (dash && --dash->ref_count == 0) { g_free (dash->dashes); g_free (dash); } } GType goo_canvas_line_dash_get_type (void) { static GType cairo_line_dash_type = 0; if (cairo_line_dash_type == 0) cairo_line_dash_type = g_boxed_type_register_static ("GooCairoLineDash", (GBoxedCopyFunc) goo_canvas_line_dash_ref, (GBoxedFreeFunc) goo_canvas_line_dash_unref); return cairo_line_dash_type; } /** * goo_canvas_line_dash_new: * @num_dashes: the number of dashes and gaps in the pattern. * @...: the length of each dash and gap. * * Creates a new dash pattern. * * Returns: a new dash pattern. **/ GooCanvasLineDash* goo_canvas_line_dash_new (gint num_dashes, ...) { GooCanvasLineDash *dash; va_list var_args; gint i; dash = g_new (GooCanvasLineDash, 1); dash->ref_count = 1; dash->num_dashes = num_dashes; dash->dashes = g_new (double, num_dashes); dash->dash_offset = 0.0; va_start (var_args, num_dashes); for (i = 0; i < num_dashes; i++) { dash->dashes[i] = va_arg (var_args, double); } va_end (var_args); return dash; } /** * goo_canvas_line_dash_newv: * @num_dashes: the number of dashes and gaps in the pattern. * @dashes: a g_new-allocated vector of doubles, the length of each * dash and gap. * * Creates a new dash pattern. Takes ownership of the @dashes vector. * * Returns: a new dash pattern. **/ GooCanvasLineDash* goo_canvas_line_dash_newv (gint num_dashes, double *dashes) { GooCanvasLineDash *dash; dash = g_new (GooCanvasLineDash, 1); dash->ref_count = 1; dash->num_dashes = num_dashes; dash->dashes = dashes; dash->dash_offset = 0.0; return dash; } cairo_matrix_t* goo_cairo_matrix_copy (cairo_matrix_t *matrix) { cairo_matrix_t *matrix_copy; if (!matrix) return NULL; matrix_copy = g_new (cairo_matrix_t, 1); *matrix_copy = *matrix; return matrix_copy; } GType goo_cairo_matrix_get_type (void) { static GType type_cairo_matrix = 0; if (!type_cairo_matrix) type_cairo_matrix = g_boxed_type_register_static ("GooCairoMatrix", (GBoxedCopyFunc) goo_cairo_matrix_copy, (GBoxedFreeFunc) g_free); return type_cairo_matrix; }