예제 #1
0
static void
_cairo_clip_set_all_clipped (cairo_clip_t *clip, cairo_surface_t *target)
{
    _cairo_clip_reset (clip);

    clip->all_clipped = TRUE;
    clip->serial = _cairo_surface_allocate_clip_serial (target);
}
예제 #2
0
cairo_status_t
_cairo_clip_clip (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_status_t status;
    cairo_traps_t traps;
    cairo_path_fixed_t path_transformed;

    if (_cairo_surface_has_device_offset_or_scale (target)) {
	_cairo_path_fixed_init_copy (&path_transformed, path);
	_cairo_path_fixed_offset (&path_transformed,
				  _cairo_fixed_from_double (target->device_x_offset),
				  _cairo_fixed_from_double (target->device_y_offset));
	path = &path_transformed;
    }
    
    status = _cairo_clip_intersect_path (clip,
					 path, fill_rule, tolerance,
					 antialias);
    if (status == CAIRO_STATUS_SUCCESS)
        clip->serial = _cairo_surface_allocate_clip_serial (target);

    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;


    _cairo_traps_init (&traps);
    status = _cairo_path_fixed_fill_to_traps (path,
					      fill_rule,
					      tolerance,
					      &traps);
    if (status)
	goto bail;

    status = _cairo_clip_intersect_region (clip, &traps, target);
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	goto bail;

    status = _cairo_clip_intersect_mask (clip, &traps, antialias, target);
	
 bail:
    _cairo_traps_fini (&traps);
    if (path == &path_transformed)
	_cairo_path_fixed_fini (&path_transformed);

    return status;
}
예제 #3
0
cairo_status_t
_cairo_clip_clip (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_status_t status;
    cairo_traps_t traps;

    if (clip->all_clipped)
	return CAIRO_STATUS_SUCCESS;

    /* catch the empty clip path */
    if (! path->has_current_point) {
	_cairo_clip_set_all_clipped (clip, target);
	return CAIRO_STATUS_SUCCESS;
    }

    status = _cairo_clip_intersect_path (clip,
					 path, fill_rule, tolerance,
					 antialias);
    if (status == CAIRO_STATUS_SUCCESS)
        clip->serial = _cairo_surface_allocate_clip_serial (target);

    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    _cairo_traps_init (&traps);
    status = _cairo_path_fixed_fill_to_traps (path,
					      fill_rule,
					      tolerance,
					      &traps);
    if (status)
	goto bail;

    status = _cairo_clip_intersect_region (clip, &traps, target);
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	goto bail;

    status = _cairo_clip_intersect_mask (clip, &traps, antialias, target);

 bail:
    _cairo_traps_fini (&traps);

    return status;
}
예제 #4
0
static cairo_int_status_t
_cairo_clip_intersect_region (cairo_clip_t    *clip,
			      cairo_traps_t   *traps,
			      cairo_surface_t *target)
{
    cairo_region_t region;
    cairo_int_status_t status;

    if (clip->all_clipped)
	return CAIRO_STATUS_SUCCESS;

    if (clip->mode != CAIRO_CLIP_MODE_REGION)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    status = _cairo_traps_extract_region (traps, &region);

    if (status)
	return status;

    status = CAIRO_STATUS_SUCCESS;

    if (!clip->has_region) {
        status = _cairo_region_copy (&clip->region, &region);
	if (status == CAIRO_STATUS_SUCCESS)
	    clip->has_region = TRUE;
    } else {
	cairo_region_t intersection;
        _cairo_region_init (&intersection);

	status = _cairo_region_intersect (&intersection,
		                         &clip->region,
		                         &region);

	if (status == CAIRO_STATUS_SUCCESS)
	    status = _cairo_region_copy (&clip->region, &intersection);

        _cairo_region_fini (&intersection);
    }

    clip->serial = _cairo_surface_allocate_clip_serial (target);
    _cairo_region_fini (&region);

    if (! _cairo_region_not_empty (&clip->region))
	_cairo_clip_set_all_clipped (clip, target);

    return status;
}
예제 #5
0
static cairo_status_t
_cairo_clip_intersect_region (cairo_clip_t    *clip,
			      cairo_traps_t   *traps,
			      cairo_surface_t *target)
{
    pixman_region16_t *region;
    cairo_status_t status;

    if (clip->mode != CAIRO_CLIP_MODE_REGION)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    status = _cairo_traps_extract_region (traps, &region);
    if (status)
	return status;

    if (region == NULL)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    status = CAIRO_STATUS_SUCCESS;
    if (clip->region == NULL) {
	clip->region = region;
    } else {
	pixman_region16_t *intersection = pixman_region_create();

	if (pixman_region_intersect (intersection,
				     clip->region, region)
	    == PIXMAN_REGION_STATUS_SUCCESS) {
	    pixman_region_destroy (clip->region);
	    clip->region = intersection;
	} else {
	    status = CAIRO_STATUS_NO_MEMORY;
	}
	pixman_region_destroy (region);
    }

    clip->serial = _cairo_surface_allocate_clip_serial (target);

    return status;
}
예제 #6
0
static cairo_status_t
_cairo_clip_intersect_mask (cairo_clip_t      *clip,
			    cairo_traps_t     *traps,
			    cairo_antialias_t antialias,
			    cairo_surface_t   *target)
{
    cairo_pattern_union_t pattern;
    cairo_box_t extents;
    cairo_rectangle_int16_t surface_rect, target_rect;
    cairo_surface_t *surface;
    cairo_status_t status;

    /* Represent the clip as a mask surface.  We create a new surface
     * the size of the intersection of the old mask surface and the
     * extents of the new clip path. */

    _cairo_traps_extents (traps, &extents);
    _cairo_box_round_to_rectangle (&extents, &surface_rect);

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

    /* Intersect with the target surface rectangle so we don't use
     * more memory and time than we need to. */

    status = _cairo_surface_get_extents (target, &target_rect);
    if (!status)
	_cairo_rectangle_intersect (&surface_rect, &target_rect);

    surface = _cairo_surface_create_similar_solid (target,
						   CAIRO_CONTENT_ALPHA,
						   surface_rect.width,
						   surface_rect.height,
						   CAIRO_COLOR_WHITE);
    if (surface->status)
	return CAIRO_STATUS_NO_MEMORY;

    /* Render the new clipping path into the new mask surface. */

    _cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y);
    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);

    status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
						  &pattern.base,
						  surface,
						  antialias,
						  0, 0,
						  0, 0,
						  surface_rect.width,
						  surface_rect.height,
						  traps->traps,
						  traps->num_traps);

    _cairo_pattern_fini (&pattern.base);

    if (status) {
	cairo_surface_destroy (surface);
	return status;
    }

    /* If there was a clip surface already, combine it with the new
     * mask surface using the IN operator, so we get the intersection
     * of the old and new clipping paths. */

    if (clip->surface != NULL) {
	_cairo_pattern_init_for_surface (&pattern.surface, clip->surface);

	status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
					   &pattern.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 (&pattern.base);

	if (status) {
	    cairo_surface_destroy (surface);
	    return status;
	}

	cairo_surface_destroy (clip->surface);
    }

    clip->surface = surface;
    clip->surface_rect = surface_rect;
    clip->serial = _cairo_surface_allocate_clip_serial (target);

    return status;
}
예제 #7
0
/* Composites a region representing a set of trapezoids.
 */
static cairo_status_t
_composite_trap_region (cairo_clip_t            *clip,
			cairo_pattern_t         *src,
			cairo_operator_t         op,
			cairo_surface_t         *dst,
			cairo_region_t          *trap_region,
			cairo_rectangle_int_t   *extents)
{
    cairo_status_t status;
    cairo_pattern_union_t solid_pattern;
    cairo_pattern_union_t mask;
    int num_rects = _cairo_region_num_boxes (trap_region);
    unsigned int clip_serial;
    cairo_surface_t *clip_surface = clip ? clip->surface : NULL;

    if (clip_surface && op == CAIRO_OPERATOR_CLEAR) {
	_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE,
				   CAIRO_CONTENT_COLOR);
	src = &solid_pattern.base;
	op = CAIRO_OPERATOR_DEST_OUT;
    }

    if (num_rects == 0)
	return CAIRO_STATUS_SUCCESS;

    if (num_rects > 1) {
      if (_cairo_surface_get_clip_mode (dst) != CAIRO_CLIP_MODE_REGION)
	    return CAIRO_INT_STATUS_UNSUPPORTED;

	clip_serial = _cairo_surface_allocate_clip_serial (dst);
	status = _cairo_surface_set_clip_region (dst,
						 trap_region,
						 clip_serial);
	if (status)
	    return status;
    }

    if (clip_surface)
	_cairo_pattern_init_for_surface (&mask.surface, clip_surface);

    status = _cairo_surface_composite (op,
				       src,
				       clip_surface ? &mask.base : NULL,
				       dst,
				       extents->x, extents->y,
				       extents->x - (clip_surface ? clip->surface_rect.x : 0),
				       extents->y - (clip_surface ? clip->surface_rect.y : 0),
				       extents->x, extents->y,
				       extents->width, extents->height);

    /* Restore the original clip if we modified it temporarily. */
    if (num_rects > 1) {
	cairo_status_t status2 = _cairo_surface_set_clip (dst, clip);
	if (status == CAIRO_STATUS_SUCCESS)
	    status = status2;
    }

    if (clip_surface)
      _cairo_pattern_fini (&mask.base);

    if (src == &solid_pattern.base)
	_cairo_pattern_fini (&solid_pattern.base);

    return status;
}
예제 #8
0
static cairo_status_t
_cairo_clip_intersect_mask (cairo_clip_t      *clip,
			    cairo_traps_t     *traps,
			    cairo_antialias_t antialias,
			    cairo_surface_t   *target)
{
    cairo_pattern_union_t pattern;
    cairo_box_t extents;
    cairo_rectangle_int_t surface_rect, target_rect;
    cairo_surface_t *surface;
    cairo_status_t status;

    if (clip->all_clipped)
	return CAIRO_STATUS_SUCCESS;

    /* Represent the clip as a mask surface.  We create a new surface
     * the size of the intersection of the old mask surface and the
     * extents of the new clip path. */

    _cairo_traps_extents (traps, &extents);
    _cairo_box_round_to_rectangle (&extents, &surface_rect);

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

    /* Intersect with the target surface rectangle so we don't use
     * more memory and time than we need to. */

    status = _cairo_surface_get_extents (target, &target_rect);
    if (!status)
	_cairo_rectangle_intersect (&surface_rect, &target_rect);

    if (surface_rect.width == 0 || surface_rect.height == 0) {
	surface = NULL;
	status = CAIRO_STATUS_SUCCESS;
	if (clip->surface != NULL)
	    cairo_surface_destroy (clip->surface);
	goto DONE;
    }

    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
			       CAIRO_CONTENT_COLOR);
    /* The clipping operation should ideally be something like the following to
     * avoid having to do as many passes over the data

	if (clip->surface != NULL) {
	    _cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
	} else {
	    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
			       CAIRO_CONTENT_COLOR);
	}
	status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
						  &pattern.base,
						  surface,
						  antialias,
						  0, 0,
						  0, 0,
						  surface_rect.width,
						  surface_rect.height,
						  traps->traps,
						  traps->num_traps);

	However this operation is not accelerated by pixman

	I believe the best possible operation would probably an unbounded SRC
	operator.  Using SRC we could potentially avoid having to initialize
	the surface which would be ideal from an efficiency point of view.
	However, _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_SOURCE) is
	bounded by the mask.

    */

    surface = _cairo_surface_create_similar_solid (target,
						   CAIRO_CONTENT_ALPHA,
						   surface_rect.width,
						   surface_rect.height,
						   CAIRO_COLOR_TRANSPARENT,
						   &pattern.base);
    if (surface->status) {
	_cairo_pattern_fini (&pattern.base);
	return surface->status;
    }

    /* Render the new clipping path into the new mask surface. */

    _cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y);

    status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
						  &pattern.base,
						  surface,
						  antialias,
						  0, 0,
						  0, 0,
						  surface_rect.width,
						  surface_rect.height,
						  traps->traps,
						  traps->num_traps);

    _cairo_pattern_fini (&pattern.base);

    if (status) {
	cairo_surface_destroy (surface);
	return status;
    }

    /* If there was a clip surface already, combine it with the new
     * mask surface using the IN operator, so we get the intersection
     * of the old and new clipping paths. */

    if (clip->surface != NULL) {
	_cairo_pattern_init_for_surface (&pattern.surface, clip->surface);

	status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
					   &pattern.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 (&pattern.base);

	if (status) {
	    cairo_surface_destroy (surface);
	    return status;
	}

	cairo_surface_destroy (clip->surface);
    }

 DONE:
    clip->surface = surface;
    clip->surface_rect = surface_rect;
    clip->serial = _cairo_surface_allocate_clip_serial (target);

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

    return status;
}
예제 #9
0
cairo_status_t
_cairo_clip_clip (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_status_t status;
    cairo_rectangle_int_t rectangle;
    cairo_traps_t traps;
    cairo_box_t ignored_box;

    if (clip->all_clipped)
	return CAIRO_STATUS_SUCCESS;

    /* catch the empty clip path */
    if (! path->has_current_point) {
	_cairo_clip_set_all_clipped (clip, target);
	return CAIRO_STATUS_SUCCESS;
    }

    status = _cairo_clip_intersect_path (clip,
					 path, fill_rule, tolerance,
					 antialias);
    if (status == CAIRO_STATUS_SUCCESS)
        clip->serial = _cairo_surface_allocate_clip_serial (target);

    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    /* TODO: allow ANTIALIAS_NONE when we have a mono scan converter
     * again. */
    if (antialias != CAIRO_ANTIALIAS_NONE &&
	!_cairo_path_fixed_is_box (path, &ignored_box) &&
	!_cairo_path_fixed_is_region (path))
    {
	status = _cairo_clip_intersect_mask_using_spans (
	    clip, path, fill_rule, tolerance, antialias, target);
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	    return status;
    }

    _cairo_traps_init (&traps);

    /* Limit the traps to the target surface
     * - so we don't add more traps than needed. */
    status = _cairo_surface_get_extents (target, &rectangle);
    if (status == CAIRO_STATUS_SUCCESS) {
	cairo_box_t box;

	_cairo_box_from_rectangle (&box, &rectangle);
	_cairo_traps_limit (&traps, &box);
    }

    status = _cairo_path_fixed_fill_to_traps (path,
					      fill_rule,
					      tolerance,
					      &traps);
    if (unlikely (status))
	goto bail;

    status = _cairo_clip_intersect_region (clip, &traps, target);
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	goto bail;

    status = _cairo_clip_intersect_mask (clip, &traps, antialias, target);

 bail:
    _cairo_traps_fini (&traps);

    return status;
}
예제 #10
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;
}