summaryrefslogtreecommitdiffstats
path: root/src/display/sodipodi-ctrl.cpp
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2010-06-22 21:36:47 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2010-06-22 21:36:47 +0000
commit917de2bab458d51b4149a1b794cbb1b6b9562171 (patch)
tree9abd6fe6497b8b0965bb85caf4b4456ff2099989 /src/display/sodipodi-ctrl.cpp
parent* [INTL:sk] Slovak translation update (diff)
downloadinkscape-917de2bab458d51b4149a1b794cbb1b6b9562171.tar.gz
inkscape-917de2bab458d51b4149a1b794cbb1b6b9562171.zip
Initial Cairo rendering commit: solid shapes, gradients, opacity and patterns
(bzr r9508.1.1)
Diffstat (limited to 'src/display/sodipodi-ctrl.cpp')
-rw-r--r--src/display/sodipodi-ctrl.cpp283
1 files changed, 139 insertions, 144 deletions
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<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] ? 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;
}