/* Handles compositing with a clip surface when we have to do the operation * in two pieces and combine them together. */ static cairo_status_t clip_and_composite_combine (const cairo_composite_rectangles_t*extents, draw_func_t draw_func, void *draw_closure) { cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface; cairo_image_surface_t *tmp, *clip; int clip_x, clip_y; cairo_status_t status; tmp = (cairo_image_surface_t *) _cairo_surface_create_similar_solid (&dst->base, dst->base.content, extents->bounded.width, extents->bounded.height, CAIRO_COLOR_TRANSPARENT); if (unlikely (tmp->base.status)) return tmp->base.status; pixman_image_composite32 (PIXMAN_OP_SRC, dst->pixman_image, NULL, tmp->pixman_image, extents->bounded.x, extents->bounded.y, 0, 0, 0, 0, extents->bounded.width, extents->bounded.height); status = draw_func (tmp, draw_closure, extents->op, &extents->source_pattern.base, extents->bounded.x, extents->bounded.y, &extents->bounded); if (unlikely (status)) goto error; clip = (cairo_image_surface_t *) get_clip_surface (dst, extents, &clip_x, &clip_y); if (unlikely (clip->base.status)) goto error; pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, clip->pixman_image, NULL, dst->pixman_image, extents->bounded.x - clip_x, extents->bounded.y - clip_y, 0, 0, extents->bounded.x, extents->bounded.y, extents->bounded.width, extents->bounded.height); pixman_image_composite32 (PIXMAN_OP_ADD, tmp->pixman_image, clip->pixman_image, dst->pixman_image, 0, 0, extents->bounded.x - clip_x, extents->bounded.y - clip_y, extents->bounded.x, extents->bounded.y, extents->bounded.width, extents->bounded.height); cairo_surface_destroy (&clip->base); error: cairo_surface_destroy (&tmp->base); return status; }
static cairo_int_status_t fixup_unbounded_mask (const cairo_spans_compositor_t *compositor, const cairo_composite_rectangles_t *extents, cairo_boxes_t *boxes) { cairo_composite_rectangles_t composite; cairo_surface_t *clip; cairo_int_status_t status; TRACE((stderr, "%s\n", __FUNCTION__)); clip = get_clip_surface (compositor, extents->surface, extents->clip, &extents->unbounded); if (unlikely (clip->status)) { if ((cairo_int_status_t)clip->status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; return clip->status; } status = _cairo_composite_rectangles_init_for_boxes (&composite, extents->surface, CAIRO_OPERATOR_CLEAR, &_cairo_pattern_clear.base, boxes, NULL); if (unlikely (status)) goto cleanup_clip; _cairo_pattern_init_for_surface (&composite.mask_pattern.surface, clip); composite.mask_pattern.base.filter = CAIRO_FILTER_NEAREST; composite.mask_pattern.base.extend = CAIRO_EXTEND_NONE; status = composite_boxes (compositor, &composite, boxes); _cairo_pattern_fini (&composite.mask_pattern.base); _cairo_composite_rectangles_fini (&composite); cleanup_clip: cairo_surface_destroy (clip); return status; }
static cairo_status_t fixup_unbounded (const cairo_composite_rectangles_t *extents) { cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface; pixman_image_t *mask; int mask_x, mask_y; if (! _cairo_clip_is_region (extents->clip)) { cairo_image_surface_t *clip; clip = get_clip_surface (dst, extents, &mask_x, &mask_y); if (unlikely (clip->base.status)) return clip->base.status; mask = pixman_image_ref (clip->pixman_image); cairo_surface_destroy (&clip->base); } else { mask_x = mask_y = 0; mask = _pixman_image_for_color (CAIRO_COLOR_WHITE); if (unlikely (mask == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } /* top */ if (extents->bounded.y != extents->unbounded.y) { int x = extents->unbounded.x; int y = extents->unbounded.y; int width = extents->unbounded.width; int height = extents->bounded.y - y; pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, mask, NULL, dst->pixman_image, x - mask_x, y - mask_y, 0, 0, x, y, width, height); } /* left */ if (extents->bounded.x != extents->unbounded.x) { int x = extents->unbounded.x; int y = extents->bounded.y; int width = extents->bounded.x - x; int height = extents->bounded.height; pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, mask, NULL, dst->pixman_image, x - mask_x, y - mask_y, 0, 0, x, y, width, height); } /* right */ if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) { int x = extents->bounded.x + extents->bounded.width; int y = extents->bounded.y; int width = extents->unbounded.x + extents->unbounded.width - x; int height = extents->bounded.height; pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, mask, NULL, dst->pixman_image, x - mask_x, y - mask_y, 0, 0, x, y, width, height); } /* bottom */ if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) { int x = extents->unbounded.x; int y = extents->bounded.y + extents->bounded.height; int width = extents->unbounded.width; int height = extents->unbounded.y + extents->unbounded.height - y; pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, mask, NULL, dst->pixman_image, x - mask_x, y - mask_y, 0, 0, x, y, width, height); } pixman_image_unref (mask); return CAIRO_STATUS_SUCCESS; }
static cairo_int_status_t composite_aligned_boxes (const cairo_spans_compositor_t *compositor, const cairo_composite_rectangles_t *extents, cairo_boxes_t *boxes) { cairo_surface_t *dst = extents->surface; cairo_operator_t op = extents->op; const cairo_pattern_t *source = &extents->source_pattern.base; cairo_int_status_t status; cairo_bool_t need_clip_mask = ! _clip_is_region (extents->clip); cairo_bool_t op_is_source; cairo_bool_t no_mask; cairo_bool_t inplace; TRACE ((stderr, "%s: need_clip_mask=%d, is-bounded=%d\n", __FUNCTION__, need_clip_mask, extents->is_bounded)); if (need_clip_mask && ! extents->is_bounded) return CAIRO_INT_STATUS_UNSUPPORTED; no_mask = extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID && CAIRO_COLOR_IS_OPAQUE (&extents->mask_pattern.solid.color); op_is_source = op_reduces_to_source (extents, no_mask); inplace = ! need_clip_mask && op_is_source && no_mask; TRACE ((stderr, "%s: op-is-source=%d [op=%d], no-mask=%d, inplace=%d\n", __FUNCTION__, op_is_source, op, no_mask, inplace)); if (op == CAIRO_OPERATOR_SOURCE && (need_clip_mask || ! no_mask)) { /* SOURCE with a mask is actually a LERP in cairo semantics */ if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP) == 0) return CAIRO_INT_STATUS_UNSUPPORTED; } /* Are we just copying a recording surface? */ if (inplace && recording_pattern_contains_sample (&extents->source_pattern.base, &extents->source_sample_area)) { cairo_clip_t *recording_clip; const cairo_pattern_t *source = &extents->source_pattern.base; /* XXX could also do tiling repeat modes... */ /* first clear the area about to be overwritten */ if (! dst->is_clear) status = compositor->fill_boxes (dst, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, boxes); recording_clip = _cairo_clip_from_boxes (boxes); status = _cairo_recording_surface_replay_with_clip (unwrap_source (source), &source->matrix, dst, recording_clip); _cairo_clip_destroy (recording_clip); return status; } status = CAIRO_INT_STATUS_UNSUPPORTED; if (! need_clip_mask && no_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) { const cairo_color_t *color; color = &((cairo_solid_pattern_t *) source)->color; if (op_is_source) op = CAIRO_OPERATOR_SOURCE; status = compositor->fill_boxes (dst, op, color, boxes); } else if (inplace && source->type == CAIRO_PATTERN_TYPE_SURFACE) { status = upload_boxes (compositor, extents, boxes); } if (status == CAIRO_INT_STATUS_UNSUPPORTED) { cairo_surface_t *src; cairo_surface_t *mask = NULL; int src_x, src_y; int mask_x = 0, mask_y = 0; /* All typical cases will have been resolved before now... */ if (need_clip_mask) { mask = get_clip_surface (compositor, dst, extents->clip, &extents->bounded); if (unlikely (mask->status)) return mask->status; mask_x = -extents->bounded.x; mask_y = -extents->bounded.y; } /* XXX but this is still ugly */ if (! no_mask) { src = compositor->pattern_to_surface (dst, &extents->mask_pattern.base, TRUE, &extents->bounded, &extents->mask_sample_area, &src_x, &src_y); if (unlikely (src->status)) { cairo_surface_destroy (mask); return src->status; } if (mask != NULL) { status = compositor->composite_boxes (mask, CAIRO_OPERATOR_IN, src, NULL, src_x, src_y, 0, 0, mask_x, mask_y, boxes, &extents->bounded); cairo_surface_destroy (src); } else { mask = src; mask_x = src_x; mask_y = src_y; } } src = compositor->pattern_to_surface (dst, source, FALSE, &extents->bounded, &extents->source_sample_area, &src_x, &src_y); if (likely (src->status == CAIRO_STATUS_SUCCESS)) { status = compositor->composite_boxes (dst, op, src, mask, src_x, src_y, mask_x, mask_y, 0, 0, boxes, &extents->bounded); cairo_surface_destroy (src); } else status = src->status; cairo_surface_destroy (mask); } if (status == CAIRO_INT_STATUS_SUCCESS && ! extents->is_bounded) status = fixup_unbounded_boxes (compositor, extents, boxes); return status; }