Пример #1
0
cairo_int_status_t
_cairo_composite_rectangles_lazy_init_for_paint (cairo_composite_rectangles_t *extents,
						 cairo_surface_t *surface,
						 cairo_operator_t op,
						 const cairo_pattern_t *source,
						 const cairo_clip_t *clip)
{
    cairo_bool_t should_be_lazy = TRUE;
    if (! _cairo_composite_rectangles_init (extents,
					    surface, op, source, clip,
					    &should_be_lazy))
    {
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    if (! should_be_lazy) {
	extents->mask = extents->destination;

	extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
	if (_cairo_clip_is_all_clipped (extents->clip))
	    return CAIRO_INT_STATUS_NOTHING_TO_DO;

	if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
	    _cairo_pattern_sampled_area (&extents->source_pattern.base,
					 &extents->bounded,
					 &extents->source_sample_area);
    } else
	extents->clip = _cairo_clip_copy (clip);

    return CAIRO_STATUS_SUCCESS;
}
Пример #2
0
cairo_status_t
_cairo_surface_offset_paint (cairo_surface_t		*target,
			     int x, int y,
			     cairo_operator_t		 op,
			     const cairo_pattern_t	*source,
			     const cairo_clip_t		*clip)
{
    cairo_status_t status;
    cairo_clip_t *dev_clip = (cairo_clip_t *) clip;
    cairo_pattern_union_t source_copy;

    if (unlikely (target->status))
	return target->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);

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

    status = _cairo_surface_paint (target, op, source, dev_clip);

    if (dev_clip != clip)
	_cairo_clip_destroy (dev_clip);

    return status;
}
Пример #3
0
cairo_int_status_t
_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
					    cairo_surface_t *surface,
					    cairo_operator_t		 op,
					    const cairo_pattern_t	*source,
					    const cairo_clip_t		*clip)
{
    if (! _cairo_composite_rectangles_init (extents,
					    surface, op, source, clip))
    {
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    extents->mask = extents->destination;

    extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
    if (_cairo_clip_is_all_clipped (extents->clip))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    if (! _cairo_rectangle_intersect (&extents->unbounded,
				      _cairo_clip_get_extents (extents->clip)))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
	_cairo_pattern_sampled_area (&extents->source_pattern.base,
				     &extents->bounded,
				     &extents->source_sample_area);

    return CAIRO_STATUS_SUCCESS;
}
Пример #4
0
cairo_status_t
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
			      cairo_operator_t	 op,
			      const cairo_pattern_t *source,
			      const cairo_clip_t    *clip)
{
    cairo_status_t status;
    cairo_clip_t *dev_clip;
    cairo_pattern_union_t source_copy;

    if (unlikely (wrapper->target->status))
	return wrapper->target->status;

    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
    if (_cairo_clip_is_all_clipped (dev_clip))
	return (cairo_status_t)CAIRO_INT_STATUS_NOTHING_TO_DO;

    if (wrapper->needs_transform) {
	cairo_matrix_t m;

	_cairo_surface_wrapper_get_transform (wrapper, &m);

	status = cairo_matrix_invert (&m);
	assert (status == CAIRO_STATUS_SUCCESS);

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

    status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);

    _cairo_clip_destroy (dev_clip);
    return status;
}
Пример #5
0
cairo_clip_t *
_cairo_clip_reduce_to_rectangle (const cairo_clip_t *clip,
				 const cairo_rectangle_int_t *r)
{
    cairo_clip_t *copy;

    if (_cairo_clip_is_all_clipped (clip))
	return (cairo_clip_t *) clip;

    if (_cairo_clip_contains_rectangle (clip, r))
	return _cairo_clip_intersect_rectangle (NULL, r);

    copy = _cairo_clip_copy_intersect_rectangle (clip, r);
    if (_cairo_clip_is_all_clipped (copy))
	return copy;

    return _cairo_clip_reduce_to_boxes (copy);
}
Пример #6
0
cairo_status_t
_cairo_surface_offset_glyphs (cairo_surface_t		*surface,
			      int x, int y,
			      cairo_operator_t		 op,
			      const cairo_pattern_t	*source,
			      cairo_scaled_font_t	*scaled_font,
			      cairo_glyph_t		*glyphs,
			      int			 num_glyphs,
			      const cairo_clip_t	*clip)
{
    cairo_status_t status;
    cairo_clip_t *dev_clip = (cairo_clip_t *) clip;
    cairo_pattern_union_t source_copy;
    cairo_glyph_t *dev_glyphs;
    int i;

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

    if (_cairo_clip_is_all_clipped (clip))
	return CAIRO_STATUS_SUCCESS;

    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
    if (dev_glyphs == NULL)
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);

    if (x | y) {
	cairo_matrix_t m;

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

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

	for (i = 0; i < num_glyphs; i++) {
	    dev_glyphs[i].x -= x;
	    dev_glyphs[i].y -= y;
	}
    }

    status = _cairo_surface_show_text_glyphs (surface, op, source,
					      NULL, 0,
					      dev_glyphs, num_glyphs,
					      NULL, 0, 0,
					      scaled_font,
					      dev_clip);

    if (dev_clip != clip)
	_cairo_clip_destroy (dev_clip);
    cr_free (dev_glyphs);

    return status;
}
Пример #7
0
cairo_status_t
_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper,
				 const cairo_clip_t *clip)
{
    cairo_status_t status;
    cairo_bool_t incremental = FALSE;

    if (_cairo_clip_equal (clip, clipper->clip))
	return CAIRO_STATUS_SUCCESS;

    /* all clipped out state should never propagate this far */
    assert (!_cairo_clip_is_all_clipped (clip));

    /* XXX Is this an incremental clip? */
    if (clipper->clip && clip &&
	clip->num_boxes == clipper->clip->num_boxes &&
	memcmp (clip->boxes, clipper->clip->boxes,
		sizeof (cairo_box_t) * clip->num_boxes) == 0)
    {
	cairo_clip_path_t *clip_path = clip->path;
	while (clip_path != NULL && clip_path != clipper->clip->path)
	    clip_path = clip_path->prev;

	if (clip_path) {
	    incremental = TRUE;
	    status = _cairo_surface_clipper_intersect_clip_path_recursive (clipper,
									   clip->path,
									   clipper->clip->path);
	}
    }

    _cairo_clip_destroy (clipper->clip);
    clipper->clip = _cairo_clip_copy (clip);

    if (incremental)
	return status;

    status = clipper->intersect_clip_path (clipper, NULL, 0, 0, 0);
    if (unlikely (status))
	return status;

    if (clip == NULL)
	return CAIRO_STATUS_SUCCESS;

    status = _cairo_surface_clipper_intersect_clip_boxes (clipper, clip);
    if (unlikely (status))
	return status;

    if (clip->path != NULL) {
	    status = _cairo_surface_clipper_intersect_clip_path_recursive (clipper,
									   clip->path,
									   NULL);
    }

    return status;
}
Пример #8
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;
}
Пример #9
0
static inline cairo_bool_t
_cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
				  cairo_surface_t *surface,
				  cairo_operator_t op,
				  const cairo_pattern_t *source,
				  const cairo_clip_t *clip,
				  cairo_bool_t *should_be_lazy)
{
    if (_cairo_clip_is_all_clipped (clip))
	return FALSE;

    extents->surface = surface;
    extents->op = op;

    _cairo_surface_get_extents (surface, &extents->destination);
    extents->clip = NULL;

    extents->unbounded = extents->destination;
    extents->is_bounded = _cairo_operator_bounded_by_either (op);

    if (*should_be_lazy)
        *should_be_lazy = _cairo_composite_rectangles_check_lazy_init (extents,
                                                                       surface,
                                                                       source);

    if ((! *should_be_lazy) &&
        (clip && ! _cairo_rectangle_intersect (&extents->unbounded,
                                               _cairo_clip_get_extents (clip))))
        return FALSE;

    extents->bounded = extents->unbounded;

	extents->original_source_pattern = source;
	if (! *should_be_lazy) {
		_cairo_composite_reduce_pattern (source, &extents->source_pattern);

		_cairo_pattern_get_extents (&extents->source_pattern.base,
                                    &extents->source);
	} else
        _cairo_pattern_get_extents (extents->original_source_pattern,
                                    &extents->source);

    if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) {
	if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source))
	    return FALSE;
    }

    extents->original_mask_pattern = NULL;
    extents->mask_pattern.base.type = CAIRO_PATTERN_TYPE_SOLID;
    extents->mask_pattern.solid.color.alpha = 1.; /* XXX full initialisation? */
    extents->mask_pattern.solid.color.alpha_short = 0xffff;

    return TRUE;
}
Пример #10
0
cairo_status_t
_cairo_surface_wrapper_fill (cairo_surface_wrapper_t	*wrapper,
			     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_pattern_union_t source_copy;
    cairo_clip_t *dev_clip;

    if (unlikely (wrapper->target->status))
	return wrapper->target->status;

    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
    if (_cairo_clip_is_all_clipped (dev_clip))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    if (wrapper->needs_transform) {
	cairo_matrix_t m;

	_cairo_surface_wrapper_get_transform (wrapper, &m);

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

	_cairo_path_fixed_transform (&path_copy, &m);
	dev_path = &path_copy;

	status = cairo_matrix_invert (&m);
	assert (status == CAIRO_STATUS_SUCCESS);

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

    status = _cairo_surface_fill (wrapper->target, op, source,
				  dev_path, fill_rule,
				  tolerance, antialias,
				  dev_clip);

 FINISH:
    if (dev_path != path)
	_cairo_path_fixed_fini (dev_path);
    _cairo_clip_destroy (dev_clip);
    return status;
}
Пример #11
0
cairo_bool_t
_cairo_clip_is_polygon (const cairo_clip_t *clip)
{
    if (_cairo_clip_is_all_clipped (clip))
	return TRUE;

    /* If there is no clip, we need an infinite polygon */
    if (clip == NULL)
	return FALSE;

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

    /* check that residual is all of the same type/tolerance */
    return can_convert_to_polygon (clip);
}
Пример #12
0
static cairo_int_status_t
_cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents,
				       const cairo_clip_t *clip)
{
    if ((!_cairo_rectangle_intersect (&extents->bounded, &extents->mask)) &&
        (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE)) {
	extents->unbounded = extents->bounded;
    } else if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) {
	if (!_cairo_rectangle_intersect (&extents->unbounded, &extents->mask))
	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
    if (_cairo_clip_is_all_clipped (extents->clip))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    if (! _cairo_rectangle_intersect (&extents->unbounded,
				      _cairo_clip_get_extents (extents->clip)))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    if (! _cairo_rectangle_intersect (&extents->bounded,
				      _cairo_clip_get_extents (extents->clip)) &&
	extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
    {
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
	_cairo_pattern_sampled_area (&extents->source_pattern.base,
				     &extents->bounded,
				     &extents->source_sample_area);
    if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
	_cairo_pattern_sampled_area (&extents->mask_pattern.base,
				     &extents->bounded,
				     &extents->mask_sample_area);
	if (extents->mask_sample_area.width == 0 ||
	    extents->mask_sample_area.height == 0) {
	    _cairo_composite_rectangles_fini (extents);
	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
	}
    }

    return CAIRO_STATUS_SUCCESS;
}
Пример #13
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);
}
Пример #14
0
static void
_cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite,
				    cairo_gl_composite_t *setup)
{
    uint32_t is_bounded;

    if (_cairo_clip_is_all_clipped (composite->clip))
	return;

    /* We don't need to check CAIRO_OPERATOR_BOUND_BY_MASK in these
       situations. */
    is_bounded = composite->is_bounded;
    composite->is_bounded = CAIRO_OPERATOR_BOUND_BY_SOURCE;
    if (_cairo_composite_rectangles_can_reduce_clip (composite, composite->clip))
	return;

    _cairo_gl_composite_set_clip (setup, composite->clip);

    composite->is_bounded = is_bounded;
}
Пример #15
0
static cairo_bool_t
_cairo_clip_contains_rectangle_box (const cairo_clip_t *clip,
				    const cairo_rectangle_int_t *rect,
				    const cairo_box_t *box)
{
    int i;

    /* clip == NULL means no clip, so the clip contains everything */
    if (clip == NULL)
	return TRUE;

    if (_cairo_clip_is_all_clipped (clip))
	return FALSE;

    /* If we have a non-trivial path, just say no */
    if (clip->path)
	return FALSE;

    if (clip->extents.x > rect->x ||
	clip->extents.y > rect->y ||
	clip->extents.x + clip->extents.width  < rect->x + rect->width ||
	clip->extents.y + clip->extents.height < rect->y + rect->height)
    {
	return FALSE;
    }

    /* Check for a clip-box that wholly contains the rectangle */
    for (i = 0; i < clip->num_boxes; i++) {
	if (box->p1.x >= clip->boxes[i].p1.x &&
	    box->p1.y >= clip->boxes[i].p1.y &&
	    box->p2.x <= clip->boxes[i].p2.x &&
	    box->p2.y <= clip->boxes[i].p2.y)
	{
	    return TRUE;
	}
    }

    return FALSE;
}
Пример #16
0
static cairo_int_status_t
_draw_clip_to_stencil_buffer (cairo_gl_context_t	*ctx,
			      cairo_gl_composite_t	*setup,
			      cairo_clip_t		*clip)
{
    cairo_int_status_t status;

    assert (! _cairo_clip_is_all_clipped (clip));

    if (! _cairo_gl_ensure_stencil (ctx, setup->dst))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    glDepthMask (GL_TRUE);
    glEnable (GL_STENCIL_TEST);
    glClearStencil (0);
    glClear (GL_STENCIL_BUFFER_BIT);
    glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
    glStencilFunc (GL_EQUAL, 1, 0xffffffff);
    glColorMask (0, 0, 0, 0);

    status = _draw_clip (ctx, setup, clip);
    if (unlikely (status)) {
	glColorMask (1, 1, 1, 1);
	_disable_stencil_buffer ();
	return status;
    }

    /* We want to only render to the stencil buffer, so draw everything now. */
    _cairo_gl_composite_flush (ctx);

    glColorMask (1, 1, 1, 1);
    glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
    glStencilFunc (GL_EQUAL, 1, 0xffffffff);

    return status;;
}
Пример #17
0
cairo_clip_t *
_cairo_clip_intersect_boxes (cairo_clip_t *clip,
			     const cairo_boxes_t *boxes)
{
    cairo_boxes_t clip_boxes;
    cairo_box_t limits;
    cairo_rectangle_int_t extents;

    if (_cairo_clip_is_all_clipped (clip))
	return clip;

    if (boxes->num_boxes == 0)
	return _cairo_clip_set_all_clipped (clip);

    if (boxes->num_boxes == 1)
	return _cairo_clip_intersect_box (clip, boxes->chunks.base);

    if (clip == NULL)
	clip = _cairo_clip_create ();

    if (clip->num_boxes) {
	_cairo_boxes_init_for_array (&clip_boxes, clip->boxes, clip->num_boxes);
	if (unlikely (_cairo_boxes_intersect (&clip_boxes, boxes, &clip_boxes))) {
	    clip = _cairo_clip_set_all_clipped (clip);
	    goto out;
	}

	if (clip->boxes != &clip->embedded_box)
	    free (clip->boxes);

	clip->boxes = NULL;
	boxes = &clip_boxes;
    }

    if (boxes->num_boxes == 0) {
	clip = _cairo_clip_set_all_clipped (clip);
	goto out;
    } else if (boxes->num_boxes == 1) {
	clip->boxes = &clip->embedded_box;
	clip->boxes[0] = boxes->chunks.base[0];
	clip->num_boxes = 1;
    } else {
	clip->boxes = _cairo_boxes_to_array (boxes, &clip->num_boxes, TRUE);
    }
    _cairo_boxes_extents (boxes, &limits);

    _cairo_box_round_to_rectangle (&limits, &extents);
    if (clip->path == NULL)
	clip->extents = extents;
    else if (! _cairo_rectangle_intersect (&clip->extents, &extents))
	clip = _cairo_clip_set_all_clipped (clip);

    if (clip->region) {
	cairo_region_destroy (clip->region);
	clip->region = NULL;
    }
    clip->is_region = FALSE;

out:
    if (boxes == &clip_boxes)
	_cairo_boxes_fini (&clip_boxes);

    return clip;
}
Пример #18
0
static cairo_int_status_t
clip_and_composite_boxes (const cairo_spans_compositor_t	*compositor,
			  cairo_composite_rectangles_t		*extents,
			  cairo_boxes_t				*boxes)
{
    cairo_int_status_t status;
    cairo_polygon_t polygon;

    TRACE ((stderr, "%s\n", __FUNCTION__));
    status = trim_extents_to_boxes (extents, boxes);
    if (unlikely (status))
	return status;

    if (boxes->num_boxes == 0) {
	if (extents->is_bounded)
	    return CAIRO_STATUS_SUCCESS;

	return fixup_unbounded_boxes (compositor, extents, boxes);
    }

    /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
    if (extents->clip->path != NULL && extents->is_bounded) {
	cairo_polygon_t polygon;
	cairo_fill_rule_t fill_rule;
	cairo_antialias_t antialias;
	cairo_clip_t *clip;

	clip = _cairo_clip_copy (extents->clip);
	clip = _cairo_clip_intersect_boxes (clip, boxes);
	if (_cairo_clip_is_all_clipped (clip))
	    return CAIRO_INT_STATUS_NOTHING_TO_DO;

	status = _cairo_clip_get_polygon (clip, &polygon,
					  &fill_rule, &antialias);
	_cairo_clip_path_destroy (clip->path);
	clip->path = NULL;
	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
	    cairo_clip_t *saved_clip = extents->clip;
	    extents->clip = clip;

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

	    clip = extents->clip;
	    extents->clip = saved_clip;

	    _cairo_polygon_fini (&polygon);
	}
	_cairo_clip_destroy (clip);

	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	    return status;
    }

    if (boxes->is_pixel_aligned) {
	status = composite_aligned_boxes (compositor, extents, boxes);
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	    return status;
    }

    status = composite_boxes (compositor, extents, boxes);
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    status = _cairo_polygon_init_boxes (&polygon, boxes);
    if (unlikely (status))
	return status;

    status = composite_polygon (compositor, extents, &polygon,
				CAIRO_FILL_RULE_WINDING,
				CAIRO_ANTIALIAS_DEFAULT);
    _cairo_polygon_fini (&polygon);

    return status;
}
Пример #19
0
cairo_int_status_t
_cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t *extents,
						    const cairo_box_t *box)
{
    cairo_rectangle_int_t mask;
    cairo_clip_t *clip;

    _cairo_box_round_to_rectangle (box, &mask);
    if (mask.x == extents->mask.x &&
	mask.y == extents->mask.y &&
	mask.width  == extents->mask.width &&
	mask.height == extents->mask.height)
    {
	return CAIRO_INT_STATUS_SUCCESS;
    }

    _cairo_rectangle_intersect (&extents->mask, &mask);

    mask = extents->bounded;
    if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask) &&
	extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    if (mask.width  == extents->bounded.width &&
	mask.height == extents->bounded.height)
	return CAIRO_INT_STATUS_SUCCESS;

    if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE)) {
	extents->unbounded = extents->bounded;
    } else if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) {
	if (!_cairo_rectangle_intersect (&extents->unbounded, &extents->mask))
	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    clip = extents->clip;
    extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
    if (clip != extents->clip)
	_cairo_clip_destroy (clip);

    if (_cairo_clip_is_all_clipped (extents->clip))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    if (! _cairo_rectangle_intersect (&extents->unbounded,
				      _cairo_clip_get_extents (extents->clip)))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
	_cairo_pattern_sampled_area (&extents->source_pattern.base,
				     &extents->bounded,
				     &extents->source_sample_area);
    if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
	_cairo_pattern_sampled_area (&extents->mask_pattern.base,
				     &extents->bounded,
				     &extents->mask_sample_area);
	if (extents->mask_sample_area.width == 0 ||
	    extents->mask_sample_area.height == 0)
	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

    return CAIRO_INT_STATUS_SUCCESS;
}
Пример #20
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;
}
Пример #21
0
cairo_status_t
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
					 cairo_operator_t	     op,
					 const cairo_pattern_t	    *source,
					 const char		    *utf8,
					 int			     utf8_len,
					 const cairo_glyph_t	    *glyphs,
					 int			     num_glyphs,
					 const cairo_text_cluster_t *clusters,
					 int			     num_clusters,
					 cairo_text_cluster_flags_t  cluster_flags,
					 cairo_scaled_font_t	    *scaled_font,
					 const cairo_clip_t	    *clip)
{
    cairo_status_t status;
    cairo_clip_t *dev_clip;
    cairo_glyph_t stack_glyphs [CAIRO_STACK_ARRAY_LENGTH(cairo_glyph_t)];
    cairo_glyph_t *dev_glyphs = stack_glyphs;
    cairo_scaled_font_t *dev_scaled_font = scaled_font;
    cairo_pattern_union_t source_copy;
    cairo_font_options_t options;

    if (unlikely (wrapper->target->status))
	return wrapper->target->status;

    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
    if (_cairo_clip_is_all_clipped (dev_clip))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    cairo_surface_get_font_options (wrapper->target, &options);
    cairo_font_options_merge (&options, &scaled_font->options);

    if (wrapper->needs_transform) {
	cairo_matrix_t m;
	int i;

	_cairo_surface_wrapper_get_transform (wrapper, &m);

	if (! _cairo_matrix_is_translation (&wrapper->transform)) {
	    cairo_matrix_t ctm;

	    /* XXX No device-transform? A bug in the tangle of layers? */
	    _cairo_matrix_multiply (&ctm,
				    &wrapper->transform,
				    &scaled_font->ctm);
	    dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
							&scaled_font->font_matrix,
							&ctm, &options);
	}

	if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
	    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
	    if (unlikely (dev_glyphs == NULL)) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		goto FINISH;
	    }
	}

	for (i = 0; i < num_glyphs; i++) {
	    dev_glyphs[i] = glyphs[i];
	    cairo_matrix_transform_point (&m,
					  &dev_glyphs[i].x,
					  &dev_glyphs[i].y);
	}

	status = cairo_matrix_invert (&m);
	assert (status == CAIRO_STATUS_SUCCESS);

	_copy_transformed_pattern (&source_copy.base, source, &m);
	source = &source_copy.base;
    } else {
	if (! cairo_font_options_equal (&options, &scaled_font->options)) {
	    dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
							&scaled_font->font_matrix,
							&scaled_font->ctm,
							&options);
	}

	/* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
	 * to modify the glyph array that's passed in.  We must always
	 * copy the array before handing it to the backend.
	 */
	if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
	    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
	    if (unlikely (dev_glyphs == NULL)) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		goto FINISH;
	    }
	}

	memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
    }

    status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
					      utf8, utf8_len,
					      dev_glyphs, num_glyphs,
					      clusters, num_clusters,
					      cluster_flags,
					      dev_scaled_font,
					      dev_clip);
 FINISH:
    _cairo_clip_destroy (dev_clip);
    if (dev_glyphs != stack_glyphs)
	free (dev_glyphs);
    if (dev_scaled_font != scaled_font)
	cairo_scaled_font_destroy (dev_scaled_font);
    return status;
}
Пример #22
0
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;
}