app: port GimpDisplayShell selection drawing to cairo

but keep the old code around because it's much faster. The new code is
enabled by defining the CAIRO_SELECTION environment variable.
This commit is contained in:
Michael Natterer 2010-08-26 18:09:33 +02:00
parent f1d89f712d
commit 58db8a3ef0
5 changed files with 264 additions and 75 deletions

View file

@ -565,6 +565,69 @@ gimp_display_shell_draw_layer_boundary (GimpDisplayShell *shell,
cairo_stroke (cr);
}
void
gimp_display_shell_draw_selection_out (GimpDisplayShell *shell,
cairo_t *cr,
GdkSegment *segs,
gint n_segs)
{
gint i;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
g_return_if_fail (cr != NULL);
g_return_if_fail (segs != NULL && n_segs > 0);
gimp_display_shell_set_selection_out_style (shell, cr);
for (i = 0; i < n_segs; i++)
{
if (segs[i].x1 == segs[i].x2)
{
cairo_move_to (cr, segs[i].x1 + 0.5, segs[i].y1);
cairo_line_to (cr, segs[i].x2 + 0.5, segs[i].y2);
}
else
{
cairo_move_to (cr, segs[i].x1, segs[i].y1 + 0.5);
cairo_line_to (cr, segs[i].x2, segs[i].y2 + 0.5);
}
}
cairo_stroke (cr);
}
void
gimp_display_shell_draw_selection_in (GimpDisplayShell *shell,
cairo_t *cr,
GdkSegment *segs,
gint n_segs,
gint index)
{
gint i;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (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);
for (i = 0; i < n_segs; i++)
{
if (segs[i].x1 == segs[i].x2)
{
cairo_move_to (cr, segs[i].x1 + 0.5, segs[i].y1);
cairo_line_to (cr, segs[i].x2 + 0.5, segs[i].y2);
}
else
{
cairo_move_to (cr, segs[i].x1, segs[i].y1 + 0.5);
cairo_line_to (cr, segs[i].x2, segs[i].y2 + 0.5);
}
}
cairo_stroke (cr);
}
void
gimp_display_shell_draw_vector (GimpDisplayShell *shell,
GimpVectors *vectors)

View file

@ -53,6 +53,15 @@ void gimp_display_shell_draw_layer_boundary (GimpDisplayShell *shell,
GimpDrawable *drawable,
GdkSegment *segs,
gint n_segs);
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,
cairo_t *cr,
GdkSegment *segs,
gint n_segs,
gint index);
void gimp_display_shell_draw_vector (GimpDisplayShell *shell,
GimpVectors *vectors);
void gimp_display_shell_draw_vectors (GimpDisplayShell *shell);

View file

@ -51,6 +51,8 @@ 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 */
@ -122,6 +124,7 @@ 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);
@ -295,70 +298,105 @@ 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
{
#ifdef USE_DRAWPOINTS
#ifdef VERBOSE
{
gint j, sum;
{
gint j, sum;
sum = 0;
for (j = 0; j < 8; j++)
sum += selection->num_points_in[j];
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);
}
g_print ("%d segments, %d points\n", selection->n_segs_in, sum);
}
#endif
if (selection->segs_in)
{
gint i;
if (selection->index == 0)
if (selection->segs_in)
{
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]);
gint 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]);
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]);
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]);
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 */
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_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);
#endif /* USE_DRAWPOINTS */
}
#ifdef BENCHMARK
}
g_printerr ("drawing 20 selections took %f seconds\n",
g_timer_elapsed (timer, NULL));
g_timer_destroy (timer);
#endif /* BENCHMARK */
}
static void
@ -739,10 +777,26 @@ selection_start_timeout (Selection *selection)
selection_draw (selection);
if (selection->segs_out)
gimp_canvas_draw_segments (canvas, GIMP_CANVAS_STYLE_SELECTION_OUT,
selection->segs_out,
selection->n_segs_out);
{
if (selection->use_cairo)
{
cairo_t *cr;
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);
cairo_destroy (cr);
}
else
{
gimp_canvas_draw_segments (canvas, GIMP_CANVAS_STYLE_SELECTION_OUT,
selection->segs_out,
selection->n_segs_out);
}
}
if (selection->segs_in && selection->visible)
selection->timeout = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,

View file

@ -20,6 +20,8 @@
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
@ -53,12 +55,19 @@ static const GimpRGB layer_group_bg = { 0.0, 1.0, 1.0, 1.0 };
static const GimpRGB layer_mask_fg = { 0.0, 0.0, 0.0, 1.0 };
static const GimpRGB layer_mask_bg = { 0.0, 1.0, 0.0, 1.0 };
static const GimpRGB selection_out_fg = { 1.0, 1.0, 1.0, 1.0 };
static const GimpRGB selection_out_bg = { 0.5, 0.5, 0.5, 1.0 };
static const GimpRGB selection_in_fg = { 0.0, 0.0, 0.0, 1.0 };
static const GimpRGB selection_in_bg = { 1.0, 1.0, 1.0, 1.0 };
/* local function prototypes */
static void gimp_display_shell_set_stipple_style (cairo_t *cr,
const GimpRGB *fg,
const GimpRGB *bg);
const GimpRGB *bg,
gint index);
/* public functions */
@ -76,11 +85,13 @@ gimp_display_shell_set_guide_style (GimpDisplayShell *shell,
if (active)
gimp_display_shell_set_stipple_style (cr,
&guide_active_fg,
&guide_active_bg);
&guide_active_bg,
0);
else
gimp_display_shell_set_stipple_style (cr,
&guide_normal_fg,
&guide_normal_bg);
&guide_normal_bg,
0);
}
void
@ -124,7 +135,8 @@ gimp_display_shell_set_grid_style (GimpDisplayShell *shell,
{
gimp_display_shell_set_stipple_style (cr,
&grid->fgcolor,
&grid->bgcolor);
&grid->bgcolor,
0);
}
else
{
@ -132,7 +144,8 @@ gimp_display_shell_set_grid_style (GimpDisplayShell *shell,
gimp_display_shell_set_stipple_style (cr,
&grid->fgcolor,
&bg);
&bg,
0);
}
break;
@ -205,22 +218,56 @@ gimp_display_shell_set_layer_style (GimpDisplayShell *shell,
{
gimp_display_shell_set_stipple_style (cr,
&layer_mask_fg,
&layer_mask_bg);
&layer_mask_bg,
0);
}
else if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
{
gimp_display_shell_set_stipple_style (cr,
&layer_group_fg,
&layer_group_bg);
&layer_group_bg,
0);
}
else
{
gimp_display_shell_set_stipple_style (cr,
&layer_fg,
&layer_bg);
&layer_bg,
0);
}
}
void
gimp_display_shell_set_selection_out_style (GimpDisplayShell *shell,
cairo_t *cr)
{
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
g_return_if_fail (cr != NULL);
cairo_set_line_width (cr, 1.0);
gimp_display_shell_set_stipple_style (cr,
&selection_out_fg,
&selection_out_bg,
0);
}
void
gimp_display_shell_set_selection_in_style (GimpDisplayShell *shell,
cairo_t *cr,
gint index)
{
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
g_return_if_fail (cr != NULL);
cairo_set_line_width (cr, 1.0);
gimp_display_shell_set_stipple_style (cr,
&selection_in_fg,
&selection_in_bg,
index);
}
/* private functions */
@ -229,7 +276,8 @@ static cairo_user_data_key_t surface_data_key = { 0, };
static void
gimp_display_shell_set_stipple_style (cairo_t *cr,
const GimpRGB *fg,
const GimpRGB *bg)
const GimpRGB *bg,
gint index)
{
cairo_surface_t *surface;
guchar *data = g_malloc0 (8 * 8 * 4);
@ -247,7 +295,7 @@ gimp_display_shell_set_stipple_style (cairo_t *cr,
{
for (x = 0; x < 8; x++)
{
if ((y < 4 && x < 4) || (y >= 4 && x >= 4))
if ((x + y + index) % 8 >= 4)
GIMP_CAIRO_ARGB32_SET_PIXEL (d, fg_r, fg_g, fg_b, fg_a);
else
GIMP_CAIRO_ARGB32_SET_PIXEL (d, bg_r, bg_g, bg_b, bg_a);
@ -256,6 +304,16 @@ gimp_display_shell_set_stipple_style (cairo_t *cr,
}
}
if (FALSE)//index > 0)
{
gint move = index * 4;
guchar *buf = g_alloca (8 * 8 * 4);
memcpy (buf, data, 8 * 8 * 4);
memcpy (data, buf + 8 * 8 * 4 - move, move);
memcpy (data + move, buf, 8 * 8 * 4 - move);
}
surface = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_ARGB32,
8, 8, 8 * 4);

View file

@ -22,25 +22,30 @@
#define __GIMP_DISPLAY_SHELL_STYLE_H__
void gimp_display_shell_set_guide_style (GimpDisplayShell *shell,
cairo_t *cr,
gboolean active);
void gimp_display_shell_set_sample_point_style (GimpDisplayShell *shell,
cairo_t *cr,
gboolean active);
void gimp_display_shell_set_grid_style (GimpDisplayShell *shell,
cairo_t *cr,
GimpGrid *grid);
void gimp_display_shell_set_cursor_style (GimpDisplayShell *shell,
cairo_t *cr);
void gimp_display_shell_set_pen_style (GimpDisplayShell *shell,
cairo_t *cr,
GimpContext *context,
GimpActiveColor active,
gint width);
void gimp_display_shell_set_layer_style (GimpDisplayShell *shell,
cairo_t *cr,
GimpDrawable *drawable);
void gimp_display_shell_set_guide_style (GimpDisplayShell *shell,
cairo_t *cr,
gboolean active);
void gimp_display_shell_set_sample_point_style (GimpDisplayShell *shell,
cairo_t *cr,
gboolean active);
void gimp_display_shell_set_grid_style (GimpDisplayShell *shell,
cairo_t *cr,
GimpGrid *grid);
void gimp_display_shell_set_cursor_style (GimpDisplayShell *shell,
cairo_t *cr);
void gimp_display_shell_set_pen_style (GimpDisplayShell *shell,
cairo_t *cr,
GimpContext *context,
GimpActiveColor active,
gint width);
void gimp_display_shell_set_layer_style (GimpDisplayShell *shell,
cairo_t *cr,
GimpDrawable *drawable);
void gimp_display_shell_set_selection_out_style (GimpDisplayShell *shell,
cairo_t *cr);
void gimp_display_shell_set_selection_in_style (GimpDisplayShell *shell,
cairo_t *cr,
gint index);
#endif /* __GIMP_DISPLAY_SHELL_STYLE_H__ */