diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2011-06-19 09:01:29 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2011-06-19 09:01:29 +0000 |
| commit | f6dba310bc22dc65845e0cd0743594545e356a59 (patch) | |
| tree | 13095cd94d89c5ea9d1a2bc47d019aefa5d2ffe9 /src | |
| parent | Fixed font problem on win32. (diff) | |
| download | inkscape-f6dba310bc22dc65845e0cd0743594545e356a59.tar.gz inkscape-f6dba310bc22dc65845e0cd0743594545e356a59.zip | |
Fix rendering of control points
(bzr r9508.1.88)
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/cairo-utils.cpp | 129 | ||||
| -rw-r--r-- | src/display/cairo-utils.h | 6 | ||||
| -rw-r--r-- | src/display/sodipodi-ctrl.cpp | 361 | ||||
| -rw-r--r-- | src/display/sodipodi-ctrl.h | 2 |
4 files changed, 273 insertions, 225 deletions
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index adf5dcb9a..90f65c33e 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -555,6 +555,62 @@ ink_cairo_pattern_create_checkerboard() return p; } +/* The following two functions use "from" instead of "to", because when you write: + val1 = argb32_from_pixbuf(val1); + the name of the format is closer to the value in that format. */ + +guint32 argb32_from_pixbuf(guint32 c) +{ + guint32 o = 0; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + guint32 a = (c & 0xff000000) >> 24; +#else + guint32 a = (c & 0x000000ff); +#endif + if (a != 0) { + // extract color components +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + guint32 r = (c & 0x000000ff); + guint32 g = (c & 0x0000ff00) >> 8; + guint32 b = (c & 0x00ff0000) >> 16; +#else + guint32 r = (c & 0xff000000) >> 24; + guint32 g = (c & 0x00ff0000) >> 16; + guint32 b = (c & 0x0000ff00) >> 8; +#endif + // premultiply + r = premul_alpha(r, a); + b = premul_alpha(b, a); + g = premul_alpha(g, a); + // combine into output + o = (a << 24) | (r << 16) | (g << 8) | (b); + } + return o; +} + +guint32 pixbuf_from_argb32(guint32 c) +{ + guint32 a = (c & 0xff000000) >> 24; + if (a == 0) return 0; + + // extract color components + guint32 r = (c & 0x00ff0000) >> 16; + guint32 g = (c & 0x0000ff00) >> 8; + guint32 b = (c & 0x000000ff); + // unpremultiply; adding a/2 gives correct rounding + // (taken from Cairo sources) + r = (r * 255 + a/2) / a; + b = (b * 255 + a/2) / a; + g = (g * 255 + a/2) / a; + // combine into output +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + guint32 o = (r) | (g << 8) | (b << 16) | (a << 24); +#else + guint32 o = (r << 24) | (g << 16) | (b << 8) | (a); +#endif + return o; +} + /** * @brief Convert pixel data from GdkPixbuf format to ARGB. * This will convert pixel data from GdkPixbuf format to Cairo's native pixel format. @@ -565,38 +621,11 @@ ink_cairo_pattern_create_checkerboard() void convert_pixels_pixbuf_to_argb32(guchar *data, int w, int h, int stride) { - // TODO: optimize until it squeaks. - guint32 *ipx = reinterpret_cast<guint32*>(data); - for (int i = 0; i < h; ++i) { + guint32 *px = reinterpret_cast<guint32*>(data + i*stride); for (int j = 0; j < w; ++j) { - int index = i * stride / 4 + j; - guint32 c = ipx[index]; - guint32 o = 0; -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - guint32 a = (c & 0xff000000) >> 24; -#else - guint32 a = (c & 0x000000ff); -#endif - if (a != 0) { - // extract color components -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - guint32 r = (c & 0x000000ff); - guint32 g = (c & 0x0000ff00) >> 8; - guint32 b = (c & 0x00ff0000) >> 16; -#else - guint32 r = (c & 0xff000000) >> 24; - guint32 g = (c & 0x00ff0000) >> 16; - guint32 b = (c & 0x0000ff00) >> 8; -#endif - // premultiply - r = premul_alpha(r, a); - b = premul_alpha(b, a); - g = premul_alpha(g, a); - // combine into output - o = (a << 24) | (r << 16) | (g << 8) | (b); - } - ipx[index] = o; + *px = argb32_from_pixbuf(*px); + ++px; } } } @@ -609,32 +638,11 @@ convert_pixels_pixbuf_to_argb32(guchar *data, int w, int h, int stride) void convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int stride) { - // TODO: optimize until it squeaks. - guint32 *ipx = reinterpret_cast<guint32*>(data); for (int i = 0; i < h; ++i) { + guint32 *px = reinterpret_cast<guint32*>(data + i*stride); for (int j = 0; j < w; ++j) { - int index = i * stride / 4 + j; - guint32 c = ipx[index]; - guint32 o = 0; - guint32 a = (c & 0xff000000) >> 24; - if (a != 0) { - // extract color components - guint32 r = (c & 0x00ff0000) >> 16; - guint32 g = (c & 0x0000ff00) >> 8; - guint32 b = (c & 0x000000ff); - // unpremultiply; adding a/2 gives correct rounding - // (taken from Cairo sources) - r = (r * 255 + a/2) / a; - b = (b * 255 + a/2) / a; - g = (g * 255 + a/2) / a; - // combine into output -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - o = (r) | (g << 8) | (b << 16) | (a << 24); -#else - o = (r << 24) | (g << 16) | (b << 8) | (a); -#endif - } - ipx[index] = o; + *px = pixbuf_from_argb32(*px); + ++px; } } } @@ -642,7 +650,7 @@ convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int stride) /** * @brief Converts GdkPixbuf's data to premultiplied ARGB. * This function will convert a GdkPixbuf in place into Cairo's native pixel format. - * Note that this is a hack intended to save memory. When the pixbuf is Cairo's format, + * Note that this is a hack intended to save memory. When the pixbuf is in Cairo's format, * using it with GTK will result in corrupted drawings. */ void @@ -669,6 +677,17 @@ convert_pixbuf_argb32_to_normal(GdkPixbuf *pb) gdk_pixbuf_get_rowstride(pb)); } +guint32 argb32_from_rgba(guint32 in) +{ + guint32 r, g, b, a; + a = (in & 0x000000ff); + r = premul_alpha((in & 0xff000000) >> 24, a); + g = premul_alpha((in & 0x00ff0000) >> 16, a); + b = premul_alpha((in & 0x0000ff00) >> 8, a); + ASSEMBLE_ARGB32(px, a, r, g, b) + return px; +} + /* Local Variables: mode:c++ diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h index 1ad3c0b46..0c2ac2dd6 100644 --- a/src/display/cairo-utils.h +++ b/src/display/cairo-utils.h @@ -107,6 +107,12 @@ void convert_pixbuf_normal_to_argb32(GdkPixbuf *); void convert_pixbuf_argb32_to_normal(GdkPixbuf *); cairo_surface_t *ink_cairo_surface_create_for_argb32_pixbuf(GdkPixbuf *pb); +G_GNUC_CONST guint32 argb32_from_pixbuf(guint32 in); +G_GNUC_CONST guint32 pixbuf_from_argb32(guint32 in); +/** Convert a pixel in 0xRRGGBBAA format to Cairo ARGB32 format. */ +G_GNUC_CONST guint32 argb32_from_rgba(guint32 in); + + G_GNUC_CONST inline guint32 premul_alpha(guint32 color, guint32 alpha) { diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index a165fd52e..5e939ffee 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -125,7 +125,7 @@ sp_ctrl_destroy (GtkObject *object) ctrl = SP_CTRL (object); if (ctrl->cache) { - g_free(ctrl->cache); + delete[] ctrl->cache; ctrl->cache = NULL; } @@ -176,9 +176,7 @@ sp_ctrl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) break; case ARG_FILL_COLOR: { - // treat colors with zero alpha as opaque guint32 fill = GTK_VALUE_INT (*arg); - fill = ((fill & 0xff) == 0 && fill) ? fill | 0xff : fill; ctrl->fill_color = fill; ctrl->build = FALSE; sp_canvas_item_request_update (item); @@ -191,9 +189,7 @@ sp_ctrl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) break; case ARG_STROKE_COLOR: { - // treat colors with zero alpha as opaque guint32 stroke = GTK_VALUE_INT (*arg); - stroke = ((stroke & 0xff) == 0 && stroke) ? stroke | 0xff : stroke; ctrl->stroke_color = stroke; ctrl->build = FALSE; sp_canvas_item_request_update (item); @@ -303,101 +299,162 @@ sp_ctrl_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item) static void sp_ctrl_build_cache (SPCtrl *ctrl) { - //guchar * p, *q; - //int size, x, y, z, s, a, side, c; - //guint8 fr, fg, fb, fa, sr, sg, sb, sa; - - /*if (ctrl->filled) { - fr = (ctrl->fill_color >> 24) & 0xff; - fg = (ctrl->fill_color >> 16) & 0xff; - fb = (ctrl->fill_color >> 8) & 0xff; - fa = (ctrl->fill_color) & 0xff; + guint32 *p, *q; + gint size, x, y, z, s, a, side, c; + guint32 stroke_color, fill_color; + + if (ctrl->filled) { + if (ctrl->mode == SP_CTRL_MODE_XOR) { + fill_color = ctrl->fill_color; + } else { + fill_color = argb32_from_rgba(ctrl->fill_color); + } } else { - fr = 0x00; fg = 0x00; fb = 0x00; fa = 0x00; + fill_color = 0; } if (ctrl->stroked) { - sr = (ctrl->stroke_color >> 24) & 0xff; - sg = (ctrl->stroke_color >> 16) & 0xff; - sb = (ctrl->stroke_color >> 8) & 0xff; - sa = (ctrl->stroke_color) & 0xff; + if (ctrl->mode == SP_CTRL_MODE_XOR) { + stroke_color = ctrl->stroke_color; + } else { + stroke_color = argb32_from_rgba(ctrl->stroke_color); + } } else { - sr = fr; sg = fg; sb = fb; sa = fa; - }*/ + stroke_color = fill_color; + } - int w, h; // for clarity; w and h are always odd - w = h = (ctrl->span * 2 +1); - int c = ctrl->span ; - if (ctrl->cache) { - cairo_surface_finish(ctrl->cache); - cairo_surface_destroy(ctrl->cache); - } - ctrl->cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); - cairo_t *cr = cairo_create(ctrl->cache); + side = (ctrl->span * 2 +1); + c = ctrl->span; + size = side * side; + if (side < 2) return; - bool supress_paint = false; + if (ctrl->cache) delete[] ctrl->cache; + ctrl->cache = new guint32[size]; switch (ctrl->shape) { case SP_CTRL_SHAPE_SQUARE: - cairo_rectangle(cr, 0, 0, w, h); + p = ctrl->cache; + // top edge + for (x=0; x < side; x++) { + *p++ = stroke_color; + } + // middle + for (y = 2; y < side; y++) { + *p++ = stroke_color; // stroke at first and last pixel + for (x=2; x < side; x++) { + *p++ = fill_color; // fill in the middle + } + *p++ = stroke_color; + } + // bottom edge + for (x=0; x < side; x++) { + *p++ = stroke_color; + } ctrl->build = TRUE; break; case SP_CTRL_SHAPE_DIAMOND: - cairo_move_to(cr, c, 0); // c stands for "center" - it is half of the width / height - cairo_line_to(cr, w, c); - cairo_line_to(cr, c, h); - cairo_line_to(cr, 0, c); - cairo_close_path(cr); + p = ctrl->cache; + for (y = 0; y < side; y++) { + z = abs (c - y); + for (x = 0; x < z; x++) { + *p++ = 0; + } + *p++ = stroke_color; x++; + for (; x < side - z -1; x++) { + *p++ = fill_color; + } + if (z != c) { + *p++ = stroke_color; x++; + } + for (; x < side; x++) { + *p++ = 0; + } + } ctrl->build = TRUE; break; case SP_CTRL_SHAPE_CIRCLE: - cairo_arc(cr, 0.5+c, 0.5+c, c, 0, 2*M_PI); - cairo_close_path(cr); + p = ctrl->cache; + q = p + size -1; + s = -1; + for (y = 0; y <= c ; y++) { + a = abs (c - y); + z = (gint)(0.0 + sqrt ((c+.4)*(c+.4) - a*a)); + x = 0; + while (x < c-z) { + *p++ = 0; + *q-- = 0; + x++; + } + do { + *p++ = stroke_color; + *q-- = stroke_color; + x++; + } while (x < c-s); + while (x < MIN(c+s+1, c+z)) { + *p++ = fill_color; + *q-- = fill_color; + x++; + } + do { + *p++ = stroke_color; + *q-- = stroke_color; + x++; + } while (x <= c+z); + while (x < side) { + *p++ = 0; + *q-- = 0; + x++; + } + s = z; + } ctrl->build = TRUE; break; case SP_CTRL_SHAPE_CROSS: - cairo_move_to(cr, 0.5, 0.5); - cairo_line_to(cr, -0.5+w, -0.5+h); - cairo_move_to(cr, -0.5+w, 0.5); // right stroke - cairo_line_to(cr, 0.5, -0.5+h); - cairo_set_line_width(cr, 1); - cairo_stroke(cr); - supress_paint = true; + p = ctrl->cache; + for (y = 0; y < side; y++) { + z = abs (c - y); + for (x = 0; x < c-z; x++) { + *p++ = 0; + } + *p++ = stroke_color; x++; + for (; x < c + z; x++) { + *p++ = 0; + } + if (z != 0) { + *p++ = stroke_color; x++; + } + for (; x < side; x++) { + *p++ = 0; + } + } ctrl->build = TRUE; break; case SP_CTRL_SHAPE_BITMAP: if (ctrl->pixbuf) { - gdk_cairo_set_source_pixbuf(cr, ctrl->pixbuf, 0, 0); - cairo_paint(cr); - cairo_surface_flush(ctrl->cache); - - // TODO lame!!! find a way to do this without direct pixel manipulation. - int stride = cairo_image_surface_get_stride(ctrl->cache); - guint32 *px = reinterpret_cast<guint32*>(cairo_image_surface_get_data(ctrl->cache)); - - // fix byte order. fill_color is 0xrrggbbaa, cairo needs 0xaarrggbb. - // both quantities are native-endian, so it should be portable. - guint32 fill = ctrl->fill_color; - guint32 stroke = ctrl->stroke_color; - fill = ((fill & 0xff) << 24) | ((fill & 0xffffff00) >> 8); - stroke = ((stroke & 0xff) << 24) | ((stroke & 0xffffff00) >> 8); - - for (int i = 0; i < h; ++i) { - for (int j = 0; j < w; ++j) { - int index = i * stride / 4 + j; - if (px[index] & 0xff000000) { - px[index] = (px[index] & 0x00ffffff) ? stroke : fill; + unsigned char *px; + unsigned int rs; + px = gdk_pixbuf_get_pixels (ctrl->pixbuf); + rs = gdk_pixbuf_get_rowstride (ctrl->pixbuf); + for (y = 0; y < side; y++){ + guint32 *d; + unsigned char *s; + s = px + y * rs; + d = ctrl->cache + side * y; + for (x = 0; x < side; x++) { + if (s[3] < 0x80) { + *d++ = 0; + } else if (s[0] < 0x80) { + *d++ = stroke_color; } else { - px[index] = 0; + *d++ = fill_color; } + s += 4; } } - cairo_surface_mark_dirty(ctrl->cache); - supress_paint = true; } else { g_print ("control has no pixmap\n"); } @@ -406,9 +463,16 @@ sp_ctrl_build_cache (SPCtrl *ctrl) case SP_CTRL_SHAPE_IMAGE: if (ctrl->pixbuf) { - gdk_cairo_set_source_pixbuf(cr, ctrl->pixbuf, 0, 0); - cairo_paint(cr); - supress_paint = true; + guint r = gdk_pixbuf_get_rowstride (ctrl->pixbuf); + guint32 *px; + guchar *data = gdk_pixbuf_get_pixels (ctrl->pixbuf); + p = ctrl->cache; + for (y = 0; y < side; y++){ + px = reinterpret_cast<guint32*>(data + y * r); + for (x = 0; x < side; x++) { + *p++ = *px++; + } + } } else { g_print ("control has no pixmap\n"); } @@ -418,27 +482,13 @@ sp_ctrl_build_cache (SPCtrl *ctrl) default: break; } - - if (ctrl->build && !supress_paint) { - if (ctrl->filled) { - ink_cairo_set_source_rgba32(cr, ctrl->fill_color); - cairo_fill_preserve(cr); - } - if (ctrl->stroked) { - ink_cairo_set_source_rgba32(cr, ctrl->stroke_color); - cairo_set_line_width(cr, 2); - cairo_clip_preserve(cr); - cairo_stroke(cr); - } - } - - cairo_destroy(cr); } -// composite background, foreground, alpha for xor mode -#define COMPOSE_X(b,f,a) ( FAST_DIVIDE<255>( ((guchar) b) * ((guchar) (0xff - a)) + ((guchar) ((b ^ ~f) + b/4 - (b>127? 63 : 0))) * ((guchar) a) ) ) -// composite background, foreground, alpha for color mode -#define COMPOSE_N(b,f,a) ( FAST_DIVIDE<255>( ((guchar) b) * ((guchar) (0xff - a)) + ((guchar) f) * ((guchar) a) ) ) +static inline guint32 compose_xor(guint32 bg, guint32 fg, guint32 a) +{ + guint32 c = bg * (255-a) + (((bg ^ ~fg) + (bg >> 2) - (bg > 127 ? 63 : 0)) & 255) * a; + return (c + 127) / 255; +} static void sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) @@ -456,88 +506,61 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) sp_ctrl_build_cache (ctrl); } - cairo_set_source_surface(buf->ct, ctrl->cache, - ctrl->box.x0 - buf->rect.x0, ctrl->box.y0 - buf->rect.y0); - cairo_paint(buf->ct); - - /* - double x0 = ctrl->box.x0; - double y0 = ctrl->box.y0; - double w = ctrl->box.x1 - ctrl->box.x0 + 1; - double h = ctrl->box.y1 - ctrl->box.y0 + 1; - //guint32 fill = ctrl->fill_color; - //fill = (fill & 0xff == 0 && fill) ? fill | 0xff : fill; - - - switch (ctrl->shape) { - case SP_CTRL_SHAPE_SQUARE: - cairo_rectangle(buf->ct, x0, y0, w, h); - break; - case SP_CTRL_SHAPE_DIAMOND: - cairo_move_to(buf->ct, x0 + w/2, y0); - cairo_line_to(buf->ct, x0 + w, y0 + h/2); - cairo_line_to(buf->ct, x0 + w/2, y0 + h); - cairo_line_to(buf->ct, x0, y0 + h/2); - cairo_close_path(buf->ct); - break; - //case SP_CTRL_SHAPE_CIRCLE: - default: - cairo_arc(buf->ct, x0 + w/2, y0 + h/2, w/2, 0, 2*M_PI); - cairo_close_path(buf->ct); - break; - } - - //if (ctrl->mode == SP_CTRL_MODE_XOR) { - // cairo_set_operator(buf->ct, CAIRO_OPERATOR_XOR); - //} - if (ctrl->filled) { - ink_cairo_set_source_rgba32(buf->ct, ctrl->fill_color); - cairo_fill_preserve(buf->ct); - } - if (ctrl->stroked) { - ink_cairo_set_source_rgba32(buf->ct, ctrl->stroke_color); - cairo_set_line_width(buf->ct, 2); - cairo_clip_preserve(buf->ct); - cairo_stroke_preserve(buf->ct); - } + int w, h; + w = h = (ctrl->span * 2 +1); - cairo_new_path(buf->ct); - cairo_restore(buf->ct);*/ - - #if 0 - // then we render from ctrl->cache - y0 = MAX (ctrl->box.y0, buf->rect.y0); - y1 = MIN (ctrl->box.y1, buf->rect.y1 - 1); - x0 = MAX (ctrl->box.x0, buf->rect.x0); - x1 = MIN (ctrl->box.x1, buf->rect.x1 - 1); - - for (y = y0; y <= y1; y++) { - p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 4; - q = ctrl->cache + ((y - ctrl->box.y0) * (ctrl->span*2+1) + (x0 - ctrl->box.x0)) * 4; - for (x = x0; x <= x1; x++) { - a = *(q + 3); - // 00000000 is the only way to get invisible; all other colors with alpha 00 are treated as mode_color with alpha ff - colormode = false; - if (a == 0x00 && !(q[0] == 0x00 && q[1] == 0x00 && q[2] == 0x00)) { - a = 0xff; - colormode = true; - } - if (ctrl->mode == SP_CTRL_MODE_COLOR || colormode) { - p[0] = COMPOSE_N (p[0], q[0], a); - p[1] = COMPOSE_N (p[1], q[1], a); - p[2] = COMPOSE_N (p[2], q[2], a); - q += 4; - p += 4; - } else if (ctrl->mode == SP_CTRL_MODE_XOR) { - p[0] = COMPOSE_X (p[0], q[0], a); - p[1] = COMPOSE_X (p[1], q[1], a); - p[2] = COMPOSE_X (p[2], q[2], a); - q += 4; - p += 4; + // The code below works even when the target is not an image surface + if (ctrl->mode == SP_CTRL_MODE_XOR) { + // 1. Copy the affected part of output to a temporary surface + cairo_surface_t *work = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); + cairo_t *cr = cairo_create(work); + cairo_translate(cr, -ctrl->box.x0, -ctrl->box.y0); + cairo_set_source_surface(cr, cairo_get_target(buf->ct), buf->rect.x0, buf->rect.y0); + cairo_paint(cr); + cairo_destroy(cr); + + // 2. Composite the control on a temporary surface + cairo_surface_flush(work); + int strideb = cairo_image_surface_get_stride(work); + unsigned char *pxb = cairo_image_surface_get_data(work); + guint32 *p = ctrl->cache; + for (int i=0; i<h; ++i) { + guint32 *pb = reinterpret_cast<guint32*>(pxb + i*strideb); + for (int j=0; j<w; ++j) { + guint32 cc = *p++; + guint32 ac = cc & 0xff; + if (ac == 0 && cc != 0) { + *pb++ = argb32_from_rgba(cc | 0x000000ff); + } else { + EXTRACT_ARGB32(*pb, ab,rb,gb,bb) + guint32 ro = compose_xor(rb, (cc & 0xff000000) >> 24, ac); + guint32 go = compose_xor(gb, (cc & 0x00ff0000) >> 16, ac); + guint32 bo = compose_xor(bb, (cc & 0x0000ff00) >> 8, ac); + ASSEMBLE_ARGB32(px, ab,ro,go,bo) + *pb++ = px; + } } } + cairo_surface_mark_dirty(work); + + // 3. Replace the affected part of output with contents of temporary surface + cairo_save(buf->ct); + cairo_set_source_surface(buf->ct, work, + ctrl->box.x0 - buf->rect.x0, ctrl->box.y0 - buf->rect.y0); + cairo_rectangle(buf->ct, ctrl->box.x0 - buf->rect.x0, ctrl->box.y0 - buf->rect.y0, w, h); + cairo_clip(buf->ct); + cairo_set_operator(buf->ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(buf->ct); + cairo_restore(buf->ct); + cairo_surface_destroy(work); + } else { + cairo_surface_t *cache = cairo_image_surface_create_for_data( + reinterpret_cast<unsigned char*>(ctrl->cache), CAIRO_FORMAT_ARGB32, w, h, w*4); + cairo_set_source_surface(buf->ct, cache, + ctrl->box.x0 - buf->rect.x0, ctrl->box.y0 - buf->rect.y0); + cairo_paint(buf->ct); + cairo_surface_destroy(cache); } - #endif ctrl->shown = TRUE; } diff --git a/src/display/sodipodi-ctrl.h b/src/display/sodipodi-ctrl.h index 27728296a..df0470adb 100644 --- a/src/display/sodipodi-ctrl.h +++ b/src/display/sodipodi-ctrl.h @@ -49,7 +49,7 @@ struct SPCtrl : public SPCanvasItem { bool _moved; NRRectL box; /* NB! x1 & y1 are included */ - cairo_surface_t *cache; + guint32 *cache; GdkPixbuf * pixbuf; void moveto(Geom::Point const p); |
