cairo_status_t
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
				 cairo_fill_rule_t fill_rule,
				 double tolerance,
				 cairo_traps_t *traps)
{
    cairo_polygon_t polygon;
    cairo_status_t status;

    if (path->is_empty_fill)
	return CAIRO_STATUS_SUCCESS;

    _cairo_polygon_init (&polygon);
    _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);

    status = _cairo_path_fixed_fill_to_polygon (path,
						tolerance,
						&polygon);
    if (unlikely (status || polygon.num_edges == 0))
	goto CLEANUP;

    if (path->is_rectilinear) {
	status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (traps,
									&polygon,
									fill_rule);
    } else {
	status = _cairo_bentley_ottmann_tessellate_polygon (traps,
							    &polygon,
							    fill_rule);
    }

  CLEANUP:
    _cairo_polygon_fini (&polygon);
    return status;
}
示例#2
0
cairo_status_t
_cairo_path_fixed_fill_rectilinear_to_polygon (const cairo_path_fixed_t *path,
					       cairo_antialias_t antialias,
					       cairo_polygon_t *polygon)
{
    cairo_filler_ra_t filler;
    cairo_status_t status;

    if (antialias != CAIRO_ANTIALIAS_NONE)
	return _cairo_path_fixed_fill_to_polygon (path, 0., polygon);

    filler.polygon = polygon;

    /* make sure that the closure represents a degenerate path */
    filler.current_point.x = 0;
    filler.current_point.y = 0;
    filler.last_move_to = filler.current_point;

    status = _cairo_path_fixed_interpret_flat (path,
					       _cairo_filler_ra_move_to,
					       _cairo_filler_ra_line_to,
					       _cairo_filler_ra_close,
					       &filler,
					       0.);
    if (unlikely (status))
	return status;

    return _cairo_filler_ra_close (&filler);
}
示例#3
0
cairo_int_status_t
_cairo_clip_get_polygon (const cairo_clip_t *clip,
			 cairo_polygon_t *polygon,
			 cairo_fill_rule_t *fill_rule,
			 cairo_antialias_t *antialias)
{
    cairo_status_t status;
    cairo_clip_path_t *clip_path;

    if (_cairo_clip_is_all_clipped (clip)) {
	_cairo_polygon_init (polygon, NULL, 0);
	return CAIRO_INT_STATUS_SUCCESS;
    }

    /* If there is no clip, we need an infinite polygon */
    assert (clip && (clip->path || clip->num_boxes));

    if (clip->path == NULL) {
	*fill_rule = CAIRO_FILL_RULE_WINDING;
	*antialias = CAIRO_ANTIALIAS_DEFAULT;
	return _cairo_polygon_init_box_array (polygon,
					      clip->boxes,
					      clip->num_boxes);
    }

    /* check that residual is all of the same type/tolerance */
    if (! can_convert_to_polygon (clip))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    if (clip->num_boxes < 2)
	_cairo_polygon_init_with_clip (polygon, clip);
    else
	_cairo_polygon_init_with_clip (polygon, NULL);

    clip_path = clip->path;
    *fill_rule = clip_path->fill_rule;
    *antialias = clip_path->antialias;

    status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
						clip_path->tolerance,
						polygon);
    if (unlikely (status))
	goto err;

    if (clip->num_boxes > 1) {
	status = _cairo_polygon_intersect_with_boxes (polygon, fill_rule,
						      clip->boxes, clip->num_boxes);
	if (unlikely (status))
	    goto err;
    }

    polygon->limits = NULL;
    polygon->num_limits = 0;

    while ((clip_path = clip_path->prev) != NULL) {
	cairo_polygon_t next;

	_cairo_polygon_init (&next, NULL, 0);
	status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
						    clip_path->tolerance,
						    &next);
	if (likely (status == CAIRO_STATUS_SUCCESS))
		status = _cairo_polygon_intersect (polygon, *fill_rule,
						   &next, clip_path->fill_rule);
	_cairo_polygon_fini (&next);
	if (unlikely (status))
	    goto err;

	*fill_rule = CAIRO_FILL_RULE_WINDING;
    }

    return CAIRO_STATUS_SUCCESS;

err:
    _cairo_polygon_fini (polygon);
    return status;
}
static cairo_region_t *
_cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_t	*path,
							 cairo_fill_rule_t	 fill_rule,
							 const cairo_rectangle_int_t *extents)
{
    cairo_box_t box;
    cairo_polygon_t polygon;
    cairo_traps_t traps;
    cairo_status_t status;
    cairo_region_t *region;

    /* first try to bypass fill-to-polygon */
    _cairo_traps_init (&traps);
    status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
							  fill_rule,
							  &traps);
    if (_cairo_status_is_error (status))
	goto CLEANUP_TRAPS;

    if (status == CAIRO_STATUS_SUCCESS) {
	status = _cairo_traps_extract_region (&traps, &region);
	goto CLEANUP_TRAPS;
    }

    /* path is not rectangular, try extracting clipped rectilinear edges */
    _cairo_polygon_init (&polygon);
    if (extents != NULL) {
	_cairo_box_from_rectangle (&box, extents);
	_cairo_polygon_limit (&polygon, &box, 1);
    }

    /* tolerance will be ignored as the path is rectilinear */
    status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
    if (unlikely (status))
	goto CLEANUP_POLYGON;

    if (polygon.num_edges == 0) {
	region = cairo_region_create ();
    } else {
	status =
	    _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
								   &polygon,
								   fill_rule);
	if (likely (status == CAIRO_STATUS_SUCCESS))
	    status = _cairo_traps_extract_region (&traps, &region);
    }

  CLEANUP_POLYGON:
    _cairo_polygon_fini (&polygon);

  CLEANUP_TRAPS:
    _cairo_traps_fini (&traps);

    if (unlikely (status)) { /* XXX _cairo_region_create_in_error() */
	region = cairo_region_create ();
	if (likely (region->status) == CAIRO_STATUS_SUCCESS)
	    region->status = status;
    }

    return region;
}
static cairo_surface_t *
get_clip_surface (const cairo_spans_compositor_t *compositor,
		  cairo_surface_t *dst,
		  const cairo_clip_t *clip,
		  const cairo_rectangle_int_t *extents)
{
    cairo_composite_rectangles_t composite;
    cairo_surface_t *surface;
    cairo_box_t box;
    cairo_polygon_t polygon;
    const cairo_clip_path_t *clip_path;
    cairo_antialias_t antialias;
    cairo_fill_rule_t fill_rule;
    cairo_int_status_t status;

    assert (clip->path);

    surface = _cairo_surface_create_similar_solid (dst,
						   CAIRO_CONTENT_ALPHA,
						   extents->width,
						   extents->height,
						   CAIRO_COLOR_TRANSPARENT);

    _cairo_box_from_rectangle (&box, extents);
    _cairo_polygon_init (&polygon, &box, 1);

    clip_path = clip->path;
    status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
						clip_path->tolerance,
						&polygon);
    if (unlikely (status))
	goto cleanup_polygon;

    antialias = clip_path->antialias;
    fill_rule = clip_path->fill_rule;

    if (clip->boxes) {
	cairo_polygon_t intersect;
	cairo_boxes_t tmp;

	_cairo_boxes_init_for_array (&tmp, clip->boxes, clip->num_boxes);
	status= _cairo_polygon_init_boxes (&intersect, &tmp);
	if (unlikely (status))
	    goto cleanup_polygon;

	status = _cairo_polygon_intersect (&polygon, fill_rule,
					   &intersect, CAIRO_FILL_RULE_WINDING);
	_cairo_polygon_fini (&intersect);

	if (unlikely (status))
	    goto cleanup_polygon;

	fill_rule = CAIRO_FILL_RULE_WINDING;
    }

    polygon.limits = NULL;
    polygon.num_limits = 0;

    clip_path = clip_path->prev;
    while (clip_path) {
	if (clip_path->antialias == antialias) {
	    cairo_polygon_t next;

	    _cairo_polygon_init (&next, NULL, 0);
	    status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
							clip_path->tolerance,
							&next);
	    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
		status = _cairo_polygon_intersect (&polygon, fill_rule,
						   &next, clip_path->fill_rule);
	    _cairo_polygon_fini (&next);
	    if (unlikely (status))
		goto cleanup_polygon;

	    fill_rule = CAIRO_FILL_RULE_WINDING;
	}

	clip_path = clip_path->prev;
    }

    _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
    status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
							   CAIRO_OPERATOR_ADD,
							   &_cairo_pattern_white.base,
							   &polygon,
							   NULL);
    if (unlikely (status))
	goto cleanup_polygon;

    status = composite_polygon (compositor, &composite,
				&polygon, fill_rule, antialias);
    _cairo_composite_rectangles_fini (&composite);
    _cairo_polygon_fini (&polygon);
    if (unlikely (status))
	goto error;

    _cairo_polygon_init (&polygon, &box, 1);

    clip_path = clip->path;
    antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT;
    clip_path = clip_path->prev;
    while (clip_path) {
	if (clip_path->antialias == antialias) {
	    if (polygon.num_edges == 0) {
		status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
							    clip_path->tolerance,
							    &polygon);

		fill_rule = clip_path->fill_rule;
		polygon.limits = NULL;
		polygon.num_limits = 0;
	    } else {
		cairo_polygon_t next;

		_cairo_polygon_init (&next, NULL, 0);
		status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
							    clip_path->tolerance,
							    &next);
		if (likely (status == CAIRO_INT_STATUS_SUCCESS))
		    status = _cairo_polygon_intersect (&polygon, fill_rule,
						       &next, clip_path->fill_rule);
		_cairo_polygon_fini (&next);
		fill_rule = CAIRO_FILL_RULE_WINDING;
	    }
	    if (unlikely (status))
		goto error;
	}

	clip_path = clip_path->prev;
    }

    if (polygon.num_edges) {
	_cairo_polygon_translate (&polygon, -extents->x, -extents->y);
	status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
							       CAIRO_OPERATOR_IN,
							       &_cairo_pattern_white.base,
							       &polygon,
							       NULL);
	if (unlikely (status))
	    goto cleanup_polygon;

	status = composite_polygon (compositor, &composite,
				    &polygon, fill_rule, antialias);
	_cairo_composite_rectangles_fini (&composite);
	_cairo_polygon_fini (&polygon);
	if (unlikely (status))
	    goto error;
    }

    return surface;

cleanup_polygon:
    _cairo_polygon_fini (&polygon);
error:
    cairo_surface_destroy (surface);
    return _cairo_int_surface_create_in_error (status);
}
static cairo_int_status_t
_cairo_spans_compositor_fill (const cairo_compositor_t		*_compositor,
			      cairo_composite_rectangles_t	 *extents,
			      const cairo_path_fixed_t		*path,
			      cairo_fill_rule_t			 fill_rule,
			      double				 tolerance,
			      cairo_antialias_t			 antialias)
{
    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
    cairo_int_status_t status;

    TRACE((stderr, "%s op=%d, antialias=%d\n", __FUNCTION__, extents->op, antialias));

    status = CAIRO_INT_STATUS_UNSUPPORTED;
    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
	cairo_boxes_t boxes;

	TRACE((stderr, "%s - rectilinear\n", __FUNCTION__));

	_cairo_boxes_init (&boxes);
	if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
	    _cairo_boxes_limit (&boxes,
				extents->clip->boxes,
				extents->clip->num_boxes);
	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
							      fill_rule,
							      antialias,
							      &boxes);
	if (likely (status == CAIRO_INT_STATUS_SUCCESS))
	    status = clip_and_composite_boxes (compositor, extents, &boxes);
	_cairo_boxes_fini (&boxes);
    }
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
	cairo_polygon_t polygon;

	TRACE((stderr, "%s - polygon\n", __FUNCTION__));

	if (extents->mask.width  > extents->unbounded.width ||
	    extents->mask.height > extents->unbounded.height)
	{
	    cairo_box_t limits;
	    TRACE((stderr, "%s - clipping to bounds\n", __FUNCTION__));
	    _cairo_box_from_rectangle (&limits, &extents->unbounded);
	    _cairo_polygon_init (&polygon, &limits, 1);
	}
	else
	{
	    _cairo_polygon_init (&polygon, NULL, 0);
	}

	status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
	if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
	    TRACE((stderr, "%s - polygon intersect with %d clip boxes\n",
		   __FUNCTION__, extents->clip->num_boxes));
	    status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
							  extents->clip->boxes,
							  extents->clip->num_boxes);
	}
	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
	    cairo_clip_t *saved_clip = extents->clip;

	    if (extents->is_bounded) {
		TRACE((stderr, "%s - polygon discard clip boxes\n",
		       __FUNCTION__));
		extents->clip = _cairo_clip_copy_path (extents->clip);
		extents->clip = _cairo_clip_intersect_box(extents->clip,
							  &polygon.extents);
	    }

	    status = clip_and_composite_polygon (compositor, extents, &polygon,
						 fill_rule, antialias);

	    if (extents->is_bounded) {
		_cairo_clip_destroy (extents->clip);
		extents->clip = saved_clip;
	    }
	}
	_cairo_polygon_fini (&polygon);

	TRACE((stderr, "%s - polygon status=%d\n", __FUNCTION__, status));
    }

    return status;
}
示例#7
0
static cairo_status_t
_rectilinear_clip_to_boxes (const cairo_path_fixed_t *path,
			    cairo_fill_rule_t fill_rule,
			    cairo_box_t **boxes,
			    int *num_boxes,
			    int *size_boxes)
{
    cairo_polygon_t polygon;
    cairo_traps_t traps;
    cairo_status_t status;

    _cairo_traps_init (&traps);
    _cairo_traps_limit (&traps, *boxes, *num_boxes);

    _cairo_polygon_init (&polygon);
    _cairo_polygon_limit (&polygon, *boxes, *num_boxes);

    status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
							  fill_rule,
							  &traps);
    if (unlikely (_cairo_status_is_error (status)))
	goto CLEANUP;
    if (status == CAIRO_STATUS_SUCCESS)
	goto BOXES;

    /* tolerance will be ignored as the path is rectilinear */
    status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
    if (unlikely (status))
	goto CLEANUP;

    if (polygon.num_edges == 0) {
	*num_boxes = 0;
    } else {
	status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
									&polygon,
									fill_rule);
	if (likely (status == CAIRO_STATUS_SUCCESS)) {
	    int i;

          BOXES:
	    i = *size_boxes;
	    if (i < 0)
		i = -i;

	    if (traps.num_traps > i) {
		cairo_box_t *new_boxes;
		int new_size;

		new_size = pot (traps.num_traps);
		new_boxes = _cairo_malloc_ab (new_size, sizeof (cairo_box_t));
		if (unlikely (new_boxes == NULL)) {
		    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		    goto CLEANUP;
		}

		if (*size_boxes > 0)
		    free (*boxes);

		*boxes = new_boxes;
		*size_boxes = new_size;
	    }

	    for (i = 0; i < traps.num_traps; i++) {
		(*boxes)[i].p1.x = traps.traps[i].left.p1.x;
		(*boxes)[i].p1.y = traps.traps[i].top;
		(*boxes)[i].p2.x = traps.traps[i].right.p1.x;
		(*boxes)[i].p2.y = traps.traps[i].bottom;
	    }
	    *num_boxes = i;
	}
    }

  CLEANUP:
    _cairo_polygon_fini (&polygon);
    _cairo_traps_fini (&traps);

    return status;
}
示例#8
0
static cairo_int_status_t
_cairo_spans_compositor_fill (const cairo_compositor_t		*_compositor,
			      cairo_composite_rectangles_t	 *extents,
			      const cairo_path_fixed_t		*path,
			      cairo_fill_rule_t			 fill_rule,
			      double				 tolerance,
			      cairo_antialias_t			 antialias)
{
    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
    cairo_int_status_t status;

    status = CAIRO_INT_STATUS_UNSUPPORTED;
    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
	cairo_boxes_t boxes;

	_cairo_boxes_init (&boxes);
	if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
	    _cairo_boxes_limit (&boxes,
				extents->clip->boxes,
				extents->clip->num_boxes);
	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
							      fill_rule,
							      antialias,
							      &boxes);
	if (likely (status == CAIRO_INT_STATUS_SUCCESS))
	    status = clip_and_composite_boxes (compositor, extents, &boxes);
	_cairo_boxes_fini (&boxes);
    }
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
	cairo_polygon_t polygon;

	if (extents->mask.width  > extents->unbounded.width ||
	    extents->mask.height > extents->unbounded.height)
	{
	    cairo_box_t limits;
	    _cairo_box_from_rectangle (&limits, &extents->unbounded);
	    _cairo_polygon_init (&polygon, &limits, 1);
	}
	else
	{
	    _cairo_polygon_init (&polygon, NULL, 0);
	}

	status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
	    status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
							  extents->clip->boxes,
							  extents->clip->num_boxes);
	}
	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
	    if (extents->is_bounded) {
		if (extents->clip->boxes != &extents->clip->embedded_box)
		    free (extents->clip->boxes);

		extents->clip->num_boxes = 1;
		extents->clip->boxes = &extents->clip->embedded_box;
		extents->clip->boxes[0] = polygon.extents;
	    }
	    status = clip_and_composite_polygon (compositor, extents, &polygon,
						 fill_rule, antialias);
	}
	_cairo_polygon_fini (&polygon);
    }

    return status;
}