mirror of https://github.com/GNOME/gimp.git
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.
This commit is contained in:
parent
ebeb933350
commit
ccee0ec41a
|
@ -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);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue