cairo_int_status_t
_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
					   cairo_surface_t *surface,
					   cairo_operator_t		 op,
					   const cairo_pattern_t	*source,
					   const cairo_path_fixed_t		*path,
					   const cairo_clip_t		*clip)
{
    if (! _cairo_composite_rectangles_init (extents,
					    surface, op, source, clip))
    {
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    _cairo_path_fixed_approximate_fill_extents (path, &extents->mask);

    return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
					     cairo_surface_t *surface,
					     cairo_operator_t		 op,
					     const cairo_pattern_t	*source,
					     cairo_scaled_font_t	*scaled_font,
					     cairo_glyph_t		*glyphs,
					     int			 num_glyphs,
					     const cairo_clip_t		*clip,
					     cairo_bool_t		*overlap)
{
    cairo_status_t status;

    if (! _cairo_composite_rectangles_init (extents, surface, op, source, clip))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    /* Computing the exact bbox and the overlap is expensive.
     * First perform a cheap test to see if the glyphs are all clipped out.
     */
    if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK &&
	_cairo_scaled_font_glyph_approximate_extents (scaled_font,
						      glyphs, num_glyphs,
						      &extents->mask))
    {
	if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask))
	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    status = _cairo_scaled_font_glyph_device_extents (scaled_font,
						      glyphs, num_glyphs,
						      &extents->mask,
						      overlap);
    if (unlikely (status))
	return status;

    if (overlap && *overlap &&
	scaled_font->options.antialias == CAIRO_ANTIALIAS_NONE &&
	_cairo_pattern_is_opaque_solid (&extents->source_pattern.base))
    {
	*overlap = FALSE;
    }

    return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t
_cairo_composite_rectangles_lazy_init_for_mask (cairo_composite_rectangles_t *extents,
						cairo_surface_t *surface,
						cairo_operator_t op,
						const cairo_pattern_t *source,
						const cairo_pattern_t *mask,
						const cairo_clip_t *clip)
{
	cairo_bool_t ret;
	cairo_bool_t should_be_lazy = (op == CAIRO_OPERATOR_SOURCE) ? FALSE : TRUE;


	if (! _cairo_composite_rectangles_init (extents,
						surface, op, source, clip,
						&should_be_lazy))
    {
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

	extents->original_mask_pattern = mask;

	if (! should_be_lazy) {
		_cairo_composite_reduce_pattern (mask, &extents->mask_pattern);
		_cairo_pattern_get_extents (&extents->mask_pattern.base,
					&extents->mask);
		return _cairo_composite_rectangles_intersect (extents, clip);
	}

	_cairo_pattern_get_extents (extents->original_mask_pattern,
				&extents->mask);

	ret = _cairo_rectangle_intersect (&extents->bounded, &extents->mask);
	if (! ret && extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
		return CAIRO_INT_STATUS_NOTHING_TO_DO;

	if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE))
		extents->unbounded = extents->bounded;
	else if ((extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) &&
			 (!_cairo_rectangle_intersect (&extents->unbounded, &extents->mask)))
			 return CAIRO_INT_STATUS_NOTHING_TO_DO;

	extents->clip = _cairo_clip_copy (clip);
	return CAIRO_INT_STATUS_SUCCESS;
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_polygon (cairo_composite_rectangles_t *extents,
					      cairo_surface_t		*surface,
					      cairo_operator_t		 op,
					      const cairo_pattern_t	*source,
					      const cairo_polygon_t	*polygon,
					      const cairo_clip_t		*clip)
{
    cairo_bool_t should_be_lazy = FALSE;
    if (! _cairo_composite_rectangles_init (extents,
					    surface, op, source, clip,
					    &should_be_lazy))
    {
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
    return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
					   int surface_width, int surface_height,
					   cairo_operator_t		 op,
					   const cairo_pattern_t	*source,
					   const cairo_pattern_t	*mask,
					   cairo_clip_t			*clip)
{
    if (! _cairo_composite_rectangles_init (extents,
					    surface_width, surface_height,
					    op, source, clip))
    {
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    _cairo_pattern_get_extents (mask, &extents->mask);

    return _cairo_composite_rectangles_intersect (extents);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_boxes (cairo_composite_rectangles_t *extents,
					      cairo_surface_t		*surface,
					      cairo_operator_t		 op,
					      const cairo_pattern_t	*source,
					      const cairo_boxes_t	*boxes,
					      const cairo_clip_t		*clip)
{
    cairo_box_t box;

    if (! _cairo_composite_rectangles_init (extents,
					    surface, op, source, clip))
    {
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    _cairo_boxes_extents (boxes, &box);
    _cairo_box_round_to_rectangle (&box, &extents->mask);
    return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
					   cairo_surface_t*surface,
					   cairo_operator_t		 op,
					   const cairo_pattern_t	*source,
					   const cairo_pattern_t	*mask,
					   const cairo_clip_t		*clip)
{
    if (! _cairo_composite_rectangles_init (extents,
					    surface, op, source, clip))
    {
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    extents->original_mask_pattern = mask;
    _cairo_composite_reduce_pattern (mask, &extents->mask_pattern);
    _cairo_pattern_get_extents (&extents->mask_pattern.base, &extents->mask);

    return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
					     int surface_width, int surface_height,
					     cairo_operator_t		 op,
					     const cairo_pattern_t	*source,
					     cairo_path_fixed_t		*path,
					     const cairo_stroke_style_t	*style,
					     const cairo_matrix_t	*ctm,
					     cairo_clip_t		*clip)
{
    if (! _cairo_composite_rectangles_init (extents,
					    surface_width, surface_height,
					    op, source, clip))
    {
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &extents->mask);

    return _cairo_composite_rectangles_intersect (extents);
}
static cairo_status_t
_composite_spans_fill_func (void                          *closure,
			    cairo_operator_t               op,
			    const cairo_pattern_t         *src,
			    cairo_surface_t               *dst,
			    int                            dst_x,
			    int                            dst_y,
			    const cairo_rectangle_int_t   *extents)
{
    cairo_composite_rectangles_t rects;
    cairo_composite_spans_fill_info_t *info = closure;
    cairo_pattern_union_t pattern;
    cairo_status_t status = CAIRO_STATUS_SUCCESS;

    _cairo_composite_rectangles_init (
	&rects, extents->x, extents->y,
	extents->width, extents->height);

    /* The incoming dst_x/y are where we're pretending the origin of
     * the dst surface is -- *not* the offset of a rectangle where
     * we'd like to place the result. */
    rects.dst.x -= dst_x;
    rects.dst.y -= dst_y;

    /* We're called without a source pattern from
     * _create_composite_mask_pattern(). */
    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
			       CAIRO_CONTENT_COLOR);
    if (src == NULL)
	src = &pattern.base;

    status = _cairo_path_fixed_fill_using_spans (
	op, src, info->path, dst,
	info->fill_rule, info->tolerance, info->antialias,
	&rects);

    _cairo_pattern_fini (&pattern.base);
    return status;
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
					     cairo_surface_t *surface,
					     cairo_operator_t		 op,
					     const cairo_pattern_t	*source,
					     const cairo_path_fixed_t		*path,
					     const cairo_stroke_style_t	*style,
					     const cairo_matrix_t	*ctm,
					     const cairo_clip_t		*clip)
{
    cairo_bool_t should_be_lazy = FALSE;

    if (! _cairo_composite_rectangles_init (extents,
					    surface, op, source, clip,
					    &should_be_lazy))
    {
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &extents->mask);

    return _cairo_composite_rectangles_intersect (extents, clip);
}
Beispiel #11
0
static cairo_status_t
_cairo_clip_intersect_mask_using_spans (cairo_clip_t       *clip,
					cairo_path_fixed_t *path,
					cairo_fill_rule_t   fill_rule,
					double		    tolerance,
					cairo_antialias_t   antialias,
					cairo_surface_t    *target)
{
    cairo_span_renderer_t *renderer = NULL;
    cairo_pattern_union_t pattern;
    cairo_rectangle_int_t surface_rect;
    cairo_surface_t *surface = NULL;
    cairo_status_t status;
    cairo_operator_t op;
    cairo_composite_rectangles_t rects;

    if (clip->all_clipped)
	return CAIRO_STATUS_SUCCESS;

    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
			       CAIRO_CONTENT_COLOR);

    /* If we have a clip surface we're going to use IN to combine our
     * new clip with the old clip.  The ADD is done to a transparent
     * surface, as that's a fast way of doing it currently.  We should
     * really be using SOURCE instead, but _cairo_surface_composite()
     * checks that it's not called with SOURCE or DEST. */
    op = clip->surface ? CAIRO_OPERATOR_IN : CAIRO_OPERATOR_ADD;

    /* Test if the target can composite spans.  We're going to assume
     * this is a good indicator of whether a similar surface is going
     * to be able to composite spans too. */
    if ( !_cairo_surface_check_span_renderer (op,
					      &pattern.base,
					      target,
					      antialias,
					      NULL))
    {
	status = CAIRO_INT_STATUS_UNSUPPORTED;
	goto BAIL;
    }

    status = _cairo_surface_get_extents (target, &surface_rect);
    if (status)
	goto BAIL;

    /* We'll create a new surface the size of the intersection of the
     * old mask surface and the extents of the new clip path. */
    {
	cairo_rectangle_int_t extents;

	_cairo_path_fixed_approximate_clip_extents (path, &extents);
	if (! _cairo_rectangle_intersect (&surface_rect, &extents))
	    goto SUCCESS;

	if (clip->surface != NULL &&
	    ! _cairo_rectangle_intersect (&surface_rect, &clip->surface_rect))
	    goto SUCCESS;
    }

    /* Make the new mask surface and optionally initialise it from the
     * previous clip if we have one. */
    surface = _cairo_surface_create_similar_solid (target,
						   CAIRO_CONTENT_ALPHA,
						   surface_rect.width,
						   surface_rect.height,
						   CAIRO_COLOR_TRANSPARENT);
    if (surface->status) {
	_cairo_pattern_fini (&pattern.base);
	return surface->status;
    }

    if (clip->surface) {
	cairo_surface_pattern_t old_clip;
	_cairo_pattern_init_for_surface (&old_clip, clip->surface);
	status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
					   &old_clip.base,
					   NULL,
					   surface,
					   surface_rect.x - clip->surface_rect.x,
					   surface_rect.y - clip->surface_rect.y,
					   0, 0,
					   0, 0,
					   surface_rect.width,
					   surface_rect.height);
	_cairo_pattern_fini (&old_clip.base);
	if (status)
	    goto BAIL;
    }

    _cairo_composite_rectangles_init (&rects,
				      surface_rect.x,
				      surface_rect.y,
				      surface_rect.width,
				      surface_rect.height);
    rects.dst.x = 0;
    rects.dst.y = 0;

    /* Render the new clipping path into the new mask surface. We've
     * chosen op to either combine the new clip path with the existing
     * clip mask (if there is one) or just render it. */
    status =_cairo_path_fixed_fill_using_spans (op, &pattern.base,
						path, surface,
						fill_rule, tolerance,
						antialias, &rects);
    if (status)
	goto BAIL;

 SUCCESS:
    if (clip->surface != NULL)
	cairo_surface_destroy (clip->surface);
    clip->surface = surface;
    clip->surface_rect = surface_rect;
    clip->serial = _cairo_surface_allocate_clip_serial (target);
    surface = NULL;

    if (surface_rect.width == 0 || surface_rect.height == 0)
	_cairo_clip_set_all_clipped (clip, target);

 BAIL:
    if (renderer)
	renderer->destroy(renderer);
    if (surface)
	cairo_surface_destroy (surface);
    _cairo_pattern_fini (&pattern.base);
    return status;
}