From ccee0ec41a37727115e73d919e0c2a34ffae8f20 Mon Sep 17 00:00:00 2001 From: Sven Neumann Date: Tue, 28 Sep 2010 21:10:03 +0200 Subject: [PATCH] app/display: let cairo render the checkerboard Instead of blending the scaled image data onto the checkerboard and then painting this image to the screen, render the image data into an ARGB cairo image surface. Then paint a checkerboard on the canvas and the image on top of it. --- app/display/gimpdisplayshell-callbacks.c | 8 ++ app/display/gimpdisplayshell-draw.c | 46 +++++++++ app/display/gimpdisplayshell-draw.h | 6 ++ app/display/gimpdisplayshell-handlers.c | 6 ++ app/display/gimpdisplayshell-render.c | 123 ++++------------------- app/display/gimpdisplayshell.c | 8 +- app/display/gimpdisplayshell.h | 1 + 7 files changed, 91 insertions(+), 107 deletions(-) diff --git a/app/display/gimpdisplayshell-callbacks.c b/app/display/gimpdisplayshell-callbacks.c index dbd1dc3e70..61926891e0 100644 --- a/app/display/gimpdisplayshell-callbacks.c +++ b/app/display/gimpdisplayshell-callbacks.c @@ -2285,6 +2285,14 @@ gimp_display_shell_canvas_expose_image (GimpDisplayShell *shell, if (! gdk_region_empty (image_region)) { + cairo_save (cr); + gimp_display_shell_draw_checkerboard (shell, cr, + image_rect.x, + image_rect.y, + image_rect.width, + image_rect.height); + cairo_restore (cr); + gdk_region_get_rectangles (image_region, &rects, &n_rects); cairo_save (cr); diff --git a/app/display/gimpdisplayshell-draw.c b/app/display/gimpdisplayshell-draw.c index 5c67580127..8131898752 100644 --- a/app/display/gimpdisplayshell-draw.c +++ b/app/display/gimpdisplayshell-draw.c @@ -21,6 +21,7 @@ #include #include "libgimpbase/gimpbase.h" +#include "libgimpcolor/gimpcolor.h" #include "libgimpmath/gimpmath.h" #include "libgimpwidgets/gimpwidgets.h" @@ -750,3 +751,48 @@ gimp_display_shell_draw_area (GimpDisplayShell *shell, } } } + +static cairo_pattern_t * +gimp_display_shell_create_checkerboard (GimpDisplayShell *shell, + cairo_t *cr) +{ + GimpCheckSize check_size; + GimpCheckType check_type; + guchar check_light; + guchar check_dark; + GimpRGB light; + GimpRGB dark; + + g_object_get (shell->display->config, + "transparency-size", &check_size, + "transparency-type", &check_type, + NULL); + + gimp_checks_get_shades (check_type, &check_light, &check_dark); + gimp_rgb_set_uchar (&light, check_light, check_light, check_light); + gimp_rgb_set_uchar (&dark, check_dark, check_dark, check_dark); + + return gimp_cairo_checkerboard_create (cr, + 1 << (check_size + 2), &light, &dark); +} + +void +gimp_display_shell_draw_checkerboard (GimpDisplayShell *shell, + cairo_t *cr, + gint x, + gint y, + gint w, + gint h) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (cr != NULL); + + if (G_UNLIKELY (! shell->checkerboard)) + shell->checkerboard = gimp_display_shell_create_checkerboard (shell, cr); + + cairo_rectangle (cr, x, y, w, h); + cairo_clip (cr); + cairo_translate (cr, - shell->offset_x, - shell->offset_y); + cairo_set_source (cr, shell->checkerboard); + cairo_paint (cr); +} diff --git a/app/display/gimpdisplayshell-draw.h b/app/display/gimpdisplayshell-draw.h index 0baff69a98..8561458638 100644 --- a/app/display/gimpdisplayshell-draw.h +++ b/app/display/gimpdisplayshell-draw.h @@ -71,6 +71,12 @@ void gimp_display_shell_draw_area (GimpDisplayShell *shell, gint y, gint w, gint h); +void gimp_display_shell_draw_checkerboard (GimpDisplayShell *shell, + cairo_t *cr, + gint x, + gint y, + gint w, + gint h); #endif /* __GIMP_DISPLAY_SHELL_DRAW_H__ */ diff --git a/app/display/gimpdisplayshell-handlers.c b/app/display/gimpdisplayshell-handlers.c index f080b74b84..ff65d8b669 100644 --- a/app/display/gimpdisplayshell-handlers.c +++ b/app/display/gimpdisplayshell-handlers.c @@ -592,6 +592,12 @@ gimp_display_shell_check_notify_handler (GObject *config, GimpCanvasPaddingMode padding_mode; GimpRGB padding_color; + if (shell->checkerboard) + { + cairo_pattern_destroy (shell->checkerboard); + shell->checkerboard = NULL; + } + gimp_display_shell_get_padding (shell, &padding_mode, &padding_color); switch (padding_mode) diff --git a/app/display/gimpdisplayshell-render.c b/app/display/gimpdisplayshell-render.c index b229ed0c58..26c8d66d50 100644 --- a/app/display/gimpdisplayshell-render.c +++ b/app/display/gimpdisplayshell-render.c @@ -74,7 +74,6 @@ struct _RenderInfo gdouble scaley; gint src_x; gint src_y; - gint dest_bpp; gint dest_bpl; gint zoom_quality; @@ -102,17 +101,7 @@ static void gimp_display_shell_render_info_scale (RenderInfo *info, gint level, gboolean is_premult); -static void gimp_display_shell_render_setup_notify (GObject *config, - GParamSpec *param_spec, - Gimp *gimp); - - -static guchar *tile_buf = NULL; - -static guint check_mod = 0; -static guint check_shift = 0; -static guchar check_dark = 0; -static guchar check_light = 0; +static guchar *tile_buf = NULL; void @@ -121,17 +110,8 @@ gimp_display_shell_render_init (Gimp *gimp) g_return_if_fail (GIMP_IS_GIMP (gimp)); g_return_if_fail (tile_buf == NULL); - g_signal_connect (gimp->config, "notify::transparency-size", - G_CALLBACK (gimp_display_shell_render_setup_notify), - gimp); - g_signal_connect (gimp->config, "notify::transparency-type", - G_CALLBACK (gimp_display_shell_render_setup_notify), - gimp); - /* allocate a buffer for arranging information from a row of tiles */ tile_buf = g_new (guchar, GIMP_DISPLAY_RENDER_BUF_WIDTH * MAX_CHANNELS); - - gimp_display_shell_render_setup_notify (G_OBJECT (gimp->config), NULL, gimp); } void @@ -139,10 +119,6 @@ gimp_display_shell_render_exit (Gimp *gimp) { g_return_if_fail (GIMP_IS_GIMP (gimp)); - g_signal_handlers_disconnect_by_func (gimp->config, - gimp_display_shell_render_setup_notify, - gimp); - if (tile_buf) { g_free (tile_buf); @@ -150,40 +126,6 @@ gimp_display_shell_render_exit (Gimp *gimp) } } -static void -gimp_display_shell_render_setup_notify (GObject *config, - GParamSpec *param_spec, - Gimp *gimp) -{ - GimpCheckSize check_size; - GimpCheckType check_type; - - g_object_get (config, - "transparency-size", &check_size, - "transparency-type", &check_type, - NULL); - - gimp_checks_get_shades (check_type, &check_light, &check_dark); - - switch (check_size) - { - case GIMP_CHECK_SIZE_SMALL_CHECKS: - check_mod = 0x3; - check_shift = 2; - break; - - case GIMP_CHECK_SIZE_MEDIUM_CHECKS: - check_mod = 0x7; - check_shift = 3; - break; - - case GIMP_CHECK_SIZE_LARGE_CHECKS: - check_mod = 0xf; - check_shift = 4; - break; - } -} - /* Render Image functions */ @@ -248,7 +190,6 @@ gimp_display_shell_render (GimpDisplayShell *shell, info.w = w; info.h = h; - info.dest_bpp = 4; info.dest_bpl = cairo_image_surface_get_stride (shell->render_surface); switch (shell->display->config->zoom_quality) @@ -303,6 +244,7 @@ gimp_display_shell_render (GimpDisplayShell *shell, 3 * GIMP_DISPLAY_RENDER_BUF_WIDTH); #endif +#if 0 /* dim pixels outside the highlighted rectangle */ if (highlight) { @@ -317,6 +259,7 @@ gimp_display_shell_render (GimpDisplayShell *shell, gimp_display_shell_render_mask (shell, &info); } +#endif cairo_surface_mark_dirty (shell->render_surface); @@ -325,11 +268,11 @@ gimp_display_shell_render (GimpDisplayShell *shell, gint disp_xoffset, disp_yoffset; gimp_display_shell_scroll_get_disp_offset (shell, - &disp_xoffset, &disp_yoffset); + &disp_xoffset, &disp_yoffset); + cairo_rectangle (cr, x + disp_xoffset, y + disp_yoffset, w, h); cairo_set_source_surface (cr, shell->render_surface, x + disp_xoffset, y + disp_yoffset); - cairo_rectangle (cr, x + disp_xoffset, y + disp_yoffset, w, h); cairo_fill (cr); } } @@ -437,12 +380,12 @@ gimp_display_shell_render_mask (GimpDisplayShell *shell, while (TRUE) { const guchar *src = info->src; - guchar *dest = info->dest; + guint32 *dest = (guint32 *) info->dest; switch (shell->mask_color) { case GIMP_RED_CHANNEL: - for (x = info->x; x < xe; x++, src++, dest += info->dest_bpp) + for (x = info->x; x < xe; x++, src++, dest += 4) { if (*src & 0x80) continue; @@ -453,7 +396,7 @@ gimp_display_shell_render_mask (GimpDisplayShell *shell, break; case GIMP_GREEN_CHANNEL: - for (x = info->x; x < xe; x++, src++, dest += info->dest_bpp) + for (x = info->x; x < xe; x++, src++, dest += 4) { if (*src & 0x80) continue; @@ -464,7 +407,7 @@ gimp_display_shell_render_mask (GimpDisplayShell *shell, break; case GIMP_BLUE_CHANNEL: - for (x = info->x; x < xe; x++, src++, dest += info->dest_bpp) + for (x = info->x; x < xe; x++, src++, dest += 4) { if (*src & 0x80) continue; @@ -512,24 +455,12 @@ render_image_gray_a (RenderInfo *info) while (TRUE) { const guchar *src = info->src; - guchar *dest = info->dest; - guint dark_light; + guint32 *dest = (guint32 *) info->dest; - dark_light = (y >> check_shift) + (info->x >> check_shift); - - for (x = info->x; x < xe; x++, src += 2, dest += info->dest_bpp) + for (x = info->x; x < xe; x++, src += 2, dest++) { - guint v; - - if (dark_light & 0x1) - v = ((src[0] << 8) + check_dark * (256 - src[1])) >> 8; - else - v = ((src[0] << 8) + check_light * (256 - src[1])) >> 8; - - GIMP_CAIRO_RGB24_SET_PIXEL (dest, v, v, v); - - if (((x + 1) & check_mod) == 0) - dark_light += 1; + /* data in src is premultiplied already */ + *dest = (src[1] << 24) | (src[0] << 16) | (src[0] << 8) | src[0]; } if (++y == ye) @@ -561,32 +492,12 @@ render_image_rgb_a (RenderInfo *info) while (TRUE) { const guchar *src = info->src; - guchar *dest = info->dest; - guint dark_light; + guint32 *dest = (guint32 *) info->dest; - dark_light = (y >> check_shift) + (info->x >> check_shift); - - for (x = info->x; x < xe; x++, src += 4, dest += info->dest_bpp) + for (x = info->x; x < xe; x++, src += 4, dest++) { - guint r, g, b; - - if (dark_light & 0x1) - { - r = ((src[0] << 8) + check_dark * (256 - src[3])) >> 8; - g = ((src[1] << 8) + check_dark * (256 - src[3])) >> 8; - b = ((src[2] << 8) + check_dark * (256 - src[3])) >> 8; - } - else - { - r = ((src[0] << 8) + check_light * (256 - src[3])) >> 8; - g = ((src[1] << 8) + check_light * (256 - src[3])) >> 8; - b = ((src[2] << 8) + check_light * (256 - src[3])) >> 8; - } - - GIMP_CAIRO_RGB24_SET_PIXEL (dest, r, g, b); - - if (((x + 1) & check_mod) == 0) - dark_light += 1; + /* data in src is premultiplied already */ + *dest = (src[3] << 24) | (src[0] << 16) | (src[1] << 8) | src[2]; } if (++y == ye) diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c index 8b283dc6f8..0ceeb7f589 100644 --- a/app/display/gimpdisplayshell.c +++ b/app/display/gimpdisplayshell.c @@ -286,7 +286,7 @@ gimp_display_shell_init (GimpDisplayShell *shell) shell->x_src_dec = 1; shell->y_src_dec = 1; - shell->render_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + shell->render_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, GIMP_DISPLAY_RENDER_BUF_WIDTH, GIMP_DISPLAY_RENDER_BUF_HEIGHT); @@ -769,6 +769,12 @@ gimp_display_shell_dispose (GObject *object) shell->render_surface = NULL; } + if (shell->checkerboard) + { + cairo_pattern_destroy (shell->checkerboard); + shell->checkerboard = NULL; + } + if (shell->highlight) { g_slice_free (GdkRectangle, shell->highlight); diff --git a/app/display/gimpdisplayshell.h b/app/display/gimpdisplayshell.h index 3b3d313594..e990352ac9 100644 --- a/app/display/gimpdisplayshell.h +++ b/app/display/gimpdisplayshell.h @@ -132,6 +132,7 @@ struct _GimpDisplayShell GtkWidget *statusbar; /* statusbar */ cairo_surface_t *render_surface; /* buffer for rendering the image */ + cairo_pattern_t *checkerboard; /* checkerboard pattern */ guint title_idle_id; /* title update idle ID */ gchar *title; /* current title */