cairo_status_t
_cairo_surface_fallback_fill (cairo_surface_t		*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_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_fill_to_traps (path,
					      fill_rule,
					      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;
}
示例#2
0
void
_cairo_polygon_translate (cairo_polygon_t *polygon, int dx, int dy)
{
    int n;

    dx = _cairo_fixed_from_int (dx);
    dy = _cairo_fixed_from_int (dy);

    polygon->extents.p1.x += dx;
    polygon->extents.p2.x += dx;
    polygon->extents.p1.y += dy;
    polygon->extents.p2.y += dy;

    for (n = 0; n < polygon->num_edges; n++) {
	cairo_edge_t *e = &polygon->edges[n];

	e->top += dy;
	e->bottom += dy;

	e->line.p1.x += dx;
	e->line.p2.x += dx;
	e->line.p1.y += dy;
	e->line.p2.y += dy;
    }
}
示例#3
0
static cairo_status_t
span_to_traps (void *abstract_renderer, int y, int h,
	       const cairo_half_open_span_t *spans, unsigned num_spans)
{
    struct cairo_trap_renderer *r = abstract_renderer;
    cairo_fixed_t top, bot;

    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;

    top = _cairo_fixed_from_int (y);
    bot = _cairo_fixed_from_int (y + h);
    do {
	if (spans[0].coverage) {
	    cairo_fixed_t x0 = _cairo_fixed_from_int(spans[0].x);
	    cairo_fixed_t x1 = _cairo_fixed_from_int(spans[1].x);
	    cairo_line_t left = { { x0, top }, { x0, bot } },
			 right = { { x1, top }, { x1, bot } };
	    _cairo_traps_add_trap (r->traps, top, bot, &left, &right);
	}
	spans++;
    } while (--num_spans > 1);

    return CAIRO_STATUS_SUCCESS;
}
示例#4
0
void
_cairo_traps_translate (cairo_traps_t *traps, int x, int y)
{
    cairo_fixed_t xoff, yoff;
    cairo_trapezoid_t *t;
    int i;

    /* Ugh. The cairo_composite/(Render) interface doesn't allow
       an offset for the trapezoids. Need to manually shift all
       the coordinates to align with the offset origin of the
       intermediate surface. */

    xoff = _cairo_fixed_from_int (x);
    yoff = _cairo_fixed_from_int (y);

    for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
	t->top += yoff;
	t->bottom += yoff;
	t->left.p1.x += xoff;
	t->left.p1.y += yoff;
	t->left.p2.x += xoff;
	t->left.p2.y += yoff;
	t->right.p1.x += xoff;
	t->right.p1.y += yoff;
	t->right.p2.x += xoff;
	t->right.p2.y += yoff;
    }
}
示例#5
0
void
_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents)
{
    if (traps->num_traps == 0) {
	extents->p1.x = extents->p1.y = _cairo_fixed_from_int (0);
	extents->p2.x = extents->p2.y = _cairo_fixed_from_int (0);
    } else
	*extents = traps->extents;
}
示例#6
0
void
_cairo_box_from_rectangle (cairo_box_t                 *box,
			   const cairo_rectangle_int_t *rect)
{
    box->p1.x = _cairo_fixed_from_int (rect->x);
    box->p1.y = _cairo_fixed_from_int (rect->y);
    box->p2.x = _cairo_fixed_from_int (rect->x + rect->width);
    box->p2.y = _cairo_fixed_from_int (rect->y + rect->height);
}
示例#7
0
cairo_status_t
_cairo_surface_offset_fill (cairo_surface_t	*surface,
			    int x, int y,
			    cairo_operator_t	 op,
			    const cairo_pattern_t*source,
			    const cairo_path_fixed_t	*path,
			    cairo_fill_rule_t	 fill_rule,
			    double		 tolerance,
			    cairo_antialias_t	 antialias,
			    const cairo_clip_t	*clip)
{
    cairo_status_t status;
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
    cairo_clip_t *dev_clip = (cairo_clip_t *) clip;
    cairo_pattern_union_t source_copy;

    if (unlikely (surface->status))
	return surface->status;

    if (_cairo_clip_is_all_clipped (clip))
	return CAIRO_STATUS_SUCCESS;

    if (x | y) {
	cairo_matrix_t m;

	dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y);

	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
	if (unlikely (status))
	    goto FINISH;

	_cairo_path_fixed_translate (&path_copy,
				     _cairo_fixed_from_int (-x),
				     _cairo_fixed_from_int (-y));
	dev_path = &path_copy;

	cairo_matrix_init_translate (&m, x, y);
	_copy_transformed_pattern (&source_copy.base, source, &m);
	source = &source_copy.base;
    }

    status = _cairo_surface_fill (surface, op, source,
				  dev_path, fill_rule,
				  tolerance, antialias,
				  dev_clip);

FINISH:
    if (dev_path != path)
	_cairo_path_fixed_fini (dev_path);
    if (dev_clip != clip)
	_cairo_clip_destroy (dev_clip);

    return status;
}
示例#8
0
cairo_bool_t
_cairo_clip_contains_rectangle (const cairo_clip_t *clip,
				const cairo_rectangle_int_t *rect)
{
    cairo_box_t box;

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

    return _cairo_clip_contains_rectangle_box (clip, rect, &box);
}
示例#9
0
static cairo_status_t
_cairo_clip_path_reapply_clip_path_translate (cairo_clip_t      *clip,
					      cairo_clip_path_t *other_path,
					      int tx, int ty)
{
    cairo_status_t status;
    cairo_clip_path_t *clip_path;

    if (other_path->prev != NULL) {
        status = _cairo_clip_path_reapply_clip_path_translate (clip,
							       other_path->prev,
							       tx, ty);
	if (unlikely (status))
	    return status;
    }

    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,
					  &other_path->path);
    if (unlikely (status)) {
	_cairo_clip_path_destroy (clip_path);
	return status;
    }

    _cairo_path_fixed_translate (&clip_path->path,
				 _cairo_fixed_from_int (tx),
				 _cairo_fixed_from_int (ty));

    clip_path->fill_rule = other_path->fill_rule;
    clip_path->tolerance = other_path->tolerance;
    clip_path->antialias = other_path->antialias;

    clip_path->flags = other_path->flags;
    if (other_path->region != NULL) {
	clip_path->region = cairo_region_copy (other_path->region);
	cairo_region_translate (clip_path->region, tx, ty);
    }
    clip_path->surface = cairo_surface_reference (other_path->surface);

    clip_path->extents = other_path->extents;
    clip_path->extents.x += tx;
    clip_path->extents.y += ty;

    return CAIRO_STATUS_SUCCESS;
}
示例#10
0
cairo_status_t
_cairo_surface_fallback_paint (cairo_surface_t	*surface,
			       cairo_operator_t	 op,
			       cairo_pattern_t	*source)
{
    cairo_status_t status;
    cairo_rectangle_int_t extents;
    cairo_box_t box;
    cairo_traps_t traps;

    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);

    status = _cairo_traps_init_box (&traps, &box);
    if (status)
	return status;

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

    _cairo_traps_fini (&traps);

    return status;
}
示例#11
0
static cairo_clip_t *
_cairo_clip_reduce_to_boxes (cairo_clip_t *clip)
{
    struct reduce r;
    cairo_clip_path_t *clip_path;
    cairo_status_t status;

	return clip;
    if (clip->path == NULL)
	return clip;

    r.clip = clip;
    r.extents.p1.x = r.extents.p1.y = INT_MAX;
    r.extents.p2.x = r.extents.p2.y = INT_MIN;
    r.inside = FALSE;

    r.limit.p1.x = _cairo_fixed_from_int (clip->extents.x);
    r.limit.p1.y = _cairo_fixed_from_int (clip->extents.y);
    r.limit.p2.x = _cairo_fixed_from_int (clip->extents.x + clip->extents.width);
    r.limit.p2.y = _cairo_fixed_from_int (clip->extents.y + clip->extents.height);

    clip_path = clip->path;
    do {
	r.current_point.x = 0;
	r.current_point.y = 0;
	r.last_move_to = r.current_point;

	status = _cairo_path_fixed_interpret_flat (&clip_path->path,
						   _reduce_move_to,
						   _reduce_line_to,
						   _reduce_close,
						   &r,
						   clip_path->tolerance);
	assert (status == CAIRO_STATUS_SUCCESS);
	_reduce_close (&r);
    } while ((clip_path = clip_path->prev));

    if (! r.inside) {
	_cairo_clip_path_destroy (clip->path);
	clip->path = NULL;
    }

    return _cairo_clip_intersect_box (clip, &r.extents);
}
示例#12
0
cairo_clip_t *
_cairo_clip_intersect_rectangle (cairo_clip_t       *clip,
				 const cairo_rectangle_int_t *r)
{
    cairo_box_t box;

    if (_cairo_clip_is_all_clipped (clip))
	return clip;

    if (r->width == 0 || r->height == 0)
	return _cairo_clip_set_all_clipped (clip);

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

    return _cairo_clip_intersect_rectangle_box (clip, r, &box);
}
示例#13
0
static cairo_pattern_t *
_cairo_default_context_pop_group (void *abstract_cr)
{
    cairo_default_context_t *cr = abstract_cr;
    cairo_surface_t *group_surface;
    cairo_pattern_t *group_pattern;
    cairo_surface_t *parent_surface;
    cairo_matrix_t group_matrix;
    cairo_status_t status;

    /* Verify that we are at the right nesting level */
    if (unlikely (! _cairo_gstate_is_group (cr->gstate)))
	return _cairo_pattern_create_in_error (CAIRO_STATUS_INVALID_POP_GROUP);

    /* Get a reference to the active surface before restoring */
    group_surface = _cairo_gstate_get_target (cr->gstate);
    group_surface = cairo_surface_reference (group_surface);

    status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
    assert (status == CAIRO_STATUS_SUCCESS);

    parent_surface = _cairo_gstate_get_target (cr->gstate);

    group_pattern = cairo_pattern_create_for_surface (group_surface);
    status = group_pattern->status;
    if (unlikely (status))
        goto done;

    _cairo_gstate_get_matrix (cr->gstate, &group_matrix);
    cairo_pattern_set_matrix (group_pattern, &group_matrix);

    /* If we have a current path, we need to adjust it to compensate for
     * the device offset just removed. */
    _cairo_path_fixed_translate (cr->path,
				 _cairo_fixed_from_int (parent_surface->device_transform.x0 - group_surface->device_transform.x0),
				 _cairo_fixed_from_int (parent_surface->device_transform.y0 - group_surface->device_transform.y0));

done:
    cairo_surface_destroy (group_surface);

    return group_pattern;
}
示例#14
0
static cairo_status_t
_cairo_clip_intersect_rectangle (cairo_clip_t *clip,
				 const cairo_rectangle_int_t *rect)
{
    cairo_clip_path_t *clip_path;
    cairo_status_t status;

    if (clip->path != NULL) {
	if (rect->x <= clip->path->extents.x &&
	    rect->y <= clip->path->extents.y &&
	    rect->x + rect->width >= clip->path->extents.x + clip->path->extents.width &&
	    rect->y + rect->height >= 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);

    _cairo_path_fixed_init (&clip_path->path);

    status = _cairo_path_fixed_move_to (&clip_path->path,
					_cairo_fixed_from_int (rect->x),
					_cairo_fixed_from_int (rect->y));
    assert (status == CAIRO_STATUS_SUCCESS);
    status = _cairo_path_fixed_rel_line_to (&clip_path->path,
					    _cairo_fixed_from_int (rect->width),
					    _cairo_fixed_from_int (0));
    assert (status == CAIRO_STATUS_SUCCESS);
    status = _cairo_path_fixed_rel_line_to (&clip_path->path,
					    _cairo_fixed_from_int (0),
					    _cairo_fixed_from_int (rect->height));
    assert (status == CAIRO_STATUS_SUCCESS);
    status = _cairo_path_fixed_rel_line_to (&clip_path->path,
					    _cairo_fixed_from_int (-rect->width),
					    _cairo_fixed_from_int (0));
    assert (status == CAIRO_STATUS_SUCCESS);
    status = _cairo_path_fixed_close_path (&clip_path->path);
    assert (status == CAIRO_STATUS_SUCCESS);

    clip_path->extents = *rect;
    clip_path->fill_rule = CAIRO_FILL_RULE_WINDING;
    clip_path->tolerance = 1;
    clip_path->antialias = CAIRO_ANTIALIAS_NONE;
    clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX;

    /* could preallocate the region if it proves worthwhile */

    return CAIRO_STATUS_SUCCESS;
}
示例#15
0
void
_cairo_traps_extents (const cairo_traps_t *traps,
		      cairo_box_t         *extents)
{
    if (traps->num_traps == 0) {
	extents->p1.x = extents->p1.y = _cairo_fixed_from_int (0);
	extents->p2.x = extents->p2.y = _cairo_fixed_from_int (0);
    } else {
	*extents = traps->extents;
	if (traps->has_limits) {
	    /* clip the traps to the imposed limits */
	    if (extents->p1.x < traps->limits.p1.x)
		extents->p1.x = traps->limits.p1.x;
	    if (extents->p2.x > traps->limits.p2.x)
		extents->p2.x = traps->limits.p2.x;

	    if (extents->p1.y < traps->limits.p1.y)
		extents->p1.y = traps->limits.p1.y;
	    if (extents->p2.y > traps->limits.p2.y)
		extents->p2.y = traps->limits.p2.y;
	}
    }
}
示例#16
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;
}
示例#17
0
cairo_status_t
_cairo_surface_offset_stroke (cairo_surface_t		*surface,
			      int x, int y,
			      cairo_operator_t		 op,
			      const cairo_pattern_t	*source,
			      cairo_path_fixed_t	*path,
			      const cairo_stroke_style_t*stroke_style,
			      const cairo_matrix_t	*ctm,
			      const cairo_matrix_t	*ctm_inverse,
			      double			 tolerance,
			      cairo_antialias_t		 antialias,
			      cairo_clip_t		*clip)
{
    cairo_path_fixed_t path_copy, *dev_path = path;
    cairo_clip_t clip_copy, *dev_clip = clip;
    cairo_matrix_t dev_ctm = *ctm;
    cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
    cairo_pattern_union_t source_copy;
    cairo_status_t status;

    if (unlikely (surface->status))
	return surface->status;

    if (clip && clip->all_clipped)
	return CAIRO_STATUS_SUCCESS;

    if (x | y) {
	cairo_matrix_t m;

	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
	if (unlikely (status))
	    goto FINISH;

	_cairo_path_fixed_translate (&path_copy,
				     _cairo_fixed_from_int (-x),
				     _cairo_fixed_from_int (-y));
	dev_path = &path_copy;

	cairo_matrix_init_translate (&m, -x, -y);
	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
	if (clip != NULL) {
	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
	    if (unlikely (status))
		goto FINISH;

	    dev_clip = &clip_copy;
	}

	cairo_matrix_init_translate (&m, x, y);
	_copy_transformed_pattern (&source_copy.base, source, &m);
	source = &source_copy.base;
	cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
    }

    status = _cairo_surface_stroke (surface, op, source,
				    dev_path, stroke_style,
				    &dev_ctm, &dev_ctm_inverse,
				    tolerance, antialias,
				    dev_clip);

 FINISH:
    if (dev_path != path)
	_cairo_path_fixed_fini (dev_path);
    if (dev_clip != clip)
	_cairo_clip_reset (dev_clip);

    return status;
}
示例#18
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;
}
static cairo_status_t
_cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
{
    cairo_default_context_t *cr = abstract_cr;
    cairo_surface_t *group_surface;
    cairo_clip_t *clip;
    cairo_status_t status;

    clip = _cairo_gstate_get_clip (cr->gstate);
    if (_cairo_clip_is_all_clipped (clip)) {
        group_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
        status = group_surface->status;
        if (unlikely (status))
            goto bail;
    } else {
        cairo_surface_t *parent_surface;
        cairo_rectangle_int_t extents;
        cairo_bool_t bounded, is_empty;

        parent_surface = _cairo_gstate_get_target (cr->gstate);

        if (unlikely (parent_surface->status))
            return parent_surface->status;
        if (unlikely (parent_surface->finished))
            return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);

        /* Get the extents that we'll use in creating our new group surface */
        bounded = _cairo_surface_get_extents (parent_surface, &extents);
        if (clip)
            /* XXX: This assignment just fixes a compiler warning? */
            is_empty = _cairo_rectangle_intersect (&extents,
                                                   _cairo_clip_get_extents (clip));

        if (!bounded) {
            /* XXX: Generic solution? */
            group_surface = cairo_recording_surface_create (content, NULL);
            extents.x = extents.y = 0;
        } else {
            group_surface = _cairo_surface_create_similar_solid (parent_surface,
                            content,
                            extents.width,
                            extents.height,
                            CAIRO_COLOR_TRANSPARENT);
        }
        status = group_surface->status;
        if (unlikely (status))
            goto bail;

        /* Set device offsets on the new surface so that logically it appears at
         * the same location on the parent surface -- when we pop_group this,
         * the source pattern will get fixed up for the appropriate target surface
         * device offsets, so we want to set our own surface offsets from /that/,
         * and not from the device origin. */
        cairo_surface_set_device_offset (group_surface,
                                         parent_surface->device_transform.x0 - extents.x,
                                         parent_surface->device_transform.y0 - extents.y);

        /* If we have a current path, we need to adjust it to compensate for
         * the device offset just applied. */
        _cairo_path_fixed_translate (cr->path,
                                     _cairo_fixed_from_int (-extents.x),
                                     _cairo_fixed_from_int (-extents.y));
    }

    /* create a new gstate for the redirect */
    status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist);
    if (unlikely (status))
        goto bail;

    status = _cairo_gstate_redirect_target (cr->gstate, group_surface);

bail:
    cairo_surface_destroy (group_surface);
    return status;
}
示例#20
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;
}
示例#21
0
cairo_surface_t *
_cairo_clip_get_surface (const cairo_clip_t *clip,
			 cairo_surface_t *target,
			 int *tx, int *ty)
{
    cairo_surface_t *surface;
    cairo_status_t status;
    cairo_clip_t *copy, *region;
    cairo_clip_path_t *copy_path, *clip_path;

    if (clip->num_boxes) {
	cairo_path_fixed_t path;
	int i;

	surface = _cairo_surface_create_scratch (target,
						 CAIRO_CONTENT_ALPHA,
						 clip->extents.width,
						 clip->extents.height,
						 CAIRO_COLOR_TRANSPARENT);
	if (unlikely (surface->status))
	    return surface;

	_cairo_path_fixed_init (&path);
	status = CAIRO_STATUS_SUCCESS;
	for (i = 0; status == CAIRO_STATUS_SUCCESS && i < clip->num_boxes; i++) {
	    status = _cairo_path_fixed_add_box (&path, &clip->boxes[i],
						-_cairo_fixed_from_int (clip->extents.x),
						-_cairo_fixed_from_int (clip->extents.y));
	}
	if (status == CAIRO_STATUS_SUCCESS)
	    status = _cairo_surface_fill (surface,
					  CAIRO_OPERATOR_ADD,
					  &_cairo_pattern_white.base,
					  &path,
					  CAIRO_FILL_RULE_WINDING,
					  1.,
					  CAIRO_ANTIALIAS_DEFAULT,
					  NULL);
	_cairo_path_fixed_fini (&path);
	if (unlikely (status)) {
	    cairo_surface_destroy (surface);
	    return _cairo_surface_create_in_error (status);
	}
    } else {
	surface = _cairo_surface_create_scratch (target,
						 CAIRO_CONTENT_ALPHA,
						 clip->extents.width,
						 clip->extents.height,
						 CAIRO_COLOR_WHITE);
	if (unlikely (surface->status))
	    return surface;
    }

    copy = _cairo_clip_copy_with_translation (clip,
					      -clip->extents.x,
					      -clip->extents.y);
    copy_path = copy->path;
    copy->path = NULL;

    region = copy;
    if (! _cairo_clip_is_region (copy))
	region = _cairo_clip_copy_region (copy);

    status = CAIRO_STATUS_SUCCESS;
    clip_path = copy_path;
    while (status == CAIRO_STATUS_SUCCESS && clip_path) {
	status = _cairo_surface_fill (surface,
				      CAIRO_OPERATOR_IN,
				      &_cairo_pattern_white.base,
				      &clip_path->path,
				      clip_path->fill_rule,
				      clip_path->tolerance,
				      clip_path->antialias,
				      region);
	clip_path = clip_path->prev;
    }

    copy->path = copy_path;
    _cairo_clip_destroy (copy);
    if (region != copy)
	_cairo_clip_destroy (region);

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

    *tx = clip->extents.x;
    *ty = clip->extents.y;
    return surface;
}
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;
}
示例#23
0
static cairo_int_status_t
_add_operation (cairo_analysis_surface_t *surface,
		cairo_rectangle_int_t    *rect,
		cairo_int_status_t        backend_status)
{
    cairo_int_status_t status;
    cairo_box_t bbox;

    if (rect->width == 0 || rect->height == 0) {
	/* Even though the operation is not visible we must be careful
	 * to not allow unsupported operations to be replayed to the
	 * backend during CAIRO_PAGINATED_MODE_RENDER */
	if (backend_status == CAIRO_INT_STATUS_SUCCESS ||
	    backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
	    backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO)
	{
	    return CAIRO_INT_STATUS_SUCCESS;
	}
	else
	{
	    return CAIRO_INT_STATUS_IMAGE_FALLBACK;
	}
    }

    _cairo_box_from_rectangle (&bbox, rect);

    if (surface->has_ctm) {
	int tx, ty;

	if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) {
	    rect->x += tx;
	    rect->y += ty;

	    tx = _cairo_fixed_from_int (tx);
	    bbox.p1.x += tx;
	    bbox.p2.x += tx;

	    ty = _cairo_fixed_from_int (ty);
	    bbox.p1.y += ty;
	    bbox.p2.y += ty;
	} else {
	    _cairo_matrix_transform_bounding_box_fixed (&surface->ctm,
							&bbox, NULL);

	    if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
		/* Even though the operation is not visible we must be
		 * careful to not allow unsupported operations to be
		 * replayed to the backend during
		 * CAIRO_PAGINATED_MODE_RENDER */
		if (backend_status == CAIRO_INT_STATUS_SUCCESS ||
		    backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
		    backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO)
		{
		    return CAIRO_INT_STATUS_SUCCESS;
		}
		else
		{
		    return CAIRO_INT_STATUS_IMAGE_FALLBACK;
		}
	    }

	    _cairo_box_round_to_rectangle (&bbox, rect);
	}
    }

    if (surface->first_op) {
	surface->first_op = FALSE;
	surface->page_bbox = bbox;
    } else
	_cairo_box_add_box(&surface->page_bbox, &bbox);

    /* If the operation is completely enclosed within the fallback
     * region there is no benefit in emitting a native operation as
     * the fallback image will be painted on top.
     */
    if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN)
	return CAIRO_INT_STATUS_IMAGE_FALLBACK;

    if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
	/* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
	 * that the backend only supports this operation if the
	 * transparency removed. If the extents of this operation does
	 * not intersect any other native operation, the operation is
	 * natively supported and the backend will blend the
	 * transparency into the white background.
	 */
	if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT)
	    backend_status = CAIRO_INT_STATUS_SUCCESS;
    }

    if (backend_status == CAIRO_INT_STATUS_SUCCESS) {
	/* Add the operation to the supported region. Operations in
	 * this region will be emitted as native operations.
	 */
	surface->has_supported = TRUE;
	return cairo_region_union_rectangle (&surface->supported_region, rect);
    }

    /* Add the operation to the unsupported region. This region will
     * be painted as an image after all native operations have been
     * emitted.
     */
    surface->has_unsupported = TRUE;
    status = cairo_region_union_rectangle (&surface->fallback_region, rect);

    /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
     * unsupported operations to the recording surface as using
     * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
     * invoke the cairo-surface-fallback path then return
     * CAIRO_STATUS_SUCCESS.
     */
    if (status == CAIRO_INT_STATUS_SUCCESS)
	return CAIRO_INT_STATUS_IMAGE_FALLBACK;
    else
	return status;
}
示例#24
0
static cairo_surface_t *
_cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
			      cairo_surface_t *target)
{
    cairo_surface_t *surface;
    cairo_pattern_union_t pattern;
    cairo_status_t status;
    const cairo_rectangle_int_t *clip_extents = &clip_path->extents;
    cairo_clip_path_t *prev;
    cairo_bool_t need_translate;

    if (clip_path->surface != NULL &&
	clip_path->surface->backend == target->backend)
    {
	return cairo_surface_reference (clip_path->surface);
    }

    surface = _cairo_surface_create_similar_solid (target,
						   CAIRO_CONTENT_ALPHA,
						   clip_extents->width,
						   clip_extents->height,
						   CAIRO_COLOR_TRANSPARENT,
						   FALSE);
    if (surface == NULL) {
	if (clip_path->surface != NULL &&
	    clip_path->surface->backend == &_cairo_image_surface_backend)
	{
	    return cairo_surface_reference (clip_path->surface);
	}

	surface =
	    _cairo_image_surface_create_with_content (CAIRO_CONTENT_ALPHA,
						      clip_extents->width,
						      clip_extents->height);
    }
    if (unlikely (surface->status))
	return surface;

    _cairo_pattern_init_solid (&pattern.solid,
			       CAIRO_COLOR_WHITE,
			       CAIRO_CONTENT_COLOR);

    status = _cairo_clip_path_to_region (clip_path);
    if (unlikely (_cairo_status_is_error (status)))
	goto BAIL;

    need_translate = clip_extents->x | clip_extents->y;
    if (status == CAIRO_STATUS_SUCCESS) {
	if (need_translate) {
	    cairo_region_translate (clip_path->region,
				    -clip_extents->x, -clip_extents->y);
	}
	status = _cairo_surface_fill_region (surface,
					     CAIRO_OPERATOR_SOURCE,
					     CAIRO_COLOR_WHITE,
					     clip_path->region);
	if (need_translate) {
	    cairo_region_translate (clip_path->region,
				    clip_extents->x, clip_extents->y);
	}
	if (unlikely (status))
	    goto BAIL;

	goto DONE;
    } else {
	if (need_translate) {
	    _cairo_path_fixed_translate (&clip_path->path,
					 _cairo_fixed_from_int (-clip_extents->x),
					 _cairo_fixed_from_int (-clip_extents->y));
	}
	status = _cairo_surface_fill (surface,
				      CAIRO_OPERATOR_OVER,
				      &pattern.base,
				      &clip_path->path,
				      clip_path->fill_rule,
				      clip_path->tolerance,
				      clip_path->antialias,
				      NULL);
	if (need_translate) {
	    _cairo_path_fixed_translate (&clip_path->path,
					 _cairo_fixed_from_int (clip_extents->x),
					 _cairo_fixed_from_int (clip_extents->y));
	}

	if (unlikely (status))
	    goto BAIL;
    }

    prev = clip_path->prev;
  NEXT_PATH:
    if (prev != NULL) {
	status = _cairo_clip_path_to_region (prev);
	if (unlikely (_cairo_status_is_error (status)))
	    goto BAIL;

	if (status == CAIRO_STATUS_SUCCESS) {
	    status = _combine_region (surface, prev->region, clip_extents);
	    if (unlikely (status))
		goto BAIL;
	} else if (prev->flags & CAIRO_CLIP_PATH_IS_BOX) {
	    /* a simple box only affects the extents */
	} else if (prev->path.is_rectilinear) {
	    if (need_translate) {
		_cairo_path_fixed_translate (&prev->path,
					     _cairo_fixed_from_int (-clip_extents->x),
					     _cairo_fixed_from_int (-clip_extents->y));
	    }
	    status = _cairo_surface_fill (surface,
					  CAIRO_OPERATOR_IN,
					  &pattern.base,
					  &prev->path,
					  prev->fill_rule,
					  prev->tolerance,
					  prev->antialias,
					  NULL);
	    if (need_translate) {
		_cairo_path_fixed_translate (&prev->path,
					     _cairo_fixed_from_int (clip_extents->x),
					     _cairo_fixed_from_int (clip_extents->y));
	    }

	    if (unlikely (status))
		goto BAIL;

	    prev = prev->prev;
	    goto NEXT_PATH;
	} else {
	    cairo_surface_t *prev_surface;

	    prev_surface = _cairo_clip_path_get_surface (prev, target);
	    _cairo_pattern_init_for_surface (&pattern.surface, prev_surface);
	    cairo_surface_destroy (prev_surface);

	    cairo_matrix_init_translate (&pattern.base.matrix,
					 -prev->extents.x + clip_extents->x,
					 -prev->extents.y + clip_extents->y);
	    status = _cairo_surface_paint (surface,
					   CAIRO_OPERATOR_IN,
					   &pattern.base,
					   NULL);
	    _cairo_pattern_fini (&pattern.base);

	    if (unlikely (status))
		goto BAIL;
	}
    }

  DONE:
    cairo_surface_destroy (clip_path->surface);
    return clip_path->surface = cairo_surface_reference (surface);

  BAIL:
    cairo_surface_destroy (surface);
    return _cairo_surface_create_in_error (status);
}
示例#25
0
cairo_status_t
_cairo_clip_combine_with_surface (cairo_clip_t *clip,
				  cairo_surface_t *dst,
				  const cairo_rectangle_int_t *extents)
{
    cairo_pattern_union_t pattern;
    cairo_clip_path_t *clip_path = clip->path;
    cairo_bool_t need_translate;
    cairo_status_t status;

    assert (clip_path != NULL);

    if (clip_path->surface != NULL &&
	clip_path->surface->backend == dst->backend)
    {
	_cairo_pattern_init_for_surface (&pattern.surface,
					 clip_path->surface);
	cairo_matrix_init_translate (&pattern.base.matrix,
				     extents->x - clip_path->extents.x,
				     extents->y - clip_path->extents.y);
	status = _cairo_surface_paint (dst,
				       CAIRO_OPERATOR_IN,
				       &pattern.base,
				       NULL);

	_cairo_pattern_fini (&pattern.base);

	return status;
    }

    _cairo_pattern_init_solid (&pattern.solid,
			       CAIRO_COLOR_WHITE,
			       CAIRO_CONTENT_COLOR);

    need_translate = extents->x | extents->y;
    do {
	status = _cairo_clip_path_to_region (clip_path);
	if (unlikely (_cairo_status_is_error (status)))
	    return status;

	if (status == CAIRO_STATUS_SUCCESS)
	    return _combine_region (dst, clip_path->region, extents);

	if (clip_path->surface != NULL &&
	    clip_path->surface->backend == dst->backend)
	{
	    _cairo_pattern_init_for_surface (&pattern.surface,
					     clip_path->surface);
	    cairo_matrix_init_translate (&pattern.base.matrix,
					 extents->x - clip_path->extents.x,
					 extents->y - clip_path->extents.y);
	    status = _cairo_surface_paint (dst,
					   CAIRO_OPERATOR_IN,
					   &pattern.base,
					   NULL);

	    _cairo_pattern_fini (&pattern.base);

	    return status;
	}

	if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) {
	    cairo_region_t clip_region;

	    _cairo_region_init_rectangle (&clip_region, &clip_path->extents);
	    status = _combine_region (dst, &clip_region, extents);
	} else {
	    if (need_translate) {
		_cairo_path_fixed_translate (&clip_path->path,
					     _cairo_fixed_from_int (-extents->x),
					     _cairo_fixed_from_int (-extents->y));
	    }
	    status = _cairo_surface_fill (dst,
					  CAIRO_OPERATOR_IN,
					  &pattern.base,
					  &clip_path->path,
					  clip_path->fill_rule,
					  clip_path->tolerance,
					  clip_path->antialias,
					  NULL);
	    if (need_translate) {
		_cairo_path_fixed_translate (&clip_path->path,
					     _cairo_fixed_from_int (extents->x),
					     _cairo_fixed_from_int (extents->y));
	    }
	}

	if (unlikely (status))
	    return status;
    } while ((clip_path = clip_path->prev) != NULL);

    return CAIRO_STATUS_SUCCESS;
}
示例#26
0
cairo_int_status_t
i965_surface_glyphs (void			*abstract_surface,
		     cairo_operator_t		 op,
		     const cairo_pattern_t	*source,
		     cairo_glyph_t		*g,
		     int			 num_glyphs,
		     cairo_scaled_font_t	*scaled_font,
		     cairo_clip_t		*clip,
		     int *num_remaining)
{
    i965_surface_t *surface = abstract_surface;
    i965_surface_t *mask = NULL;
    i965_device_t *device;
    i965_glyphs_t glyphs;
    cairo_composite_rectangles_t extents;
    cairo_clip_t local_clip;
    cairo_bool_t have_clip = FALSE;
    cairo_bool_t overlap;
    cairo_region_t *clip_region = NULL;
    intel_bo_t *last_bo = NULL;
    cairo_scaled_glyph_t *glyph_cache[64];
    cairo_status_t status;
    int mask_x = 0, mask_y = 0;
    int i = 0;

    *num_remaining = 0;
    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
							  surface->intel.drm.width,
							  surface->intel.drm.height,
							  op, source,
							  scaled_font,
							  g, num_glyphs,
							  clip,
							  &overlap);
    if (unlikely (status))
	return status;

    if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents.mask))
	clip = NULL;

    if (clip != NULL && extents.is_bounded) {
	clip = _cairo_clip_init_copy (&local_clip, clip);
	status = _cairo_clip_rectangle (clip, &extents.bounded);
	if (unlikely (status))
	    return status;

	have_clip = TRUE;
    }

    if (overlap || ! extents.is_bounded) {
	cairo_format_t format;

	format = CAIRO_FORMAT_A8;
	if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
	    format = CAIRO_FORMAT_ARGB32;

	mask = (i965_surface_t *)
	    i965_surface_create_internal (&i965_device (surface)->intel.base,
					  format,
					  extents.bounded.width,
					  extents.bounded.height,
					  I965_TILING_DEFAULT,
					  TRUE);
	if (unlikely (mask->intel.drm.base.status))
	    return mask->intel.drm.base.status;

	status = _cairo_surface_paint (&mask->intel.drm.base,
				       CAIRO_OPERATOR_CLEAR,
				       &_cairo_pattern_clear.base,
				       NULL);
	if (unlikely (status)) {
	    cairo_surface_destroy (&mask->intel.drm.base);
	    return status;
	}

	i965_shader_init (&glyphs.shader, mask, CAIRO_OPERATOR_ADD);

	status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
					      &_cairo_pattern_white.base,
					      &extents.bounded);
	if (unlikely (status)) {
	    cairo_surface_destroy (&mask->intel.drm.base);
	    return status;
	}

	mask_x = -extents.bounded.x;
	mask_y = -extents.bounded.y;
    } else {
	i965_shader_init (&glyphs.shader, surface, op);

	status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
					      source, &extents.bounded);
	if (unlikely (status))
	    return status;

	if (clip != NULL) {
	    status = _cairo_clip_get_region (clip, &clip_region);
	    assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);

	    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
		i965_shader_set_clip (&glyphs.shader, clip);
	}
    }

    glyphs.head.next = NULL;
    glyphs.head.bo = NULL;
    glyphs.head.count = 0;
    glyphs.tail = &glyphs.head;

    device = i965_device (surface);
    if (mask != NULL || clip_region == NULL) {
	glyphs.get_rectangle = i965_glyphs_emit_rectangle;
    } else {
	glyphs.get_rectangle = i965_glyphs_accumulate_rectangle;
	glyphs.head.bo = intel_bo_create (&device->intel,
					  I965_VERTEX_SIZE, I965_VERTEX_SIZE,
					  FALSE, I915_TILING_NONE, 0);
	if (unlikely (glyphs.head.bo == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	glyphs.vbo_base = intel_bo_map (&device->intel, glyphs.head.bo);
    }
    glyphs.vbo_offset = 0;

    status = cairo_device_acquire (&device->intel.base.base);
    if (unlikely (status))
	goto CLEANUP_GLYPHS;

    _cairo_scaled_font_freeze_cache (scaled_font);
    //private = _cairo_scaled_font_get_device (scaled_font, device);
    if (scaled_font->surface_private == NULL) {
	scaled_font->surface_private = device;
	scaled_font->surface_backend = surface->intel.drm.base.backend;
	cairo_list_add (&scaled_font->link, &device->intel.fonts);
    }

    memset (glyph_cache, 0, sizeof (glyph_cache));

    for (i = 0; i < num_glyphs; i++) {
	cairo_scaled_glyph_t *scaled_glyph;
	int x, y, x1, x2, y1, y2;
	int cache_index = g[i].index % ARRAY_LENGTH (glyph_cache);
	intel_glyph_t *glyph;

	scaled_glyph = glyph_cache[cache_index];
	if (scaled_glyph == NULL ||
	    _cairo_scaled_glyph_index (scaled_glyph) != g[i].index)
	{
	    status = _cairo_scaled_glyph_lookup (scaled_font,
						 g[i].index,
						 CAIRO_SCALED_GLYPH_INFO_METRICS,
						 &scaled_glyph);
	    if (unlikely (status))
		goto FINISH;

	    glyph_cache[cache_index] = scaled_glyph;
	}

	if (unlikely (scaled_glyph->metrics.width  == 0 ||
		      scaled_glyph->metrics.height == 0))
	{
	    continue;
	}

	/* XXX glyph images are snapped to pixel locations */
	x = _cairo_lround (g[i].x);
	y = _cairo_lround (g[i].y);

	x1 = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
	y1 = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
	x2 = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
	y2 = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);

	if (x2 < extents.bounded.x ||
	    y2 < extents.bounded.y ||
	    x1 > extents.bounded.x + extents.bounded.width ||
	    y1 > extents.bounded.y + extents.bounded.height)
	{
	    continue;
	}

	if (scaled_glyph->surface_private == NULL) {
	    status = intel_get_glyph (&device->intel, scaled_font, scaled_glyph);
	    if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) {
		status = CAIRO_STATUS_SUCCESS;
		continue;
	    }
	    if (unlikely (status))
		goto FINISH;
	}
	glyph = intel_glyph_pin (scaled_glyph->surface_private);

	if (glyph->cache->buffer.bo != last_bo) {
	    intel_buffer_cache_t *cache = glyph->cache;

	    glyphs.shader.mask.type.vertex   = VS_GLYPHS;
	    glyphs.shader.mask.type.fragment = FS_GLYPHS;
	    glyphs.shader.mask.type.pattern  = PATTERN_BASE;

	    glyphs.shader.mask.base.bo = cache->buffer.bo;
	    glyphs.shader.mask.base.format = cache->buffer.format;
	    glyphs.shader.mask.base.width  = cache->buffer.width;
	    glyphs.shader.mask.base.height = cache->buffer.height;
	    glyphs.shader.mask.base.stride = cache->buffer.stride;
	    glyphs.shader.mask.base.filter = i965_filter (CAIRO_FILTER_NEAREST);
	    glyphs.shader.mask.base.extend = i965_extend (CAIRO_EXTEND_NONE);
	    glyphs.shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */

	    glyphs.shader.committed = FALSE;
	    status = i965_shader_commit (&glyphs.shader, device);
	    if (unlikely (status))
		goto FINISH;

	    last_bo = cache->buffer.bo;
	}

	x2 = x1 + glyph->width;
	y2 = y1 + glyph->height;

	if (mask_x)
	    x1 += mask_x, x2 += mask_x;
	if (mask_y)
	    y1 += mask_y, y2 += mask_y;

	i965_add_glyph_rectangle (&glyphs, x1, y1, x2, y2, glyph);
    }

    if (mask != NULL && clip_region != NULL)
	i965_clipped_vertices (device, &glyphs.head, clip_region);

    status = CAIRO_STATUS_SUCCESS;
  FINISH:
    _cairo_scaled_font_thaw_cache (scaled_font);
    cairo_device_release (surface->intel.drm.base.device);
  CLEANUP_GLYPHS:
    i965_shader_fini (&glyphs.shader);

    if (glyphs.head.bo != NULL) {
	struct i965_vbo *vbo, *next;

	intel_bo_destroy (&device->intel, glyphs.head.bo);
	for (vbo = glyphs.head.next; vbo != NULL; vbo = next) {
	    next = vbo->next;
	    intel_bo_destroy (&device->intel, vbo->bo);
	    free (vbo);
	}
    }

    if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) {
	cairo_path_fixed_t path;

	_cairo_path_fixed_init (&path);
	status = _cairo_scaled_font_glyph_path (scaled_font,
						g + i, num_glyphs - i,
						&path);
	if (mask_x | mask_y) {
	    _cairo_path_fixed_translate (&path,
					 _cairo_fixed_from_int (mask_x),
					 _cairo_fixed_from_int (mask_y));
	}
	if (likely (status == CAIRO_STATUS_SUCCESS)) {
	    status = surface->intel.drm.base.backend->fill (glyphs.shader.target,
							    glyphs.shader.op,
							    mask != NULL ? &_cairo_pattern_white.base : source,
							    &path,
							    CAIRO_FILL_RULE_WINDING,
							    0,
							    scaled_font->options.antialias,
							    clip);
	}
	_cairo_path_fixed_fini (&path);
    }

    if (mask != NULL) {
	if (likely (status == CAIRO_STATUS_SUCCESS)) {
	    status = i965_surface_mask_internal (surface, op, source, mask,
					         clip, &extents);
	}
	cairo_surface_finish (&mask->intel.drm.base);
	cairo_surface_destroy (&mask->intel.drm.base);
    }

    if (have_clip)
	_cairo_clip_fini (&local_clip);

    return status;
}
示例#27
0
/* XXX there is likely a faster method! ;-) */
static cairo_status_t
_region_clip_to_boxes (const cairo_region_t *region,
		       cairo_box_t **boxes,
		       int *num_boxes,
		       int *size_boxes)
{
    cairo_traps_t traps;
    cairo_status_t status;
    int n, num_rects;

    _cairo_traps_init (&traps);
    _cairo_traps_limit (&traps, *boxes, *num_boxes);
    traps.is_rectilinear = TRUE;
    traps.is_rectangular = TRUE;

    num_rects = cairo_region_num_rectangles (region);
    for (n = 0; n < num_rects; n++) {
	cairo_rectangle_int_t rect;
	cairo_point_t p1, p2;

	cairo_region_get_rectangle (region, n, &rect);

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

	status = _cairo_traps_tessellate_rectangle (&traps, &p1, &p2);
	if (unlikely (status))
	    goto CLEANUP;
    }

    status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps, CAIRO_FILL_RULE_WINDING);
    if (unlikely (status))
	goto CLEANUP;

    n = *size_boxes;
    if (n < 0)
	n = -n;

    if (traps.num_traps > n) {
	cairo_box_t *new_boxes;

	new_boxes = _cairo_malloc_ab (traps.num_traps, 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 = traps.num_traps;
    }

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

  CLEANUP:
    _cairo_traps_fini (&traps);

    return status;
}