static void
edge_end_box (sweep_line_t *sweep_line, edge_t *left, int32_t bot)
{
    cairo_status_t status = CAIRO_STATUS_SUCCESS;

    /* Only emit (trivial) non-degenerate trapezoids with positive height. */
    if (likely (left->top < bot)) {
	if (sweep_line->do_traps) {
	    cairo_line_t _left = {
		{ left->x, left->top },
		{ left->x, bot },
	    }, _right = {
		{ left->right->x, left->top },
		{ left->right->x, bot },
	    };
	    _cairo_traps_add_trap (sweep_line->container, left->top, bot, &_left, &_right);
	    status = _cairo_traps_status ((cairo_traps_t *) sweep_line->container);
	} else {
	    cairo_box_t box;

	    box.p1.x = left->x;
	    box.p1.y = left->top;
	    box.p2.x = left->right->x;
	    box.p2.y = bot;

	    status = _cairo_boxes_add (sweep_line->container,
				       CAIRO_ANTIALIAS_DEFAULT,
				       &box);
	}
    }
    if (unlikely (status))
	longjmp (sweep_line->unwind, status);

    left->right = NULL;
}
static cairo_status_t
_cairo_bo_edge_end_trap (cairo_bo_edge_t	*left,
			 int32_t		 bot,
			 cairo_bool_t		 do_traps,
			 void			*container)
{
    cairo_bo_trap_t *trap = &left->deferred_trap;
    cairo_status_t status = CAIRO_STATUS_SUCCESS;

    /* Only emit (trivial) non-degenerate trapezoids with positive height. */
    if (likely (trap->top < bot)) {
	if (do_traps) {
	    _cairo_traps_add_trap (container,
				   trap->top, bot,
				   &left->edge.line, &trap->right->edge.line);
	    status =  _cairo_traps_status ((cairo_traps_t *) container);
	} else {
	    cairo_box_t box;

	    box.p1.x = left->edge.line.p1.x;
	    box.p1.y = trap->top;
	    box.p2.x = trap->right->edge.line.p1.x;
	    box.p2.y = bot;
	    status = _cairo_boxes_add (container, CAIRO_ANTIALIAS_DEFAULT, &box);
	}
    }

    trap->right = NULL;

    return status;
}
Exemplo n.º 3
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);
}
Exemplo n.º 4
0
cairo_int_status_t
_cairo_composite_rectangles_add_to_damage (cairo_composite_rectangles_t *composite,
					   cairo_boxes_t *damage)
{
    cairo_int_status_t status;
    int n;

    for (n = 0; n < composite->clip->num_boxes; n++) {
	status = _cairo_boxes_add (damage,
			  CAIRO_ANTIALIAS_NONE,
			  &composite->clip->boxes[n]);
	if (unlikely (status))
	    return status;
    }

    return CAIRO_INT_STATUS_SUCCESS;
}
static void
end_box (sweep_line_t *sweep_line, edge_t *left, int32_t bot, cairo_boxes_t *out)
{
    if (likely (left->top < bot)) {
	cairo_status_t status;
	cairo_box_t box;

	box.p1.x = left->x;
	box.p1.y = left->top;
	box.p2.x = left->right->x;
	box.p2.y = bot;

	status = _cairo_boxes_add (out, CAIRO_ANTIALIAS_DEFAULT, &box);
	if (unlikely (status))
	    longjmp (sweep_line->unwind, status);
    }

    left->right = NULL;
}
Exemplo n.º 6
0
static cairo_status_t
span_to_boxes (void *abstract_renderer, int y, int h,
	       const cairo_half_open_span_t *spans, unsigned num_spans)
{
    struct cairo_box_renderer *r = abstract_renderer;
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
    cairo_box_t box;

    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;

    box.p1.y = _cairo_fixed_from_int (y);
    box.p2.y = _cairo_fixed_from_int (y + h);
    do {
	if (spans[0].coverage) {
	    box.p1.x = _cairo_fixed_from_int(spans[0].x);
	    box.p2.x = _cairo_fixed_from_int(spans[1].x);
	    status = _cairo_boxes_add (r->boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
	}
	spans++;
    } while (--num_spans > 1 && status == CAIRO_STATUS_SUCCESS);

    return status;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
					 cairo_fill_rule_t fill_rule,
					 cairo_boxes_t *out)
{
    rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)];
    rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 3];
    rectangle_t *rectangles, **rectangles_ptrs;
    rectangle_t *stack_rectangles_chain[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *) ];
    rectangle_t **rectangles_chain = NULL;
    const struct _cairo_boxes_chunk *chunk;
    cairo_status_t status;
    int i, j, y_min, y_max;

    if (unlikely (in->num_boxes == 0)) {
	_cairo_boxes_clear (out);
	return CAIRO_STATUS_SUCCESS;
    }

    if (in->num_boxes == 1) {
	if (in == out) {
	    cairo_box_t *box = &in->chunks.base[0];

	    if (box->p1.x > box->p2.x) {
		cairo_fixed_t tmp = box->p1.x;
		box->p1.x = box->p2.x;
		box->p2.x = tmp;
	    }
	} else {
	    cairo_box_t box = in->chunks.base[0];

	    if (box.p1.x > box.p2.x) {
		cairo_fixed_t tmp = box.p1.x;
		box.p1.x = box.p2.x;
		box.p2.x = tmp;
	    }

	    _cairo_boxes_clear (out);
	    status = _cairo_boxes_add (out, CAIRO_ANTIALIAS_DEFAULT, &box);
	    assert (status == CAIRO_STATUS_SUCCESS);
	}
	return CAIRO_STATUS_SUCCESS;
    }

    y_min = INT_MAX; y_max = INT_MIN;
    for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) {
	const cairo_box_t *box = chunk->base;
	for (i = 0; i < chunk->count; i++) {
	    if (box[i].p1.y < y_min)
		y_min = box[i].p1.y;
	    if (box[i].p1.y > y_max)
		y_max = box[i].p1.y;
	}
    }
    y_min = _cairo_fixed_integer_floor (y_min);
    y_max = _cairo_fixed_integer_floor (y_max) + 1;
    y_max -= y_min;

    if (y_max < in->num_boxes) {
	rectangles_chain = stack_rectangles_chain;
	if (y_max > ARRAY_LENGTH (stack_rectangles_chain)) {
	    rectangles_chain = _cairo_malloc_ab (y_max, sizeof (rectangle_t *));
	    if (unlikely (rectangles_chain == NULL))
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	}
	memset (rectangles_chain, 0, y_max * sizeof (rectangle_t*));
    }

    rectangles = stack_rectangles;
    rectangles_ptrs = stack_rectangles_ptrs;
    if (in->num_boxes > ARRAY_LENGTH (stack_rectangles)) {
	rectangles = _cairo_malloc_ab_plus_c (in->num_boxes,
					      sizeof (rectangle_t) +
					      sizeof (rectangle_t *),
					      3*sizeof (rectangle_t *));
	if (unlikely (rectangles == NULL)) {
	    if (rectangles_chain != stack_rectangles_chain)
		free (rectangles_chain);
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	}

	rectangles_ptrs = (rectangle_t **) (rectangles + in->num_boxes);
    }

    j = 0;
    for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) {
	const cairo_box_t *box = chunk->base;
	for (i = 0; i < chunk->count; i++) {
	    int h;

	    if (box[i].p1.x < box[i].p2.x) {
		rectangles[j].left.x = box[i].p1.x;
		rectangles[j].left.dir = 1;

		rectangles[j].right.x = box[i].p2.x;
		rectangles[j].right.dir = -1;
	    } else {
		rectangles[j].right.x = box[i].p1.x;
		rectangles[j].right.dir = 1;

		rectangles[j].left.x = box[i].p2.x;
		rectangles[j].left.dir = -1;
	    }

	    rectangles[j].left.right = NULL;
	    rectangles[j].right.right = NULL;

	    rectangles[j].top = box[i].p1.y;
	    rectangles[j].bottom = box[i].p2.y;

	    if (rectangles_chain) {
		h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min;
		rectangles[j].left.next = (edge_t *)rectangles_chain[h];
		rectangles_chain[h] = &rectangles[j];
	    } else {
		rectangles_ptrs[j+2] = &rectangles[j];
	    }
	    j++;
	}
    }

    if (rectangles_chain) {
	j = 2;
	for (y_min = 0; y_min < y_max; y_min++) {
	    rectangle_t *r;
	    int start = j;
	    for (r = rectangles_chain[y_min]; r; r = (rectangle_t *)r->left.next)
		rectangles_ptrs[j++] = r;
	    if (j > start + 1)
		_rectangle_sort (rectangles_ptrs + start, j - start);
	}

	if (rectangles_chain != stack_rectangles_chain)
	    free (rectangles_chain);

	j -= 2;
    } else {
	_rectangle_sort (rectangles_ptrs + 2, j);
    }

    _cairo_boxes_clear (out);
    status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, j,
							    fill_rule,
							    FALSE, out);
    if (rectangles != stack_rectangles)
	free (rectangles);

    return status;
}
Exemplo n.º 8
0
cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t	*path,
					       const cairo_stroke_style_t	*stroke_style,
					       const cairo_matrix_t	*ctm,
					       cairo_antialias_t	 antialias,
					       cairo_boxes_t		*boxes)
{
    cairo_rectilinear_stroker_t rectilinear_stroker;
    cairo_int_status_t status;
    cairo_box_t box;

    assert (_cairo_path_fixed_stroke_is_rectilinear (path));

    if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker,
					   stroke_style, ctm, antialias,
					   boxes))
    {
	return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    if (! rectilinear_stroker.dash.dashed &&
	_cairo_path_fixed_is_stroke_box (path, &box) &&
	/* if the segments overlap we need to feed them into the tessellator */
	box.p2.x - box.p1.x > 2* rectilinear_stroker.half_line_x &&
	box.p2.y - box.p1.y > 2* rectilinear_stroker.half_line_y)
    {
	cairo_box_t b;

	/* top */
	b.p1.x = box.p1.x - rectilinear_stroker.half_line_x;
	b.p2.x = box.p2.x + rectilinear_stroker.half_line_x;
	b.p1.y = box.p1.y - rectilinear_stroker.half_line_y;
	b.p2.y = box.p1.y + rectilinear_stroker.half_line_y;
	status = (cairo_int_status_t)_cairo_boxes_add (boxes, antialias, &b);
	assert (status == CAIRO_INT_STATUS_SUCCESS);

	/* left  (excluding top/bottom) */
	b.p1.x = box.p1.x - rectilinear_stroker.half_line_x;
	b.p2.x = box.p1.x + rectilinear_stroker.half_line_x;
	b.p1.y = box.p1.y + rectilinear_stroker.half_line_y;
	b.p2.y = box.p2.y - rectilinear_stroker.half_line_y;
	status = (cairo_int_status_t)_cairo_boxes_add (boxes, antialias, &b);
	assert (status == CAIRO_INT_STATUS_SUCCESS);

	/* right  (excluding top/bottom) */
	b.p1.x = box.p2.x - rectilinear_stroker.half_line_x;
	b.p2.x = box.p2.x + rectilinear_stroker.half_line_x;
	b.p1.y = box.p1.y + rectilinear_stroker.half_line_y;
	b.p2.y = box.p2.y - rectilinear_stroker.half_line_y;
	status = (cairo_int_status_t)_cairo_boxes_add (boxes, antialias, &b);
	assert (status == CAIRO_INT_STATUS_SUCCESS);

	/* bottom */
	b.p1.x = box.p1.x - rectilinear_stroker.half_line_x;
	b.p2.x = box.p2.x + rectilinear_stroker.half_line_x;
	b.p1.y = box.p2.y - rectilinear_stroker.half_line_y;
	b.p2.y = box.p2.y + rectilinear_stroker.half_line_y;
	status = (cairo_int_status_t)_cairo_boxes_add (boxes, antialias, &b);
	assert (status == CAIRO_INT_STATUS_SUCCESS);

	goto done;
    }

    if (boxes->num_limits) {
	_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
					  boxes->limits,
					  boxes->num_limits);
    }

    status = (cairo_int_status_t)_cairo_path_fixed_interpret (path,
					  _cairo_rectilinear_stroker_move_to,
					  rectilinear_stroker.dash.dashed ?
					  _cairo_rectilinear_stroker_line_to_dashed :
					  _cairo_rectilinear_stroker_line_to,
					  NULL,
					  _cairo_rectilinear_stroker_close_path,
					  &rectilinear_stroker);
    if (unlikely (status))
	goto BAIL;

    if (rectilinear_stroker.dash.dashed)
	status = (cairo_int_status_t)_cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker);
    else
	status = (cairo_int_status_t)_cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);
    if (unlikely (status))
	goto BAIL;

    /* As we incrementally tessellate, we do not eliminate self-intersections */
    status = (cairo_int_status_t)_cairo_bentley_ottmann_tessellate_boxes (boxes,
						      CAIRO_FILL_RULE_WINDING,
						      boxes);
    if (unlikely (status))
	goto BAIL;

done:
    _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
    return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;

BAIL:
    _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
    _cairo_boxes_clear (boxes);
    return status;
}
Exemplo n.º 9
0
static cairo_status_t
_cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *stroker)
{
    cairo_status_t status;
    cairo_line_cap_t line_cap = stroker->stroke_style->line_cap;
    cairo_fixed_t half_line_x = stroker->half_line_x;
    cairo_fixed_t half_line_y = stroker->half_line_y;
    int i;

    for (i = 0; i < stroker->num_segments; i++) {
	cairo_point_t *a, *b;
	cairo_bool_t is_horizontal;
	cairo_box_t box;

	a = &stroker->segments[i].p1;
	b = &stroker->segments[i].p2;

	is_horizontal = stroker->segments[i].flags & HORIZONTAL;

	/* Handle the joins for a potentially degenerate segment. */
	if (line_cap == CAIRO_LINE_CAP_BUTT &&
	    stroker->segments[i].flags & JOIN &&
	    (i != stroker->num_segments - 1 ||
	     (! stroker->open_sub_path && stroker->dash.dash_starts_on)))
	{
	    cairo_slope_t out_slope;
	    int j = (i + 1) % stroker->num_segments;
	    cairo_bool_t forwards = !!(stroker->segments[i].flags & FORWARDS);

	    _cairo_slope_init (&out_slope,
			       &stroker->segments[j].p1,
			       &stroker->segments[j].p2);
	    box.p2 = box.p1 = stroker->segments[i].p2;

	    if (is_horizontal) {
		if (forwards)
		    box.p2.x += half_line_x;
		else
		    box.p1.x -= half_line_x;

		if (out_slope.dy > 0)
		    box.p1.y -= half_line_y;
		else
		    box.p2.y += half_line_y;
	    } else {
		if (forwards)
		    box.p2.y += half_line_y;
		else
		    box.p1.y -= half_line_y;

		if (out_slope.dx > 0)
		    box.p1.x -= half_line_x;
		else
		    box.p2.x += half_line_x;
	    }

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

	/* Perform the adjustments of the endpoints. */
	if (is_horizontal) {
	    if (line_cap == CAIRO_LINE_CAP_SQUARE) {
		if (a->x <= b->x) {
		    a->x -= half_line_x;
		    b->x += half_line_x;
		} else {
		    a->x += half_line_x;
		    b->x -= half_line_x;
		}
	    }

	    a->y += half_line_y;
	    b->y -= half_line_y;
	} else {
	    if (line_cap == CAIRO_LINE_CAP_SQUARE) {
		if (a->y <= b->y) {
		    a->y -= half_line_y;
		    b->y += half_line_y;
		} else {
		    a->y += half_line_y;
		    b->y -= half_line_y;
		}
	    }

	    a->x += half_line_x;
	    b->x -= half_line_x;
	}

	if (a->x == b->x && a->y == b->y)
	    continue;

	if (a->x < b->x) {
	    box.p1.x = a->x;
	    box.p2.x = b->x;
	} else {
	    box.p1.x = b->x;
	    box.p2.x = a->x;
	}
	if (a->y < b->y) {
	    box.p1.y = a->y;
	    box.p2.y = b->y;
	} else {
	    box.p1.y = b->y;
	    box.p2.y = a->y;
	}

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

    stroker->num_segments = 0;

    return CAIRO_STATUS_SUCCESS;
}
Exemplo n.º 10
0
static cairo_status_t
_cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
{
    cairo_line_cap_t line_cap = stroker->stroke_style->line_cap;
    cairo_fixed_t half_line_x = stroker->half_line_x;
    cairo_fixed_t half_line_y = stroker->half_line_y;
    cairo_status_t status;
    int i, j;

    /* For each segment we generate a single rectangle.
     * This rectangle is based on a perpendicular extension (by half the
     * line width) of the segment endpoints * after some adjustments of the
     * endpoints to account for caps and joins.
     */
    for (i = 0; i < stroker->num_segments; i++) {
	cairo_bool_t lengthen_initial, lengthen_final;
	cairo_point_t *a, *b;
	cairo_box_t box;

	a = &stroker->segments[i].p1;
	b = &stroker->segments[i].p2;

	/* We adjust the initial point of the segment to extend the
	 * rectangle to include the previous cap or join, (this
	 * adjustment applies to all segments except for the first
	 * segment of open, butt-capped paths). However, we must be
	 * careful not to emit a miter join across a degenerate segment
	 * which has been elided.
	 *
	 * Overlapping segments will be eliminated by the tessellation.
	 * Ideally, we would not emit these self-intersections at all,
	 * but that is tricky with segments shorter than half_line_width.
	 */
	j = i == 0 ? stroker->num_segments - 1 : i-1;
	lengthen_initial = (stroker->segments[i].flags ^ stroker->segments[j].flags) & HORIZONTAL;
	j = i == stroker->num_segments - 1 ? 0 : i+1;
	lengthen_final = (stroker->segments[i].flags ^ stroker->segments[j].flags) & HORIZONTAL;
	if (stroker->open_sub_path) {
	    if (i == 0)
		lengthen_initial = line_cap != CAIRO_LINE_CAP_BUTT;

	    if (i == stroker->num_segments - 1)
		lengthen_final = line_cap != CAIRO_LINE_CAP_BUTT;
	}

	/* Perform the adjustments of the endpoints. */
	if (lengthen_initial | lengthen_final) {
	    if (a->y == b->y) {
		if (a->x < b->x) {
		    if (lengthen_initial)
			a->x -= half_line_x;
		    if (lengthen_final)
			b->x += half_line_x;
		} else {
		    if (lengthen_initial)
			a->x += half_line_x;
		    if (lengthen_final)
			b->x -= half_line_x;
		}
	    } else {
		if (a->y < b->y) {
		    if (lengthen_initial)
			a->y -= half_line_y;
		    if (lengthen_final)
			b->y += half_line_y;
		} else {
		    if (lengthen_initial)
			a->y += half_line_y;
		    if (lengthen_final)
			b->y -= half_line_y;
		}
	    }
	}

	/* Form the rectangle by expanding by half the line width in
	 * either perpendicular direction. */
	if (a->y == b->y) {
	    a->y -= half_line_y;
	    b->y += half_line_y;
	} else {
	    a->x -= half_line_x;
	    b->x += half_line_x;
	}

	if (a->x < b->x) {
	    box.p1.x = a->x;
	    box.p2.x = b->x;
	} else {
	    box.p1.x = b->x;
	    box.p2.x = a->x;
	}
	if (a->y < b->y) {
	    box.p1.y = a->y;
	    box.p2.y = b->y;
	} else {
	    box.p1.y = b->y;
	    box.p2.y = a->y;
	}

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

    stroker->num_segments = 0;
    return CAIRO_STATUS_SUCCESS;
}
Exemplo n.º 11
0
static cairo_int_status_t
fixup_unbounded_boxes (const cairo_spans_compositor_t *compositor,
		       const cairo_composite_rectangles_t *extents,
		       cairo_boxes_t *boxes)
{
    cairo_boxes_t tmp, clear;
    cairo_box_t box;
    cairo_int_status_t status;

    assert (boxes->is_pixel_aligned);

    TRACE ((stderr, "%s\n", __FUNCTION__));
    if (extents->bounded.width  == extents->unbounded.width &&
	extents->bounded.height == extents->unbounded.height)
    {
	return CAIRO_STATUS_SUCCESS;
    }

    /* subtract the drawn boxes from the unbounded area */
    _cairo_boxes_init (&clear);

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

    if (boxes->num_boxes) {
	_cairo_boxes_init (&tmp);

	status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
	assert (status == CAIRO_INT_STATUS_SUCCESS);

	tmp.chunks.next = &boxes->chunks;
	tmp.num_boxes += boxes->num_boxes;

	status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
							  CAIRO_FILL_RULE_WINDING,
							  &clear);
	tmp.chunks.next = NULL;
	if (unlikely (status))
	    goto error;
    } else {
	box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
	box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);

	status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
	assert (status == CAIRO_INT_STATUS_SUCCESS);
    }

    /* If we have a clip polygon, we need to intersect with that as well */
    if (extents->clip->path) {
	status = fixup_unbounded_polygon (compositor, extents, &clear);
	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
	    status = fixup_unbounded_mask (compositor, extents, &clear);
    } else {
	/* Otherwise just intersect with the clip boxes */
	if (extents->clip->num_boxes) {
	    _cairo_boxes_init_for_array (&tmp,
					 extents->clip->boxes,
					 extents->clip->num_boxes);
	    status = _cairo_boxes_intersect (&clear, &tmp, &clear);
	    if (unlikely (status))
		goto error;
	}

	if (clear.is_pixel_aligned) {
	    status = compositor->fill_boxes (extents->surface,
					     CAIRO_OPERATOR_CLEAR,
					     CAIRO_COLOR_TRANSPARENT,
					     &clear);
	} else {
	    cairo_composite_rectangles_t composite;

	    status = _cairo_composite_rectangles_init_for_boxes (&composite,
								 extents->surface,
								 CAIRO_OPERATOR_CLEAR,
								 &_cairo_pattern_clear.base,
								 &clear,
								 NULL);
	    if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
		status = composite_boxes (compositor, &composite, &clear);
		_cairo_composite_rectangles_fini (&composite);
	    }
	}
    }

error:
    _cairo_boxes_fini (&clear);
    return status;
}