static void
_cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface,
					   cairo_operator_t op,
					   const cairo_pattern_t *source,
					   const cairo_clip_t *clip,
					   cairo_rectangle_int_t *extents)
{
    cairo_bool_t is_empty;

    is_empty = _cairo_surface_get_extents (&surface->base, extents);

    if (_cairo_operator_bounded_by_source (op)) {
	cairo_rectangle_int_t source_extents;

	_cairo_pattern_get_extents (source, &source_extents);
	_cairo_rectangle_intersect (extents, &source_extents);
    }

    _rectangle_intersect_clip (extents, clip);
}
Beispiel #2
0
static cairo_int_status_t
_cairo_analysis_surface_paint (void			*abstract_surface,
			      cairo_operator_t		op,
			      cairo_pattern_t		*source)
{
    cairo_analysis_surface_t *surface = abstract_surface;
    cairo_status_t	     status, backend_status;
    cairo_rectangle_int_t  extents;
    cairo_bool_t is_empty;

    if (!surface->target->backend->paint)
	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
    else
	backend_status = (*surface->target->backend->paint) (surface->target, op,
                                                             source);

    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
	backend_status = _analyze_meta_surface_pattern (surface, source);

    status = _cairo_surface_get_extents (&surface->base, &extents);
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    if (_cairo_operator_bounded_by_source (op)) {
	cairo_rectangle_int_t source_extents;

	status = _cairo_pattern_get_extents (source, &source_extents);
	if (status)
	    return status;

	is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
    }

    is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);

    status = _add_operation (surface, &extents, backend_status);

    return status;
}
static cairo_int_status_t
_cairo_analysis_surface_show_text_glyphs (void			    *abstract_surface,
					  cairo_operator_t	     op,
					  const cairo_pattern_t	    *source,
					  const char		    *utf8,
					  int			     utf8_len,
					  cairo_glyph_t		    *glyphs,
					  int			     num_glyphs,
					  const cairo_text_cluster_t *clusters,
					  int			     num_clusters,
					  cairo_text_cluster_flags_t cluster_flags,
					  cairo_scaled_font_t	    *scaled_font,
					  cairo_rectangle_int_t     *show_text_glyphs_extents)
{
    cairo_analysis_surface_t *surface = abstract_surface;
    cairo_status_t	     status, backend_status;
    cairo_rectangle_int_t    extents, glyph_extents;
    cairo_bool_t             is_empty;

    /* Adapted from _cairo_surface_show_glyphs */
    backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
    if (surface->target->backend->show_text_glyphs)
	backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
								     source,
								     utf8, utf8_len,
								     glyphs, num_glyphs,
								     clusters, num_clusters, cluster_flags,
								     scaled_font, NULL);
    if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs) {
	int remaining_glyphs = num_glyphs;
	backend_status = surface->target->backend->show_glyphs (surface->target, op,
								source,
								glyphs, num_glyphs,
								scaled_font,
								&remaining_glyphs, NULL);
	glyphs += num_glyphs - remaining_glyphs;
	num_glyphs = remaining_glyphs;
	if (remaining_glyphs == 0)
	    backend_status = CAIRO_STATUS_SUCCESS;
    }

    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
	backend_status = _analyze_meta_surface_pattern (surface, source);

    status = _cairo_surface_get_extents (&surface->base, &extents);
    if (_cairo_status_is_error (status))
	return status;

    if (_cairo_operator_bounded_by_source (op)) {
	cairo_rectangle_int_t source_extents;

	status = _cairo_pattern_get_extents (source, &source_extents);
	if (unlikely (status))
	    return status;

	is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
    }

    is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);

    if (_cairo_operator_bounded_by_mask (op)) {
	status = _cairo_scaled_font_glyph_device_extents (scaled_font,
							  glyphs,
							  num_glyphs,
							  &glyph_extents);
	if (unlikely (status))
	    return status;

	is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
    }
    if (show_text_glyphs_extents)
	*show_text_glyphs_extents = extents;

    status = _add_operation (surface, &extents, backend_status);

    return status;
}
static cairo_int_status_t
_cairo_analysis_surface_mask (void		*abstract_surface,
			      cairo_operator_t	 op,
			      const cairo_pattern_t	*source,
			      const cairo_pattern_t	*mask,
			      cairo_rectangle_int_t 	*mask_extents)
{
    cairo_analysis_surface_t *surface = abstract_surface;
    cairo_int_status_t	      status, backend_status;
    cairo_rectangle_int_t   extents;
    cairo_bool_t is_empty;

    if (!surface->target->backend->mask)
	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
    else
	backend_status = (*surface->target->backend->mask) (surface->target, op,
                                                            source, mask, NULL);

    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) {
	cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
	cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS;

	if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
	    const cairo_surface_pattern_t *surface_pattern = (const cairo_surface_pattern_t *) source;
	    if (_cairo_surface_is_meta (surface_pattern->surface)) {
		backend_source_status =
		    _analyze_meta_surface_pattern (surface, source);
		if (_cairo_status_is_error (backend_source_status))
		    return backend_source_status;
	    }
	}

	if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
	    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
	    if (_cairo_surface_is_meta (surface_pattern->surface)) {
		backend_mask_status =
		    _analyze_meta_surface_pattern (surface, mask);
		if (_cairo_status_is_error (backend_mask_status))
		    return backend_mask_status;
	    }
	}

	backend_status =
	    _cairo_analysis_surface_merge_status (backend_source_status,
						  backend_mask_status);
    }

    status = _cairo_surface_get_extents (&surface->base, &extents);
    if (_cairo_status_is_error (status))
	return status;

    if (_cairo_operator_bounded_by_source (op)) {
	cairo_rectangle_int_t source_extents;

	status = _cairo_pattern_get_extents (source, &source_extents);
	if (unlikely (status))
	    return status;

	is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
    }

    if (_cairo_operator_bounded_by_mask (op)) {
	cairo_rectangle_int_t mask_extents;

	status = _cairo_pattern_get_extents (mask, &mask_extents);
	if (unlikely (status))
	    return status;

	is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
    }

    is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
    if (mask_extents)
	*mask_extents = extents;

    status = _add_operation (surface, &extents, backend_status);

    return status;
}
cairo_status_t
_cairo_surface_fallback_stroke (cairo_surface_t		*surface,
				cairo_operator_t	 op,
				cairo_pattern_t		*source,
				cairo_path_fixed_t	*path,
				cairo_stroke_style_t	*stroke_style,
				cairo_matrix_t		*ctm,
				cairo_matrix_t		*ctm_inverse,
				double			 tolerance,
				cairo_antialias_t	 antialias)
{
    cairo_status_t status;
    cairo_traps_t traps;
    cairo_box_t box;
    cairo_rectangle_int_t extents;

    status = _cairo_surface_get_extents (surface, &extents);
    if (status)
        return status;

    if (_cairo_operator_bounded_by_source (op)) {
	cairo_rectangle_int_t source_extents;
	status = _cairo_pattern_get_extents (source, &source_extents);
	if (status)
	    return status;

	_cairo_rectangle_intersect (&extents, &source_extents);
    }

    status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
    if (status)
        return status;

    box.p1.x = _cairo_fixed_from_int (extents.x);
    box.p1.y = _cairo_fixed_from_int (extents.y);
    box.p2.x = _cairo_fixed_from_int (extents.x + extents.width);
    box.p2.y = _cairo_fixed_from_int (extents.y + extents.height);

    _cairo_traps_init (&traps);

    _cairo_traps_limit (&traps, &box);

    status = _cairo_path_fixed_stroke_to_traps (path,
						stroke_style,
						ctm, ctm_inverse,
						tolerance,
						&traps);
    if (status) {
	_cairo_traps_fini (&traps);
	return status;
    }

    status = _clip_and_composite_trapezoids (source,
				             op,
					     surface,
					     &traps,
					     surface->clip,
					     antialias);

    _cairo_traps_fini (&traps);

    return status;
}
static cairo_int_status_t
_cairo_image_surface_composite (cairo_operator_t	op,
				cairo_pattern_t		*src_pattern,
				cairo_pattern_t		*mask_pattern,
				void			*abstract_dst,
				int			src_x,
				int			src_y,
				int			mask_x,
				int			mask_y,
				int			dst_x,
				int			dst_y,
				unsigned int		width,
				unsigned int		height)
{
    cairo_surface_attributes_t	src_attr, mask_attr;
    cairo_image_surface_t	*dst = abstract_dst;
    cairo_image_surface_t	*src;
    cairo_image_surface_t	*mask;
    cairo_int_status_t		status;

    status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
					      &dst->base,
					      src_x, src_y,
					      mask_x, mask_y,
					      width, height,
					      (cairo_surface_t **) &src,
					      (cairo_surface_t **) &mask,
					      &src_attr, &mask_attr);
    if (status)
	return status;
    
    status = _cairo_image_surface_set_attributes (src, &src_attr);
    if (status)
      goto CLEANUP_SURFACES;

    if (mask)
    {
	status = _cairo_image_surface_set_attributes (mask, &mask_attr);
	if (status)
	    goto CLEANUP_SURFACES;
	
	pixman_composite (_pixman_operator (op),
			  src->pixman_image,
			  mask->pixman_image,
			  dst->pixman_image,
			  src_x + src_attr.x_offset,
			  src_y + src_attr.y_offset,
			  mask_x + mask_attr.x_offset,
			  mask_y + mask_attr.y_offset,
			  dst_x, dst_y,
			  width, height);
    }
    else
    {
	pixman_composite (_pixman_operator (op),
			  src->pixman_image,
			  NULL,
			  dst->pixman_image,
			  src_x + src_attr.x_offset,
			  src_y + src_attr.y_offset,
			  0, 0,
			  dst_x, dst_y,
			  width, height);
    }
    
    if (!_cairo_operator_bounded_by_source (op))
	status = _cairo_surface_composite_fixup_unbounded (&dst->base,
							   &src_attr, src->width, src->height,
							   mask ? &mask_attr : NULL,
							   mask ? mask->width : 0,
							   mask ? mask->height : 0,
							   src_x, src_y,
							   mask_x, mask_y,
							   dst_x, dst_y, width, height);

 CLEANUP_SURFACES:
    if (mask)
	_cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
    
    _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
    
    return status;
}
cairo_status_t
_cairo_surface_fallback_fill (cairo_surface_t		*surface,
			      cairo_operator_t		 op,
			      const cairo_pattern_t	*source,
			      cairo_path_fixed_t	*path,
			      cairo_fill_rule_t		 fill_rule,
			      double			 tolerance,
			      cairo_antialias_t		 antialias)
{
    cairo_status_t status;
    cairo_traps_t traps;
    cairo_box_t box;
    cairo_rectangle_int_t extents;

    status = _cairo_surface_get_extents (surface, &extents);
    if (unlikely (status))
        return status;

    if (_cairo_operator_bounded_by_source (op)) {
	cairo_rectangle_int_t source_extents;

	status = _cairo_pattern_get_extents (source, &source_extents);
	if (unlikely (status))
	    return status;

	if (! _cairo_rectangle_intersect (&extents, &source_extents))
	    return CAIRO_STATUS_SUCCESS;
    }

    status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
    if (unlikely (status))
        return status;

    if (extents.width == 0 || extents.height == 0)
	return CAIRO_STATUS_SUCCESS;

    /* Ask if the surface would like to render this combination of
     * op/source/dst/antialias with spans or not, but don't actually
     * make a renderer yet.  We'll try to hit the region optimisations
     * in _clip_and_composite_trapezoids() if it looks like the path
     * is a region. */
    /* TODO: Until we have a mono scan converter we won't even try
     * to use spans for CAIRO_ANTIALIAS_NONE. */
    /* TODO: The region filling code should be lifted from
     * _clip_and_composite_trapezoids() and given first priority
     * explicitly before deciding between spans and trapezoids. */
    if (antialias != CAIRO_ANTIALIAS_NONE &&
	!_cairo_path_fixed_is_box (path, &box) &&
	!_cairo_path_fixed_is_region (path) &&
	_cairo_surface_check_span_renderer (
	    op, source, surface, antialias, NULL))
    {
	cairo_composite_spans_fill_info_t info;
	info.path = path;
	info.fill_rule = fill_rule;
	info.tolerance = tolerance;
	info.antialias = antialias;

	if (_cairo_operator_bounded_by_mask (op)) {
	    cairo_rectangle_int_t path_extents;

	    _cairo_path_fixed_approximate_clip_extents (path,
							&path_extents);
	    if (! _cairo_rectangle_intersect (&extents, &path_extents))
		return CAIRO_STATUS_SUCCESS;
	}

	return _clip_and_composite (
	    surface->clip, op, source,
	    _composite_spans_fill_func,
	    &info,
	    surface,
	    &extents);
    }

    /* Fall back to trapezoid fills. */
    _cairo_box_from_rectangle (&box, &extents);
    _cairo_traps_init (&traps);
    _cairo_traps_limit (&traps, &box);

    status = _cairo_path_fixed_fill_to_traps (path,
					      fill_rule,
					      tolerance,
					      &traps);
    if (unlikely (status)) {
	_cairo_traps_fini (&traps);
	return status;
    }

    status = _clip_and_composite_trapezoids (source,
					     op,
					     surface,
					     &traps,
					     surface->clip,
					     antialias);

    _cairo_traps_fini (&traps);

    return status;
}
cairo_status_t
_cairo_surface_fallback_stroke (cairo_surface_t		*surface,
				cairo_operator_t	 op,
				const cairo_pattern_t	*source,
				cairo_path_fixed_t	*path,
				cairo_stroke_style_t	*stroke_style,
				cairo_matrix_t		*ctm,
				cairo_matrix_t		*ctm_inverse,
				double			 tolerance,
				cairo_antialias_t	 antialias)
{
    cairo_status_t status;
    cairo_traps_t traps;
    cairo_box_t box;
    cairo_rectangle_int_t extents;

    status = _cairo_surface_get_extents (surface, &extents);
    if (unlikely (status))
        return status;

    if (_cairo_operator_bounded_by_source (op)) {
	cairo_rectangle_int_t source_extents;
	status = _cairo_pattern_get_extents (source, &source_extents);
	if (unlikely (status))
	    return status;

	if (! _cairo_rectangle_intersect (&extents, &source_extents))
	    return CAIRO_STATUS_SUCCESS;
    }

    status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
    if (unlikely (status))
        return status;

    if (extents.width == 0 || extents.height == 0)
	return CAIRO_STATUS_SUCCESS;

    _cairo_box_from_rectangle (&box, &extents);

    _cairo_traps_init (&traps);
    _cairo_traps_limit (&traps, &box);

    status = _cairo_path_fixed_stroke_to_traps (path,
						stroke_style,
						ctm, ctm_inverse,
						tolerance,
						&traps);
    if (unlikely (status))
	goto FAIL;

    status = _clip_and_composite_trapezoids (source,
				             op,
					     surface,
					     &traps,
					     surface->clip,
					     antialias);

FAIL:
    _cairo_traps_fini (&traps);

    return status;
}
Beispiel #9
0
static cairo_int_status_t _cairo_xynth_surface_composite (cairo_operator_t cairo_operator, cairo_pattern_t *src_pattern, cairo_pattern_t *mask_pattern, void *abstract_surface, int src_x, int src_y, int mask_x, int mask_y, int dst_x, int dst_y, unsigned int width, unsigned int height)
{
	cairo_int_status_t status;
	cairo_xynth_surface_t *dst;
	cairo_xynth_surface_t *src;
	cairo_xynth_surface_t *mask;
	cairo_surface_attributes_t src_attr;
	cairo_surface_attributes_t mask_attr;
	ENTER();
	dst = (cairo_xynth_surface_t *) abstract_surface;
	status = _cairo_pattern_acquire_surfaces(src_pattern, mask_pattern, &dst->cairo, src_x, src_y, mask_x, mask_y, width, height, (cairo_surface_t **) &src, (cairo_surface_t **) &mask, &src_attr, &mask_attr);
	if (status) {
		return status;
	}
	status = _cairo_xynth_surface_set_attributes(src, &src_attr);
	if (status) {
		goto out;
	}
	if (mask) {
		status = _cairo_xynth_surface_set_attributes(mask, &mask_attr);
		if (status) {
			goto out;
		}
		s_render_composite(_cairo_xynth_operator(cairo_operator),
	                           src->render,
	                           mask->render,
	                           dst->render,
	                           src_x + src_attr.x_offset,
	                           src_y + src_attr.y_offset,
	                           mask_x + mask_attr.x_offset,
	                           mask_y + mask_attr.y_offset,
	                           dst_x, dst_y,
	                           width, height);
	} else {
		s_render_composite(_cairo_xynth_operator(cairo_operator),
		                   src->render,
		                   NULL,
		                   dst->render,
		                   src_x + src_attr.x_offset,
		                   src_y + src_attr.y_offset,
		                   0, 0,
		                   dst_x, dst_y,
		                   width, height);
	}
	if (!_cairo_operator_bounded_by_source(cairo_operator)) {
		status = _cairo_surface_composite_fixup_unbounded(&dst->cairo,
		                                                  &src_attr, src->render->width, src->render->height,
		                                                  mask ? &mask_attr : NULL,
		                                                  mask ? mask->render->width : 0,
		                                                  mask ? mask->render->height : 0,
		                                                  src_x, src_y,
		                                                  mask_x, mask_y,
		                                                  dst_x, dst_y,
		                                                  width, height);
	}
 out: 	if (mask) {
 		_cairo_pattern_release_surface(mask_pattern, &mask->cairo, &mask_attr);
 	}
 	_cairo_pattern_release_surface(src_pattern, &src->cairo, &src_attr);
	LEAVE();
	return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_analysis_surface_show_glyphs (void		  *abstract_surface,
				     cairo_operator_t	   op,
				     cairo_pattern_t	  *source,
				     cairo_glyph_t	  *glyphs,
				     int		   num_glyphs,
				     cairo_scaled_font_t  *scaled_font,
				     int                  *remaining_glyphs)
{
    cairo_analysis_surface_t *surface = abstract_surface;
    cairo_status_t	     status, backend_status;
    cairo_rectangle_int_t    extents, glyph_extents;

    /* Adapted from _cairo_surface_show_glyphs */
    if (surface->target->backend->show_glyphs)
	backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
								   source,
								   glyphs, num_glyphs,
								   scaled_font,
								   remaining_glyphs);
    else if (surface->target->backend->show_text_glyphs)
	backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
								     source,
								     NULL, 0,
								     glyphs, num_glyphs,
								     NULL, 0,
								     FALSE,
								     scaled_font);
    else
	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;

    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
	backend_status = _analyze_meta_surface_pattern (surface, source);

    status = _cairo_surface_get_extents (&surface->base, &extents);
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    if (_cairo_operator_bounded_by_source (op)) {
	cairo_rectangle_int_t source_extents;
	status = _cairo_pattern_get_extents (source, &source_extents);
	if (status)
	    return status;

	_cairo_rectangle_intersect (&extents, &source_extents);
    }

    _cairo_rectangle_intersect (&extents, &surface->current_clip);

    if (_cairo_operator_bounded_by_mask (op)) {
	status = _cairo_scaled_font_glyph_device_extents (scaled_font,
							  glyphs,
							  num_glyphs,
							  &glyph_extents);
	if (status)
	    return status;

	_cairo_rectangle_intersect (&extents, &glyph_extents);
    }

    status = _add_operation (surface, &extents, backend_status);

    return status;
}
static cairo_int_status_t
_cairo_analysis_surface_fill (void			*abstract_surface,
			      cairo_operator_t		 op,
			      cairo_pattern_t		*source,
			      cairo_path_fixed_t	*path,
			      cairo_fill_rule_t		 fill_rule,
			      double			 tolerance,
			      cairo_antialias_t		 antialias)
{
    cairo_analysis_surface_t *surface = abstract_surface;
    cairo_status_t	     status, backend_status;
    cairo_traps_t            traps;
    cairo_rectangle_int_t  extents;

    if (!surface->target->backend->fill)
	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
    else
	backend_status = (*surface->target->backend->fill) (surface->target, op,
						    source, path, fill_rule,
						    tolerance, antialias);

    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
	backend_status = _analyze_meta_surface_pattern (surface, source);

    status = _cairo_surface_get_extents (&surface->base, &extents);
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    if (_cairo_operator_bounded_by_source (op)) {
	cairo_rectangle_int_t source_extents;
	status = _cairo_pattern_get_extents (source, &source_extents);
	if (status)
	    return status;

	_cairo_rectangle_intersect (&extents, &source_extents);
    }

    _cairo_rectangle_intersect (&extents, &surface->current_clip);

    if (_cairo_operator_bounded_by_mask (op)) {
	cairo_box_t box;

	_cairo_box_from_rectangle (&box, &extents);

	_cairo_traps_init (&traps);
	_cairo_traps_limit (&traps, &box);
	status = _cairo_path_fixed_fill_to_traps (path,
						  fill_rule,
						  tolerance,
						  &traps);
	if (status) {
	    _cairo_traps_fini (&traps);
	    return status;
	}

	_cairo_traps_extents (&traps, &box);
	_cairo_traps_fini (&traps);

        _cairo_box_round_to_rectangle (&box, &extents);
    }

    status = _add_operation (surface, &extents, backend_status);

    return status;
}