From 917de2bab458d51b4149a1b794cbb1b6b9562171 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 22 Jun 2010 23:36:47 +0200 Subject: Initial Cairo rendering commit: solid shapes, gradients, opacity and patterns (bzr r9508.1.1) --- src/display/sodipodi-ctrl.cpp | 283 +++++++++++++++++++++--------------------- 1 file changed, 139 insertions(+), 144 deletions(-) (limited to 'src/display/sodipodi-ctrl.cpp') diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index caa5fa697..c85fb586b 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -13,6 +13,7 @@ #include "display-forward.h" #include "sodipodi-ctrl.h" #include "libnr/nr-pixops.h" +#include "display/inkscape-cairo.h" enum { ARG_0, @@ -176,11 +177,14 @@ sp_ctrl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) sp_canvas_item_request_update (item); break; - case ARG_FILL_COLOR: - ctrl->fill_color = GTK_VALUE_INT (*arg); + 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); - break; + } break; case ARG_STROKED: ctrl->stroked = GTK_VALUE_BOOL (*arg); @@ -188,11 +192,14 @@ sp_ctrl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) sp_canvas_item_request_update (item); break; - case ARG_STROKE_COLOR: - ctrl->stroke_color = GTK_VALUE_INT (*arg); + 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); - break; + } break; case ARG_PIXBUF: pixbuf = (GdkPixbuf*)(GTK_VALUE_POINTER (*arg)); @@ -298,11 +305,11 @@ sp_ctrl_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item) static void sp_ctrl_build_cache (SPCtrl *ctrl) { - guchar * p, *q; - gint size, x, y, z, s, a, side, c; - guint8 fr, fg, fb, fa, sr, sg, sb, sa; + //guchar * p, *q; + //int size, x, y, z, s, a, side, c; + //guint8 fr, fg, fb, fa, sr, sg, sb, sa; - if (ctrl->filled) { + /*if (ctrl->filled) { fr = (ctrl->fill_color >> 24) & 0xff; fg = (ctrl->fill_color >> 16) & 0xff; fb = (ctrl->fill_color >> 8) & 0xff; @@ -317,147 +324,85 @@ sp_ctrl_build_cache (SPCtrl *ctrl) sa = (ctrl->stroke_color) & 0xff; } else { sr = fr; sg = fg; sb = fb; sa = fa; - } + }*/ + int w, h; // for clarity; w and h are always odd + w = h = (ctrl->span * 2 +1); + int c = ctrl->span ; - side = (ctrl->span * 2 +1); - c = ctrl->span ; - size = (side) * (side) * 4; - if (side < 2) return; + 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); - if (ctrl->cache) - g_free (ctrl->cache); - ctrl->cache = (guchar*)g_malloc (size); + bool supress_fill = false; + bool supress_paint = false; switch (ctrl->shape) { case SP_CTRL_SHAPE_SQUARE: - p = ctrl->cache; - for (x=0; x < side; x++) { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; - } - for (y = 2; y < side; y++) { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; - for (x=2; x < side; x++) { - *p++ = fr; *p++ = fg; *p++ = fb; *p++ = fa; - } - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; - } - for (x=0; x < side; x++) { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; - } + cairo_rectangle(cr, 0, 0, w, h); ctrl->build = TRUE; break; case SP_CTRL_SHAPE_DIAMOND: - p = ctrl->cache; - for (y = 0; y < side; y++) { - z = abs (c - y); - for (x = 0; x < z; x++) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; - } - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++; - for (; x < side - z -1; x++) { - *p++ = fr; *p++ = fg; *p++ = fb; *p++ = fa; - } - if (z != c) { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++; - } - for (; x < side; x++) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; - } - } + 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); + ctrl->build = TRUE; break; case SP_CTRL_SHAPE_CIRCLE: - 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++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; - *q-- = 0x00; *q-- = 0x00; *q-- = 0x00; *q-- = 0x00; - x++; - } - do { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; - *q-- = sa; *q-- = sb; *q-- = sg; *q-- = sr; - x++; - } while (x < c-s); - while (x < MIN(c+s+1, c+z)) { - *p++ = fr; *p++ = fg; *p++ = fb; *p++ = fa; - *q-- = fa; *q-- = fb; *q-- = fg; *q-- = fr; - x++; - } - do { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; - *q-- = sa; *q-- = sb; *q-- = sg; *q-- = sr; - x++; - } while (x <= c+z); - while (x < side) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; - *q-- = 0x00; *q-- = 0x00; *q-- = 0x00; *q-- = 0x00; - x++; - } - s = z; - } + cairo_arc(cr, 0.5+c, 0.5+c, c, 0, 2*M_PI); + cairo_close_path(cr); ctrl->build = TRUE; break; case SP_CTRL_SHAPE_CROSS: - p = ctrl->cache; - for (y = 0; y < side; y++) { - z = abs (c - y); - for (x = 0; x < c-z; x++) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; - } - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++; - for (; x < c + z; x++) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; - } - if (z != 0) { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++; - } - for (; x < side; x++) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; - } - } + cairo_move_to(cr, 0.5+c, 0); // top stroke + cairo_line_to(cr, 0.5+c, c); + cairo_move_to(cr, w, 0.5+c); // right stroke + cairo_line_to(cr, w, c+1); + cairo_move_to(cr, 0.5+c, h); // bottom stroke + cairo_line_to(cr, 0.5+c, c+1); + cairo_move_to(cr, 0, 0.5+c); // left stroke + cairo_line_to(cr, c, 0.5+c); + supress_fill = true; ctrl->build = TRUE; break; case SP_CTRL_SHAPE_BITMAP: if (ctrl->pixbuf) { - 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++){ - unsigned char *s, *d; - s = px + y * rs; - d = ctrl->cache + 4 * side * y; - for (x = 0; x < side; x++) { - if (s[3] < 0x80) { - d[0] = 0x00; - d[1] = 0x00; - d[2] = 0x00; - d[3] = 0x00; - } else if (s[0] < 0x80) { - d[0] = sr; - d[1] = sg; - d[2] = sb; - d[3] = sa; + 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(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] ? stroke : fill; } else { - d[0] = fr; - d[1] = fg; - d[2] = fb; - d[3] = fa; + px[index] = 0; } - s += 4; - d += 4; } } + cairo_surface_mark_dirty(ctrl->cache); + supress_paint = true; } else { g_print ("control has no pixmap\n"); } @@ -466,19 +411,9 @@ sp_ctrl_build_cache (SPCtrl *ctrl) case SP_CTRL_SHAPE_IMAGE: if (ctrl->pixbuf) { - guint r = gdk_pixbuf_get_rowstride (ctrl->pixbuf); - guchar * pix; - q = gdk_pixbuf_get_pixels (ctrl->pixbuf); - p = ctrl->cache; - for (y = 0; y < side; y++){ - pix = q + (y * r); - for (x = 0; x < side; x++) { - *p++ = *pix++; - *p++ = *pix++; - *p++ = *pix++; - *p++ = *pix++; - } - } + gdk_cairo_set_source_pixbuf(cr, ctrl->pixbuf, 0, 0); + cairo_paint(cr); + supress_paint = true; } else { g_print ("control has no pixmap\n"); } @@ -489,6 +424,20 @@ sp_ctrl_build_cache (SPCtrl *ctrl) break; } + if (ctrl->build && !supress_paint) { + if (ctrl->filled && !supress_fill) { + 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 @@ -499,29 +448,74 @@ sp_ctrl_build_cache (SPCtrl *ctrl) static void sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) { - gint y0, y1, y, x0,x1,x; - guchar *p, *q, a; + //gint y0, y1, y, x0,x1,x; + //guchar *p, *q, a; SPCtrl *ctrl = SP_CTRL (item); if (!ctrl->defined) return; if ((!ctrl->filled) && (!ctrl->stroked)) return; - sp_canvas_prepare_buffer (buf); - // the control-image is rendered into ctrl->cache if (!ctrl->build) { 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); + } + + 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); - bool colormode; - 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; @@ -548,6 +542,7 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) } } } + #endif ctrl->shown = TRUE; } -- cgit v1.2.3 From 1496385d1be9d733b06e0cd94839e2ef32c959bc Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 22 Jun 2010 23:45:17 +0200 Subject: Fix cross control point (bzr r9508.1.2) --- src/display/sodipodi-ctrl.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'src/display/sodipodi-ctrl.cpp') diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index c85fb586b..dc79f5969 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -337,7 +337,6 @@ sp_ctrl_build_cache (SPCtrl *ctrl) ctrl->cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); cairo_t *cr = cairo_create(ctrl->cache); - bool supress_fill = false; bool supress_paint = false; switch (ctrl->shape) { @@ -362,15 +361,13 @@ sp_ctrl_build_cache (SPCtrl *ctrl) break; case SP_CTRL_SHAPE_CROSS: - cairo_move_to(cr, 0.5+c, 0); // top stroke - cairo_line_to(cr, 0.5+c, c); - cairo_move_to(cr, w, 0.5+c); // right stroke - cairo_line_to(cr, w, c+1); - cairo_move_to(cr, 0.5+c, h); // bottom stroke - cairo_line_to(cr, 0.5+c, c+1); - cairo_move_to(cr, 0, 0.5+c); // left stroke - cairo_line_to(cr, c, 0.5+c); - supress_fill = true; + 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; ctrl->build = TRUE; break; @@ -425,7 +422,7 @@ sp_ctrl_build_cache (SPCtrl *ctrl) } if (ctrl->build && !supress_paint) { - if (ctrl->filled && !supress_fill) { + if (ctrl->filled) { ink_cairo_set_source_rgba32(cr, ctrl->fill_color); cairo_fill_preserve(cr); } -- cgit v1.2.3 From 55f7e59c13b6fb502a0cfbbe811f2f3f90cc6f80 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 29 Jun 2010 23:05:56 +0200 Subject: Fix icons (bzr r9508.1.7) --- src/display/sodipodi-ctrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/display/sodipodi-ctrl.cpp') diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index dc79f5969..ed4c91d3b 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -392,7 +392,7 @@ sp_ctrl_build_cache (SPCtrl *ctrl) for (int j = 0; j < w; ++j) { int index = i * stride / 4 + j; if (px[index] & 0xff000000) { - px[index] = px[index] ? stroke : fill; + px[index] = (px[index] & 0x00ffffff) ? stroke : fill; } else { px[index] = 0; } -- cgit v1.2.3 From 13b15b7b977eecbededd1734f5ab001f0c44d21f Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 30 Jun 2010 00:41:48 +0200 Subject: Consolidate Cairo utils in display/cairo-utils.h. Fix icons harder. (bzr r9508.1.8) --- src/display/sodipodi-ctrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/display/sodipodi-ctrl.cpp') diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index ed4c91d3b..37685c5da 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -13,7 +13,7 @@ #include "display-forward.h" #include "sodipodi-ctrl.h" #include "libnr/nr-pixops.h" -#include "display/inkscape-cairo.h" +#include "display/cairo-utils.h" enum { ARG_0, -- cgit v1.2.3 From aa844be794b36b44b624e579db7f0945b5d3927b Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 14 Aug 2010 21:22:11 +0200 Subject: Completely remove NRPixBlock (bzr r9508.1.67) --- src/display/sodipodi-ctrl.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/display/sodipodi-ctrl.cpp') diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index 37685c5da..28488e7c3 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -12,7 +12,6 @@ #include "sp-canvas-util.h" #include "display-forward.h" #include "sodipodi-ctrl.h" -#include "libnr/nr-pixops.h" #include "display/cairo-utils.h" enum { -- cgit v1.2.3 From f6dba310bc22dc65845e0cd0743594545e356a59 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 19 Jun 2011 11:01:29 +0200 Subject: Fix rendering of control points (bzr r9508.1.88) --- src/display/sodipodi-ctrl.cpp | 361 ++++++++++++++++++++++-------------------- 1 file changed, 192 insertions(+), 169 deletions(-) (limited to 'src/display/sodipodi-ctrl.cpp') 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(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(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(pxb + i*strideb); + for (int j=0; j> 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(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; } -- cgit v1.2.3