Esempio n. 1
0
void
_cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path)
{
    cairo_status_t status;
    cairo_box_t box;

    fprintf (stream,
	     "path: extents=(%f, %f), (%f, %f)\n",
	    _cairo_fixed_to_double (path->extents.p1.x),
	    _cairo_fixed_to_double (path->extents.p1.y),
	    _cairo_fixed_to_double (path->extents.p2.x),
	    _cairo_fixed_to_double (path->extents.p2.y));

    status = _cairo_path_fixed_interpret (path,
					  _print_move_to,
					  _print_line_to,
					  _print_curve_to,
					  _print_close,
					  stream);
    assert (status == CAIRO_STATUS_SUCCESS);

    if (_cairo_path_fixed_is_box (path, &box)) {
	fprintf (stream, "[box (%d, %d), (%d, %d)]",
		 box.p1.x, box.p1.y, box.p2.x, box.p2.y);
    }

    fprintf (stream, "\n");
}
Esempio n. 2
0
/* This special-case filler supports only a path that describes a
 * device-axis aligned rectangle. It exists to avoid the overhead of
 * the general tessellator when drawing very common rectangles.
 *
 * If the path described anything but a device-axis aligned rectangle,
 * this function will return %CAIRO_INT_STATUS_UNSUPPORTED.
 */
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t	*path,
				  cairo_traps_t		*traps)
{
    if (_cairo_path_fixed_is_box (path, NULL)) {
	cairo_point_t *p = path->buf_head.base.points;
	cairo_point_t *top_left, *bot_right;

	top_left = &p[0];
	bot_right = &p[2];
	if (top_left->x > bot_right->x || top_left->y > bot_right->y) {
	    int n;

	    /* not a simple cairo_rectangle() */
	    for (n = 0; n < 4; n++) {
		if (p[n].x <= top_left->x && p[n].y <= top_left->y)
		    top_left = &p[n];
		if (p[n].x >= bot_right->x && p[n].y >= bot_right->y)
		    bot_right = &p[n];
	    }
	}

	return _cairo_traps_tessellate_rectangle (traps, top_left, bot_right);
    }

    return CAIRO_INT_STATUS_UNSUPPORTED;
}
/*
 * Check whether the given path contains a single rectangle
 * that is logically equivalent to:
 * <informalexample><programlisting>
 *   cairo_move_to (cr, x, y);
 *   cairo_rel_line_to (cr, width, 0);
 *   cairo_rel_line_to (cr, 0, height);
 *   cairo_rel_line_to (cr, -width, 0);
 *   cairo_close_path (cr);
 * </programlisting></informalexample>
 */
cairo_bool_t
_cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
				cairo_box_t        *box)
{
    cairo_path_buf_t *buf = &path->buf_head.base;

    if (!_cairo_path_fixed_is_box (path, box))
	return FALSE;

    if (buf->points[0].y == buf->points[1].y)
	return TRUE;

    return FALSE;
}
cairo_int_status_t
_cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
					     cairo_fill_rule_t fill_rule,
					     cairo_traps_t *traps)
{
    cairo_box_t box;
    cairo_status_t status;

    traps->is_rectilinear = TRUE;
    traps->is_rectangular = TRUE;

    if (_cairo_path_fixed_is_box (path, &box)) {
	return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
    } else {
	cairo_path_fixed_iter_t iter;

	_cairo_path_fixed_iter_init (&iter, path);
	while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
	    if (box.p1.y > box.p2.y) {
		cairo_fixed_t t;

		t = box.p1.y;
		box.p1.y = box.p2.y;
		box.p2.y = t;

		t = box.p1.x;
		box.p1.x = box.p2.x;
		box.p2.x = t;
	    }

	    status = _cairo_traps_tessellate_rectangle (traps,
							&box.p1, &box.p2);
	    if (unlikely (status)) {
		_cairo_traps_clear (traps);
		return status;
	    }
	}

	if (_cairo_path_fixed_iter_at_end (&iter))
	    return _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, fill_rule);

	_cairo_traps_clear (traps);
	return CAIRO_INT_STATUS_UNSUPPORTED;
    }
}
Esempio n. 5
0
cairo_status_t
_cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path,
					     cairo_fill_rule_t fill_rule,
					     cairo_antialias_t antialias,
					     cairo_boxes_t *boxes)
{
    cairo_path_fixed_iter_t iter;
    cairo_status_t status;
    cairo_box_t box;

    if (_cairo_path_fixed_is_box (path, &box))
	return _cairo_boxes_add (boxes, antialias, &box);

    _cairo_path_fixed_iter_init (&iter, path);
    while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
	if (box.p1.y == box.p2.y || box.p1.x == box.p2.x)
	    continue;

	if (box.p1.y > box.p2.y) {
	    cairo_fixed_t t;

	    t = box.p1.y;
	    box.p1.y = box.p2.y;
	    box.p2.y = t;

	    t = box.p1.x;
	    box.p1.x = box.p2.x;
	    box.p2.x = t;
	}

	status = _cairo_boxes_add (boxes, antialias, &box);
	if (unlikely (status))
	    return status;
    }

    if (_cairo_path_fixed_iter_at_end (&iter))
	return _cairo_bentley_ottmann_tessellate_boxes (boxes, fill_rule, boxes);

    /* path is not rectangular, try extracting clipped rectilinear edges */
    _cairo_boxes_clear (boxes);
    return _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (path,
								   fill_rule,
								   antialias,
								   boxes);
}
Esempio n. 6
0
static cairo_status_t
_cairo_xml_surface_emit_clip_path (cairo_xml_surface_t *surface,
				   const cairo_clip_path_t *clip_path)
{
    cairo_box_t box;
    cairo_status_t status;
    cairo_xml_t *xml;

    if (clip_path == NULL)
	return CAIRO_STATUS_SUCCESS;

    status = _cairo_xml_surface_emit_clip_path (surface, clip_path->prev);
    if (unlikely (status))
	return status;

    /* skip the trivial clip covering the surface extents */
    if (surface->width >= 0 && surface->height >= 0 &&
	_cairo_path_fixed_is_box (&clip_path->path, &box))
    {
	if (box.p1.x <= 0 && box.p1.y <= 0 &&
	    box.p2.x - box.p1.x >= _cairo_fixed_from_double (surface->width) &&
	    box.p2.y - box.p1.y >= _cairo_fixed_from_double (surface->height))
	{
	    return CAIRO_STATUS_SUCCESS;
	}
    }

    xml = to_xml (surface);

    _cairo_xml_printf_start (xml, "<clip>");
    _cairo_xml_indent (xml, 2);

    _cairo_xml_emit_path (xml, &clip_path->path);
    _cairo_xml_emit_double (xml, "tolerance", clip_path->tolerance);
    _cairo_xml_emit_string (xml, "antialias",
			    _antialias_to_string (clip_path->antialias));
    _cairo_xml_emit_string (xml, "fill-rule",
			    _fill_rule_to_string (clip_path->fill_rule));

    _cairo_xml_indent (xml, -2);
    _cairo_xml_printf_end (xml, "</clip>");

    return CAIRO_STATUS_SUCCESS;
}
/* This special-case filler supports only a path that describes a
 * device-axis aligned rectangle. It exists to avoid the overhead of
 * the general tessellator when drawing very common rectangles.
 *
 * If the path described anything but a device-axis aligned rectangle,
 * this function will abort.
 */
cairo_region_t *
_cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t	*path,
					      cairo_fill_rule_t	 fill_rule,
					      const cairo_rectangle_int_t *extents)
{
    cairo_rectangle_int_t rectangle_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
    cairo_box_t box;
    cairo_region_t *region = NULL;

    assert (path->maybe_fill_region);
    assert (! path->is_empty_fill);

    if (_cairo_path_fixed_is_box (path, &box)) {
	rectangle_stack[0].x = _cairo_fixed_integer_part (box.p1.x);
	rectangle_stack[0].y = _cairo_fixed_integer_part (box.p1.y);
	rectangle_stack[0].width = _cairo_fixed_integer_part (box.p2.x) -
	                            rectangle_stack[0].x;
	rectangle_stack[0].height = _cairo_fixed_integer_part (box.p2.y) -
	                            rectangle_stack[0].y;
	if (! _cairo_rectangle_intersect (&rectangle_stack[0], extents))
	    region = cairo_region_create ();
	else
	    region = cairo_region_create_rectangle (&rectangle_stack[0]);
    } else if (fill_rule == CAIRO_FILL_RULE_WINDING) {
	cairo_rectangle_int_t *rects = rectangle_stack;
	cairo_path_fixed_iter_t iter;
	int last_cw = -1;
	int size = ARRAY_LENGTH (rectangle_stack);
	int count = 0;

	/* Support a series of rectangles as can be expected to describe a
	 * GdkRegion clip region during exposes.
	 */
	_cairo_path_fixed_iter_init (&iter, path);
	while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
	    int cw = 0;

	    if (box.p1.x > box.p2.x) {
		cairo_fixed_t t;

		t = box.p1.x;
		box.p1.x = box.p2.x;
		box.p2.x = t;

		cw = ! cw;
	    }

	    if (box.p1.y > box.p2.y) {
		cairo_fixed_t t;

		t = box.p1.y;
		box.p1.y = box.p2.y;
		box.p2.y = t;

		cw = ! cw;
	    }

	    if (last_cw < 0)
		last_cw = cw;
	    else if (last_cw != cw)
		goto TESSELLATE;

	    if (count == size) {
		cairo_rectangle_int_t *new_rects;

		size *= 4;
		if (rects == rectangle_stack) {
		    new_rects = _cairo_malloc_ab (size,
						  sizeof (cairo_rectangle_int_t));
		    if (unlikely (new_rects == NULL)) {
			/* XXX _cairo_region_nil */
			break;
		    }
		    memcpy (new_rects, rects, sizeof (rectangle_stack));
		} else {
		    new_rects = _cairo_realloc_ab (rects, size,
						   sizeof (cairo_rectangle_int_t));
		    if (unlikely (new_rects == NULL)) {
			/* XXX _cairo_region_nil */
			break;
		    }
		}
		rects = new_rects;
	    }

	    rects[count].x = _cairo_fixed_integer_part (box.p1.x);
	    rects[count].y = _cairo_fixed_integer_part (box.p1.y);
	    rects[count].width = _cairo_fixed_integer_part (box.p2.x) - rects[count].x;
	    rects[count].height = _cairo_fixed_integer_part (box.p2.y) - rects[count].y;
	    if (_cairo_rectangle_intersect (&rects[count], extents))
		count++;
	}

	if (_cairo_path_fixed_iter_at_end (&iter))
	    region = cairo_region_create_rectangles (rects, count);

TESSELLATE:
	if (rects != rectangle_stack)
	    free (rects);
    }

    if (region == NULL) {
	/* Hmm, complex polygon */
	region = _cairo_path_fixed_fill_rectilinear_tessellate_to_region (path,
									  fill_rule,
									  extents);


    }

    return region;
}
Esempio n. 8
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;
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
static cairo_int_status_t
_cairo_clip_path_to_boxes (cairo_clip_path_t *clip_path,
			   cairo_box_t **boxes,
			   int *count)
{
    int size = -*count;
    int num_boxes = 0;
    cairo_status_t status;

    if (clip_path->region != NULL) {
	int num_rects, n;

	num_rects = cairo_region_num_rectangles (clip_path->region);
	if (num_rects > -size) {
	    cairo_box_t *new_boxes;

	    new_boxes = _cairo_malloc_ab (num_rects, sizeof (cairo_box_t));
	    if (unlikely (new_boxes == NULL))
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	    *boxes = new_boxes;
	}

	for (n = 0; n < num_rects; n++) {
	    cairo_rectangle_int_t rect;

	    cairo_region_get_rectangle (clip_path->region, n, &rect);
	    (*boxes)[n].p1.x = _cairo_fixed_from_int (rect.x);
	    (*boxes)[n].p1.y = _cairo_fixed_from_int (rect.y);
	    (*boxes)[n].p2.x = _cairo_fixed_from_int (rect.x + rect.width);
	    (*boxes)[n].p2.y = _cairo_fixed_from_int (rect.y + rect.height);
	}

	*count = num_rects;
	return CAIRO_STATUS_SUCCESS;
    }

    /* keep it simple at first */
    if (! _clip_paths_are_rectilinear (clip_path))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    assert (-size >= 1);
    if (_cairo_path_fixed_is_box (&clip_path->path, *boxes)) {
	num_boxes = 1;
    } else {
	status = _rectilinear_clip_to_boxes (&clip_path->path,
					     clip_path->fill_rule,
					     boxes, &num_boxes, &size);
	if (unlikely (status))
	    return status;
    }

    while (num_boxes > 0 && (clip_path = clip_path->prev) != NULL) {
	cairo_box_t box;

	if (clip_path->region != NULL) {
	    status = _region_clip_to_boxes (clip_path->region,
					    boxes, &num_boxes, &size);
	    if (unlikely (status))
		return status;

	    break;
	} else if (_cairo_path_fixed_is_box (&clip_path->path, &box)) {
	    int i, j;

	    for (i = j = 0; i < num_boxes; i++) {
		if (j != i)
		    (*boxes)[j] = (*boxes)[i];

		if (box.p1.x > (*boxes)[j].p1.x)
		    (*boxes)[j].p1.x = box.p1.x;
		if (box.p2.x < (*boxes)[j].p2.x)
		    (*boxes)[j].p2.x = box.p2.x;

		if (box.p1.y > (*boxes)[j].p1.y)
		    (*boxes)[j].p1.y = box.p1.y;
		if (box.p2.y < (*boxes)[j].p2.y)
		    (*boxes)[j].p2.y = box.p2.y;

		j += (*boxes)[j].p2.x > (*boxes)[j].p1.x &&
		     (*boxes)[j].p2.y > (*boxes)[j].p1.y;
	    }

	    num_boxes = j;
	} else {
	    status = _rectilinear_clip_to_boxes (&clip_path->path,
						 clip_path->fill_rule,
						 boxes, &num_boxes, &size);
	    if (unlikely (status))
		return status;
	}
    }

    *count = num_boxes;
    return CAIRO_STATUS_SUCCESS;
}
Esempio n. 11
0
static cairo_status_t
_cairo_clip_intersect_path (cairo_clip_t       *clip,
			    const cairo_path_fixed_t *path,
			    cairo_fill_rule_t   fill_rule,
			    double              tolerance,
			    cairo_antialias_t   antialias)
{
    cairo_clip_path_t *clip_path;
    cairo_status_t status;
    cairo_rectangle_int_t extents;
    cairo_box_t box;
    cairo_bool_t is_box = FALSE;

    if (clip->path != NULL) {
	if (clip->path->fill_rule == fill_rule &&
	    (path->is_rectilinear ||
	     (tolerance == clip->path->tolerance &&
	      antialias == clip->path->antialias)) &&
	    _cairo_path_fixed_equal (&clip->path->path, path))
	{
	    return CAIRO_STATUS_SUCCESS;
	}
    }

    _cairo_path_fixed_approximate_clip_extents (path, &extents);
    if (extents.width == 0 || extents.height == 0) {
	_cairo_clip_set_all_clipped (clip);
	return CAIRO_STATUS_SUCCESS;
    }

    is_box = _cairo_path_fixed_is_box (path, &box);
    if (clip->path != NULL) {
	if (! _cairo_rectangle_intersect (&extents, &clip->path->extents)) {
	    _cairo_clip_set_all_clipped (clip);
	    return CAIRO_STATUS_SUCCESS;
	}

	/* does this clip wholly subsume the others? */
	if (is_box &&
	    box.p1.x <= _cairo_fixed_from_int (clip->path->extents.x) &&
	    box.p2.x >= _cairo_fixed_from_int (clip->path->extents.x + clip->path->extents.width) &&
	    box.p1.y <= _cairo_fixed_from_int (clip->path->extents.y) &&
	    box.p2.y >= _cairo_fixed_from_int (clip->path->extents.y + clip->path->extents.height))
	{
	    return CAIRO_STATUS_SUCCESS;
	}
    }

    clip_path = _cairo_clip_path_create (clip);
    if (unlikely (clip_path == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    status = _cairo_path_fixed_init_copy (&clip_path->path, path);
    if (unlikely (status)) {
	clip->path = clip->path->prev;
	_cairo_clip_path_destroy (clip_path);
	return status;
    }

    clip_path->extents = extents;
    clip_path->fill_rule = fill_rule;
    clip_path->tolerance = tolerance;
    clip_path->antialias = antialias;
    if (is_box)
	clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX;

    return CAIRO_STATUS_SUCCESS;
}