[gimp] app: completely switch to cairo-drawing the selection
- From: Michael Natterer <mitch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: completely switch to cairo-drawing the selection
- Date: Thu, 26 Aug 2010 18:54:30 +0000 (UTC)
commit be2bd189cd6d96c63e4a8a41cff98486e740ebf4
Author: Michael Natterer <mitch gimp org>
Date: Thu Aug 26 20:52:52 2010 +0200
app: completely switch to cairo-drawing the selection
and remove all old selection drawing code. Thanks to Benjamin Otte for
pointing out the right optimization.
Also fixes bug #479875 - performance problem drawing a complex selection.
app/display/gimpcanvas.c | 184 -------------------
app/display/gimpcanvas.h | 7 -
app/display/gimpdisplayshell-draw.c | 26 ++-
app/display/gimpdisplayshell-draw.h | 7 +-
app/display/gimpdisplayshell-selection.c | 289 +++---------------------------
5 files changed, 53 insertions(+), 460 deletions(-)
---
diff --git a/app/display/gimpcanvas.c b/app/display/gimpcanvas.c
index 0043ebf..9b0402d 100644
--- a/app/display/gimpcanvas.c
+++ b/app/display/gimpcanvas.c
@@ -56,7 +56,6 @@ static void gimp_canvas_get_property (GObject *object,
GValue *value,
GParamSpec *pspec);
-static void gimp_canvas_realize (GtkWidget *widget);
static void gimp_canvas_unrealize (GtkWidget *widget);
static void gimp_canvas_style_set (GtkWidget *widget,
GtkStyle *prev_style);
@@ -76,91 +75,6 @@ G_DEFINE_TYPE (GimpCanvas, gimp_canvas, GIMP_TYPE_OVERLAY_BOX)
#define parent_class gimp_canvas_parent_class
-static const guchar stipples[GIMP_CANVAS_NUM_STIPPLES][8] =
-{
- {
- 0xF0, /* ####---- */
- 0xE1, /* ###----# */
- 0xC3, /* ##----## */
- 0x87, /* #----### */
- 0x0F, /* ----#### */
- 0x1E, /* ---####- */
- 0x3C, /* --####-- */
- 0x78, /* -####--- */
- },
- {
- 0xE1, /* ###----# */
- 0xC3, /* ##----## */
- 0x87, /* #----### */
- 0x0F, /* ----#### */
- 0x1E, /* ---####- */
- 0x3C, /* --####-- */
- 0x78, /* -####--- */
- 0xF0, /* ####---- */
- },
- {
- 0xC3, /* ##----## */
- 0x87, /* #----### */
- 0x0F, /* ----#### */
- 0x1E, /* ---####- */
- 0x3C, /* --####-- */
- 0x78, /* -####--- */
- 0xF0, /* ####---- */
- 0xE1, /* ###----# */
- },
- {
- 0x87, /* #----### */
- 0x0F, /* ----#### */
- 0x1E, /* ---####- */
- 0x3C, /* --####-- */
- 0x78, /* -####--- */
- 0xF0, /* ####---- */
- 0xE1, /* ###----# */
- 0xC3, /* ##----## */
- },
- {
- 0x0F, /* ----#### */
- 0x1E, /* ---####- */
- 0x3C, /* --####-- */
- 0x78, /* -####--- */
- 0xF0, /* ####---- */
- 0xE1, /* ###----# */
- 0xC3, /* ##----## */
- 0x87, /* #----### */
- },
- {
- 0x1E, /* ---####- */
- 0x3C, /* --####-- */
- 0x78, /* -####--- */
- 0xF0, /* ####---- */
- 0xE1, /* ###----# */
- 0xC3, /* ##----## */
- 0x87, /* #----### */
- 0x0F, /* ----#### */
- },
- {
- 0x3C, /* --####-- */
- 0x78, /* -####--- */
- 0xF0, /* ####---- */
- 0xE1, /* ###----# */
- 0xC3, /* ##----## */
- 0x87, /* #----### */
- 0x0F, /* ----#### */
- 0x1E, /* ---####- */
- },
- {
- 0x78, /* -####--- */
- 0xF0, /* ####---- */
- 0xE1, /* ###----# */
- 0xC3, /* ##----## */
- 0x87, /* #----### */
- 0x0F, /* ----#### */
- 0x1E, /* ---####- */
- 0x3C, /* --####-- */
- },
-};
-
-
static void
gimp_canvas_class_init (GimpCanvasClass *klass)
{
@@ -170,7 +84,6 @@ gimp_canvas_class_init (GimpCanvasClass *klass)
object_class->set_property = gimp_canvas_set_property;
object_class->get_property = gimp_canvas_get_property;
- widget_class->realize = gimp_canvas_realize;
widget_class->unrealize = gimp_canvas_unrealize;
widget_class->style_set = gimp_canvas_style_set;
widget_class->focus_in_event = gimp_canvas_focus_in_event;
@@ -197,9 +110,6 @@ gimp_canvas_init (GimpCanvas *canvas)
for (i = 0; i < GIMP_CANVAS_NUM_STYLES; i++)
canvas->gc[i] = NULL;
-
- for (i = 0; i < GIMP_CANVAS_NUM_STIPPLES; i++)
- canvas->stipple[i] = NULL;
}
static void
@@ -241,18 +151,6 @@ gimp_canvas_get_property (GObject *object,
}
static void
-gimp_canvas_realize (GtkWidget *widget)
-{
- GimpCanvas *canvas = GIMP_CANVAS (widget);
-
- GTK_WIDGET_CLASS (parent_class)->realize (widget);
-
- canvas->stipple[0] =
- gdk_bitmap_create_from_data (gtk_widget_get_window (widget),
- (const gchar *) stipples[0], 8, 8);
-}
-
-static void
gimp_canvas_unrealize (GtkWidget *widget)
{
GimpCanvas *canvas = GIMP_CANVAS (widget);
@@ -267,15 +165,6 @@ gimp_canvas_unrealize (GtkWidget *widget)
}
}
- for (i = 0; i < GIMP_CANVAS_NUM_STIPPLES; i++)
- {
- if (canvas->stipple[i])
- {
- g_object_unref (canvas->stipple[i]);
- canvas->stipple[i] = NULL;
- }
- }
-
if (canvas->layout)
{
g_object_unref (canvas->layout);
@@ -369,10 +258,6 @@ gimp_canvas_gc_new (GimpCanvas *canvas,
switch (style)
{
- case GIMP_CANVAS_STYLE_BLACK:
- case GIMP_CANVAS_STYLE_WHITE:
- break;
-
case GIMP_CANVAS_STYLE_RENDER:
mask |= GDK_GC_EXPOSURES;
values.graphics_exposures = TRUE;
@@ -396,14 +281,6 @@ gimp_canvas_gc_new (GimpCanvas *canvas,
values.join_style = GDK_JOIN_MITER;
break;
- case GIMP_CANVAS_STYLE_SELECTION_IN:
- case GIMP_CANVAS_STYLE_SELECTION_OUT:
- mask |= GDK_GC_CAP_STYLE | GDK_GC_FILL | GDK_GC_STIPPLE;
- values.cap_style = GDK_CAP_NOT_LAST;
- values.fill = GDK_OPAQUE_STIPPLED;
- values.stipple = canvas->stipple[0];
- break;
-
default:
return NULL;
}
@@ -426,33 +303,6 @@ gimp_canvas_gc_new (GimpCanvas *canvas,
case GIMP_CANVAS_STYLE_XOR_DASHED:
case GIMP_CANVAS_STYLE_XOR:
break;
-
- case GIMP_CANVAS_STYLE_WHITE:
- fg.red = 0xffff;
- fg.green = 0xffff;
- fg.blue = 0xffff;
- break;
-
- case GIMP_CANVAS_STYLE_BLACK:
- case GIMP_CANVAS_STYLE_SELECTION_IN:
- fg.red = 0x0;
- fg.green = 0x0;
- fg.blue = 0x0;
-
- bg.red = 0xffff;
- bg.green = 0xffff;
- bg.blue = 0xffff;
- break;
-
- case GIMP_CANVAS_STYLE_SELECTION_OUT:
- fg.red = 0xffff;
- fg.green = 0xffff;
- fg.blue = 0xffff;
-
- bg.red = 0x7f7f;
- bg.green = 0x7f7f;
- bg.blue = 0x7f7f;
- break;
}
gdk_gc_set_rgb_fg_color (gc, &fg);
@@ -886,40 +736,6 @@ gimp_canvas_set_clip_region (GimpCanvas *canvas,
}
/**
- * gimp_canvas_set_stipple_index:
- * @canvas: a #GimpCanvas widget
- * @style: the #GimpCanvasStyle to alter
- * @index: the new stipple index
- *
- * Some styles of the #GimpCanvas do a stipple fill. #GimpCanvas has a
- * set of %GIMP_CANVAS_NUM_STIPPLES stipple bitmaps. This function
- * allows you to change the bitmap being used. This can be used to
- * implement a marching ants effect. An older implementation used to
- * use this feature and so it is included since it might be useful in
- * the future. All stipple bitmaps but the default one are created on
- * the fly.
- */
-void
-gimp_canvas_set_stipple_index (GimpCanvas *canvas,
- GimpCanvasStyle style,
- guint index)
-{
- if (! gimp_canvas_ensure_style (canvas, style))
- return;
-
- index = index % GIMP_CANVAS_NUM_STIPPLES;
-
- if (! canvas->stipple[index])
- {
- canvas->stipple[index] =
- gdk_bitmap_create_from_data (gtk_widget_get_window (GTK_WIDGET (canvas)),
- (const gchar *) stipples[index], 8, 8);
- }
-
- gdk_gc_set_stipple (canvas->gc[style], canvas->stipple[index]);
-}
-
-/**
* gimp_canvas_set_bg_color:
* @canvas: a #GimpCanvas widget
* @color: a color in #GimpRGB format
diff --git a/app/display/gimpcanvas.h b/app/display/gimpcanvas.h
index 52eb9db..39a037e 100644
--- a/app/display/gimpcanvas.h
+++ b/app/display/gimpcanvas.h
@@ -24,14 +24,10 @@
typedef enum
{
- GIMP_CANVAS_STYLE_BLACK,
- GIMP_CANVAS_STYLE_WHITE,
GIMP_CANVAS_STYLE_RENDER,
GIMP_CANVAS_STYLE_XOR,
GIMP_CANVAS_STYLE_XOR_DASHED,
GIMP_CANVAS_STYLE_XOR_DOTTED,
- GIMP_CANVAS_STYLE_SELECTION_IN,
- GIMP_CANVAS_STYLE_SELECTION_OUT,
GIMP_CANVAS_NUM_STYLES
} GimpCanvasStyle;
@@ -147,9 +143,6 @@ void gimp_canvas_set_clip_rect (GimpCanvas *canvas,
void gimp_canvas_set_clip_region (GimpCanvas *canvas,
GimpCanvasStyle style,
const GdkRegion *region);
-void gimp_canvas_set_stipple_index (GimpCanvas *canvas,
- GimpCanvasStyle style,
- guint index);
void gimp_canvas_set_bg_color (GimpCanvas *canvas,
GimpRGB *color);
diff --git a/app/display/gimpdisplayshell-draw.c b/app/display/gimpdisplayshell-draw.c
index 5a08c2a..6dd32aa 100644
--- a/app/display/gimpdisplayshell-draw.c
+++ b/app/display/gimpdisplayshell-draw.c
@@ -598,11 +598,10 @@ gimp_display_shell_draw_selection_out (GimpDisplayShell *shell,
}
void
-gimp_display_shell_draw_selection_in (GimpDisplayShell *shell,
- cairo_t *cr,
- GdkSegment *segs,
- gint n_segs,
- gint index)
+gimp_display_shell_draw_selection_segments (GimpDisplayShell *shell,
+ cairo_t *cr,
+ GdkSegment *segs,
+ gint n_segs)
{
gint i;
@@ -610,7 +609,7 @@ gimp_display_shell_draw_selection_in (GimpDisplayShell *shell,
g_return_if_fail (cr != NULL);
g_return_if_fail (segs != NULL && n_segs > 0);
- gimp_display_shell_set_selection_in_style (shell, cr, index);
+ cairo_set_line_width (cr, 1.0);
for (i = 0; i < n_segs; i++)
{
@@ -630,6 +629,21 @@ gimp_display_shell_draw_selection_in (GimpDisplayShell *shell,
}
void
+gimp_display_shell_draw_selection_in_mask (GimpDisplayShell *shell,
+ cairo_t *cr,
+ cairo_pattern_t *mask,
+ gint index)
+{
+ g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+ g_return_if_fail (cr != NULL);
+ g_return_if_fail (mask != NULL);
+
+ gimp_display_shell_set_selection_in_style (shell, cr, index);
+
+ cairo_mask (cr, mask);
+}
+
+void
gimp_display_shell_draw_vector (GimpDisplayShell *shell,
GimpVectors *vectors)
{
diff --git a/app/display/gimpdisplayshell-draw.h b/app/display/gimpdisplayshell-draw.h
index 8fed497..782c7fa 100644
--- a/app/display/gimpdisplayshell-draw.h
+++ b/app/display/gimpdisplayshell-draw.h
@@ -57,10 +57,13 @@ void gimp_display_shell_draw_selection_out (GimpDisplayShell *shell,
cairo_t *cr,
GdkSegment *segs,
gint n_segs);
-void gimp_display_shell_draw_selection_in (GimpDisplayShell *shell,
+void gimp_display_shell_draw_selection_segments (GimpDisplayShell *shell,
cairo_t *cr,
GdkSegment *segs,
- gint n_segs,
+ gint n_segs);
+void gimp_display_shell_draw_selection_in_mask (GimpDisplayShell *shell,
+ cairo_t *cr,
+ cairo_pattern_t *mask,
gint index);
void gimp_display_shell_draw_vector (GimpDisplayShell *shell,
GimpVectors *vectors);
diff --git a/app/display/gimpdisplayshell-selection.c b/app/display/gimpdisplayshell-selection.c
index 28b8cfd..863d220 100644
--- a/app/display/gimpdisplayshell-selection.c
+++ b/app/display/gimpdisplayshell-selection.c
@@ -41,18 +41,10 @@
#include "gimpdisplayshell-transform.h"
-#undef VERBOSE
-
-#define MAX_POINTS_INC 2048
-#define USE_DRAWPOINTS TRUE
-
-
struct _Selection
{
GimpDisplayShell *shell; /* shell that owns the selection */
- gboolean use_cairo; /* temp hack */
-
GdkSegment *segs_in; /* gdk segments of area boundary */
gint n_segs_in; /* number of segments in segs_in */
@@ -68,8 +60,7 @@ struct _Selection
gboolean hidden; /* is the selection hidden? */
gboolean layer_hidden; /* is the layer boundary hidden? */
guint timeout; /* timer for successive draws */
- GdkPoint *points_in[8]; /* points of segs_in for fast ants */
- gint num_points_in[8]; /* number of points in points_in */
+ cairo_pattern_t *segs_in_mask; /* cache for rendered segments */
};
@@ -86,12 +77,7 @@ static void selection_undraw (Selection *selection);
static void selection_layer_undraw (Selection *selection);
static void selection_layer_draw (Selection *selection);
-static void selection_add_point (GdkPoint *points[8],
- gint max_npoints[8],
- gint npoints[8],
- gint x,
- gint y);
-static void selection_render_points (Selection *selection);
+static void selection_render_mask (Selection *selection);
static void selection_transform_segs (Selection *selection,
const BoundSeg *src_segs,
@@ -124,7 +110,6 @@ gimp_display_shell_selection_init (GimpDisplayShell *shell)
selection = g_slice_new0 (Selection);
selection->shell = shell;
- selection->use_cairo = g_getenv ("CAIRO_SELECTION") != NULL;
selection->visible = TRUE;
selection->hidden = ! gimp_display_shell_get_show_selection (shell);
selection->layer_hidden = ! gimp_display_shell_get_show_layer (shell);
@@ -298,105 +283,21 @@ selection_resume (Selection *selection)
selection_start (selection);
}
-/* #define BENCHMARK 1 */
-
static void
selection_draw (Selection *selection)
{
- GimpCanvas *canvas = GIMP_CANVAS (selection->shell->canvas);
-#ifdef BENCHMARK
- GTimer *timer = g_timer_new ();
- gint test;
-
- for (test = 0; test < 20; test++)
- {
-#endif /* BENCHMARK */
- if (selection->use_cairo)
- {
- if (selection->segs_in)
- {
- cairo_t *cr;
-
- cr = gdk_cairo_create (gtk_widget_get_window (selection->shell->canvas));
-
- gimp_display_shell_draw_selection_in (selection->shell, cr,
- selection->segs_in,
- selection->n_segs_in,
- selection->index % 8);
-
- cairo_destroy (cr);
- }
- }
- else
+ if (selection->segs_in)
{
-#ifdef USE_DRAWPOINTS
-
-#ifdef VERBOSE
- {
- gint j, sum;
-
- sum = 0;
- for (j = 0; j < 8; j++)
- sum += selection->num_points_in[j];
-
- g_print ("%d segments, %d points\n", selection->n_segs_in, sum);
- }
-#endif
+ cairo_t *cr;
- if (selection->segs_in)
- {
- gint i;
-
- if (selection->index == 0)
- {
- for (i = 0; i < 4; i++)
- if (selection->num_points_in[i])
- gimp_canvas_draw_points (canvas, GIMP_CANVAS_STYLE_WHITE,
- selection->points_in[i],
- selection->num_points_in[i]);
-
- for (i = 4; i < 8; i++)
- if (selection->num_points_in[i])
- gimp_canvas_draw_points (canvas, GIMP_CANVAS_STYLE_BLACK,
- selection->points_in[i],
- selection->num_points_in[i]);
- }
- else
- {
- i = ((selection->index + 3) & 7);
- if (selection->num_points_in[i])
- gimp_canvas_draw_points (canvas, GIMP_CANVAS_STYLE_WHITE,
- selection->points_in[i],
- selection->num_points_in[i]);
-
- i = ((selection->index + 7) & 7);
- if (selection->num_points_in[i])
- gimp_canvas_draw_points (canvas, GIMP_CANVAS_STYLE_BLACK,
- selection->points_in[i],
- selection->num_points_in[i]);
- }
- }
-
-#else /* ! USE_DRAWPOINTS */
+ cr = gdk_cairo_create (gtk_widget_get_window (selection->shell->canvas));
- gimp_canvas_set_stipple_index (canvas,
- GIMP_CANVAS_STYLE_SELECTION_IN,
- selection->index);
- if (selection->segs_in)
- gimp_canvas_draw_segments (canvas, GIMP_CANVAS_STYLE_SELECTION_IN,
- selection->segs_in,
- selection->n_segs_in);
+ gimp_display_shell_draw_selection_in_mask (selection->shell, cr,
+ selection->segs_in_mask,
+ selection->index % 8);
-#endif /* USE_DRAWPOINTS */
- }
-#ifdef BENCHMARK
+ cairo_destroy (cr);
}
-
- g_printerr ("drawing 20 selections took %f seconds\n",
- g_timer_elapsed (timer, NULL));
-
- g_timer_destroy (timer);
-#endif /* BENCHMARK */
}
static void
@@ -474,137 +375,21 @@ selection_layer_undraw (Selection *selection)
}
static void
-selection_add_point (GdkPoint *points[8],
- gint max_npoints[8],
- gint npoints[8],
- gint x,
- gint y)
+selection_render_mask (Selection *selection)
{
- gint i, j;
+ cairo_t *cr;
- j = (x - y) & 7;
+ cr = gdk_cairo_create (gtk_widget_get_window (selection->shell->canvas));
- i = npoints[j]++;
- if (i == max_npoints[j])
- {
- max_npoints[j] += 2048;
- points[j] = g_realloc (points[j], sizeof (GdkPoint) * max_npoints[j]);
- }
+ cairo_push_group_with_content (cr, CAIRO_CONTENT_ALPHA);
- points[j][i].x = x;
- points[j][i].y = y;
-}
+ gimp_display_shell_draw_selection_segments (selection->shell, cr,
+ selection->segs_in,
+ selection->n_segs_in);
+ selection->segs_in_mask = cairo_pop_group (cr);
-/* Render the segs_in array into points_in */
-
-static void
-selection_render_points (Selection *selection)
-{
- gint max_npoints[8];
- gint i;
-
- if (selection->segs_in == NULL)
- return;
-
- for (i = 0; i < 8; i++)
- {
- max_npoints[i] = MAX_POINTS_INC;
- selection->points_in[i] = g_new (GdkPoint, max_npoints[i]);
- selection->num_points_in[i] = 0;
- }
-
- for (i = 0; i < selection->n_segs_in; i++)
- {
- gint x, y;
- gint dx, dy;
- gint dxa, dya;
- gint r;
-
-#ifdef VERBOSE
- g_print ("%2d: (%d, %d) - (%d, %d)\n", i,
- selection->segs_in[i].x1,
- selection->segs_in[i].y1,
- selection->segs_in[i].x2,
- selection->segs_in[i].y2);
-#endif
-
- x = selection->segs_in[i].x1;
- dxa = selection->segs_in[i].x2 - x;
-
- if (dxa > 0)
- {
- dx = 1;
- }
- else
- {
- dxa = -dxa;
- dx = -1;
- }
-
- y = selection->segs_in[i].y1;
- dya = selection->segs_in[i].y2 - y;
-
- if (dya > 0)
- {
- dy = 1;
- }
- else
- {
- dya = -dya;
- dy = -1;
- }
-
- if (dxa > dya)
- {
- r = dya;
-
- do
- {
- selection_add_point (selection->points_in,
- max_npoints,
- selection->num_points_in,
- x, y);
- x += dx;
- r += dya;
-
- if (r >= (dxa << 1))
- {
- y += dy;
- r -= (dxa << 1);
- }
- }
- while (x != selection->segs_in[i].x2);
- }
- else if (dxa < dya)
- {
- r = dxa;
-
- do
- {
- selection_add_point (selection->points_in,
- max_npoints,
- selection->num_points_in,
- x, y);
- y += dy;
- r += dxa;
-
- if (r >= (dya << 1))
- {
- x += dx;
- r -= (dya << 1);
- }
- }
- while (y != selection->segs_in[i].y2);
- }
- else
- {
- selection_add_point (selection->points_in,
- max_npoints,
- selection->num_points_in,
- x, y);
- }
- }
+ cairo_destroy (cr);
}
static void
@@ -672,9 +457,7 @@ selection_generate_segs (Selection *selection)
selection_transform_segs (selection, segs_in,
selection->segs_in, selection->n_segs_in);
-#ifdef USE_DRAWPOINTS
- selection_render_points (selection);
-#endif
+ selection_render_mask (selection);
}
else
{
@@ -718,8 +501,6 @@ selection_generate_segs (Selection *selection)
static void
selection_free_segs (Selection *selection)
{
- gint j;
-
if (selection->segs_in)
{
g_free (selection->segs_in);
@@ -741,14 +522,10 @@ selection_free_segs (Selection *selection)
selection->n_segs_layer = 0;
}
- for (j = 0; j < 8; j++)
+ if (selection->segs_in_mask)
{
- if (selection->points_in[j])
- {
- g_free (selection->points_in[j]);
- selection->points_in[j] = NULL;
- selection->num_points_in[j] = 0;
- }
+ cairo_pattern_destroy (selection->segs_in_mask);
+ selection->segs_in_mask = NULL;
}
}
@@ -771,31 +548,21 @@ selection_start_timeout (Selection *selection)
/* Draw the ants */
if (! selection->hidden)
{
- GimpCanvas *canvas = GIMP_CANVAS (selection->shell->canvas);
GimpDisplayConfig *config = selection->shell->display->config;
selection_draw (selection);
if (selection->segs_out)
{
- if (selection->use_cairo)
- {
- cairo_t *cr;
+ cairo_t *cr;
- cr = gdk_cairo_create (gtk_widget_get_window (selection->shell->canvas));
+ cr = gdk_cairo_create (gtk_widget_get_window (selection->shell->canvas));
- gimp_display_shell_draw_selection_out (selection->shell, cr,
- selection->segs_out,
- selection->n_segs_out);
+ gimp_display_shell_draw_selection_out (selection->shell, cr,
+ selection->segs_out,
+ selection->n_segs_out);
- cairo_destroy (cr);
- }
- else
- {
- gimp_canvas_draw_segments (canvas, GIMP_CANVAS_STYLE_SELECTION_OUT,
- selection->segs_out,
- selection->n_segs_out);
- }
+ cairo_destroy (cr);
}
if (selection->segs_in && selection->visible)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]