summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cairo-image-compositor.c106
-rw-r--r--test/reference/operator-source.argb32.ref.pngbin5630 -> 5625 bytes
-rw-r--r--test/reference/operator-source.rgb24.ref.pngbin4000 -> 3967 bytes
3 files changed, 96 insertions, 10 deletions
diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c
index 8db82502..990226a0 100644
--- a/src/cairo-image-compositor.c
+++ b/src/cairo-image-compositor.c
@@ -2260,6 +2260,89 @@ _inplace_spans (void *abstract_renderer,
return CAIRO_STATUS_SUCCESS;
}
+static cairo_status_t
+_inplace_src_spans (void *abstract_renderer,
+ int y, int h,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+ uint8_t *mask;
+ int x0, y0;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ x0 = r->composite->unbounded.x;
+ y0 = r->u.composite.mask_y;
+ r->u.composite.mask_y = y + h;
+ if (y != y0) {
+ pixman_image_composite32 (PIXMAN_OP_CLEAR, r->src, NULL, r->u.composite.dst,
+ 0, 0,
+ 0, 0,
+ x0, y0,
+ r->composite->unbounded.width, y - y0);
+ }
+
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ if (spans[0].x != x0) {
+ memset(mask, 0, spans[0].x - x0);
+ mask += spans[0].x - x0;
+ }
+ do {
+ int len = spans[1].x - spans[0].x;
+ *mask++ = spans[0].coverage;
+ if (len > 1) {
+ memset (mask, spans[0].coverage, --len);
+ mask += len;
+ }
+ spans++;
+ } while (--num_spans > 1);
+ if (spans[0].x-x0 != r->composite->unbounded.width)
+ memset(mask, 0, r->composite->unbounded.width+x0 - spans[0].x);
+
+#if PIXMAN_HAS_OP_LERP
+ pixman_image_composite32 (PIXMAN_OP_LERP_SRC, r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ r->composite->unbounded.width, h);
+#else
+ pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, r->mask, NULL, r->u.composite.dst,
+ 0, 0,
+ 0, 0,
+ x0, y,
+ r->composite->unbounded.width, h);
+ pixman_image_composite32 (PIXMAN_OP_ADD, r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ r->composite->unbounded.width, h);
+#endif
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_inplace_src_finish (void *abstract_renderer)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+ int y0 = r->u.composite.mask_y;
+ int y1 = r->composite->unbounded.y + r->composite->unbounded.height;
+
+ if (y0 != y1) {
+ pixman_image_composite32 (PIXMAN_OP_CLEAR, r->src, NULL, r->u.composite.dst,
+ 0, 0,
+ 0, 0,
+ r->composite->unbounded.x, y0,
+ r->composite->unbounded.width, y1 - y0);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_int_status_t
inplace_renderer_init (cairo_image_span_renderer_t *r,
const cairo_composite_rectangles_t *composite,
@@ -2350,6 +2433,7 @@ inplace_renderer_init (cairo_image_span_renderer_t *r,
}
if (r->base.render_rows == NULL) {
unsigned int width;
+ const cairo_pattern_t *src = &composite->source_pattern.base;
if (r->op != 0xff)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -2357,25 +2441,29 @@ inplace_renderer_init (cairo_image_span_renderer_t *r,
if (composite->is_bounded == 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ width = (composite->bounded.width + 3) & ~3;
+ r->base.render_rows = _inplace_spans;
if (dst->base.is_clear &&
(composite->op == CAIRO_OPERATOR_SOURCE ||
composite->op == CAIRO_OPERATOR_OVER ||
composite->op == CAIRO_OPERATOR_ADD)) {
r->op = PIXMAN_OP_SRC;
+ } else if (composite->op == CAIRO_OPERATOR_SOURCE) {
+ r->base.render_rows = _inplace_src_spans;
+ r->base.finish = _inplace_src_finish;
+ r->u.composite.mask_y = r->composite->unbounded.y;
+ width = (composite->unbounded.width + 3) & ~3;
+ } else if (composite->op == CAIRO_OPERATOR_CLEAR) {
+ r->op = PIXMAN_OP_OUT_REVERSE;
+ src = NULL;
} else {
- if (composite->op == CAIRO_OPERATOR_SOURCE ||
- composite->op == CAIRO_OPERATOR_CLEAR)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
r->op = _pixman_operator (composite->op);
}
- width = (composite->bounded.width + 3) & ~3;
if (width > sizeof (r->buf))
return CAIRO_INT_STATUS_UNSUPPORTED;
- r->src = _pixman_image_for_pattern (dst,
- &composite->source_pattern.base, FALSE,
+ r->src = _pixman_image_for_pattern (dst, src, FALSE,
&composite->bounded,
&composite->source_sample_area,
&r->u.composite.src_x, &r->u.composite.src_y);
@@ -2384,8 +2472,7 @@ inplace_renderer_init (cairo_image_span_renderer_t *r,
/* Create an effectively unbounded mask by repeating the single line */
r->mask = pixman_image_create_bits (PIXMAN_a8,
- composite->bounded.width,
- composite->bounded.height,
+ width, composite->unbounded.height,
(uint32_t *)r->buf, 0);
if (unlikely (r->mask == NULL)) {
pixman_image_unref (r->src);
@@ -2393,7 +2480,6 @@ inplace_renderer_init (cairo_image_span_renderer_t *r,
}
r->u.composite.dst = dst->pixman_image;
- r->base.render_rows = _inplace_spans;
}
r->bpp = PIXMAN_FORMAT_BPP(dst->pixman_format);
diff --git a/test/reference/operator-source.argb32.ref.png b/test/reference/operator-source.argb32.ref.png
index ca3d18c6..87e73741 100644
--- a/test/reference/operator-source.argb32.ref.png
+++ b/test/reference/operator-source.argb32.ref.png
Binary files differ
diff --git a/test/reference/operator-source.rgb24.ref.png b/test/reference/operator-source.rgb24.ref.png
index 8109d9c6..473e1f21 100644
--- a/test/reference/operator-source.rgb24.ref.png
+++ b/test/reference/operator-source.rgb24.ref.png
Binary files differ