Пример #1
0
static cairo_int_status_t
_cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
				    cairo_gl_context_t *ctx,
				    int vertex_size)
{

    if (! _cairo_gl_context_is_flushed (ctx) &&
	(! cairo_region_equal (ctx->clip_region, setup->clip_region) ||
	 ! _cairo_clip_equal (ctx->clip, setup->clip)))
	_cairo_gl_composite_flush (ctx);

    cairo_region_destroy (ctx->clip_region);
    ctx->clip_region = cairo_region_reference (setup->clip_region);
    _cairo_clip_destroy (ctx->clip);
    ctx->clip = _cairo_clip_copy (setup->clip);

    assert (!setup->clip_region || !setup->clip);

    if (ctx->clip_region) {
	_disable_stencil_buffer ();
	glEnable (GL_SCISSOR_TEST);
	return CAIRO_INT_STATUS_SUCCESS;
    }

    if (ctx->clip)
	return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
							   vertex_size);

    _disable_stencil_buffer ();
    glDisable (GL_SCISSOR_TEST);
    return CAIRO_INT_STATUS_SUCCESS;
}
Пример #2
0
cairo_int_status_t
_cairo_composite_rectangles_lazy_init_for_fill (cairo_composite_rectangles_t *extents,
						cairo_surface_t *surface,
						cairo_operator_t op,
						const cairo_pattern_t *source,
						const cairo_path_fixed_t *path,
						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) {
	_cairo_path_fixed_approximate_fill_extents (path, &extents->mask);

	return _cairo_composite_rectangles_intersect (extents, clip);
    }

    extents->clip = _cairo_clip_copy (clip);
    return CAIRO_INT_STATUS_SUCCESS;
}
Пример #3
0
cairo_int_status_t
_cairo_composite_rectangles_lazy_init_for_glyphs (cairo_composite_rectangles_t *extents,
						  cairo_surface_t *surface,
						  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_bool_t *overlap)
{
    cairo_status_t status;
    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;

    status = _cairo_scaled_font_glyph_device_extents (scaled_font,
						      glyphs, num_glyphs,
						      &extents->source,
						      overlap);
    if (unlikely (status))
	return status;

    extents->clip = _cairo_clip_copy (clip);

    return CAIRO_INT_STATUS_SUCCESS;
}
Пример #4
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;
}
Пример #5
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;
}
Пример #6
0
static cairo_clip_t *
_cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper,
				 const cairo_clip_t *clip)
{
    cairo_clip_t *copy;

    copy = _cairo_clip_copy (clip);
    if (wrapper->has_extents) {
	copy = _cairo_clip_intersect_rectangle (copy, &wrapper->extents);
    }
    copy = _cairo_clip_transform (copy, &wrapper->transform);
    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform))
	copy = _cairo_clip_transform (copy, &wrapper->target->device_transform);
    if (wrapper->clip)
	copy = _cairo_clip_intersect_clip (copy, wrapper->clip);

    return copy;
}
Пример #7
0
static cairo_clip_t *
_cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper,
				 const cairo_clip_t *clip)
{
    cairo_clip_t *copy;
    cairo_matrix_t m;

    copy = _cairo_clip_copy (clip);
    if (wrapper->has_extents) {
	copy = _cairo_clip_intersect_rectangle (copy, &wrapper->extents);
    }
    _cairo_surface_wrapper_get_transform (wrapper, &m);
    copy = _cairo_clip_transform (copy, &m);
    if (wrapper->clip)
	copy = _cairo_clip_intersect_clip (copy, wrapper->clip);

    return copy;
}
Пример #8
0
cairo_int_status_t
_cairo_composite_rectangles_lazy_init_for_mask (cairo_composite_rectangles_t *extents,
						cairo_surface_t *surface,
						cairo_operator_t op,
						const cairo_pattern_t *source,
						const cairo_pattern_t *mask,
						const cairo_clip_t *clip)
{
	cairo_bool_t ret;
	cairo_bool_t should_be_lazy = (op == CAIRO_OPERATOR_SOURCE) ? FALSE : TRUE;


	if (! _cairo_composite_rectangles_init (extents,
						surface, op, source, clip,
						&should_be_lazy))
    {
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    }

	extents->original_mask_pattern = mask;

	if (! should_be_lazy) {
		_cairo_composite_reduce_pattern (mask, &extents->mask_pattern);
		_cairo_pattern_get_extents (&extents->mask_pattern.base,
					&extents->mask);
		return _cairo_composite_rectangles_intersect (extents, clip);
	}

	_cairo_pattern_get_extents (extents->original_mask_pattern,
				&extents->mask);

	ret = _cairo_rectangle_intersect (&extents->bounded, &extents->mask);
	if (! ret && 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) &&
			 (!_cairo_rectangle_intersect (&extents->unbounded, &extents->mask)))
			 return CAIRO_INT_STATUS_NOTHING_TO_DO;

	extents->clip = _cairo_clip_copy (clip);
	return CAIRO_INT_STATUS_SUCCESS;
}
Пример #9
0
static cairo_int_status_t
_cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
				    cairo_gl_context_t *ctx,
				    int vertex_size)
{
    cairo_bool_t clip_changing = TRUE;
    cairo_bool_t clip_region_changing = TRUE;

    if (! ctx->clip && ! setup->clip && ! setup->clip_region && ! ctx->clip_region)
	goto disable_all_clipping;

    clip_changing = ! _cairo_clip_equal (ctx->clip, setup->clip);
    clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region);
    if (! _cairo_gl_context_is_flushed (ctx) &&
	(clip_region_changing || clip_changing))
	_cairo_gl_composite_flush (ctx);

    assert (!setup->clip_region || !setup->clip);

    /* setup->clip is only used by the msaa compositor and setup->clip_region
     * only by the other compositors, so it's safe to wait to clean up obsolete
     * clips. */
    if (clip_region_changing) {
	cairo_region_destroy (ctx->clip_region);
	ctx->clip_region = cairo_region_reference (setup->clip_region);
    }
    if (clip_changing) {
	_cairo_clip_destroy (ctx->clip);
	ctx->clip = _cairo_clip_copy (setup->clip);
    }

    /* For clip regions, we scissor right before drawing. */
    if (setup->clip_region)
	goto disable_all_clipping;

    if (setup->clip)
	return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
                                                           vertex_size);
disable_all_clipping:
    _disable_stencil_buffer ();
    glDisable (GL_SCISSOR_TEST);
    return CAIRO_INT_STATUS_SUCCESS;
}
Пример #10
0
static cairo_int_status_t
render_glyphs_via_mask (cairo_gl_surface_t *dst,
			int dst_x, int dst_y,
			cairo_operator_t  op,
			cairo_surface_t *source,
			cairo_composite_glyphs_info_t *info,
			cairo_clip_t *clip,
			cairo_bool_t via_msaa_compositor)
{
    cairo_surface_t *mask;
    cairo_status_t status;
    cairo_bool_t has_component_alpha;

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

    /* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */
    mask = cairo_gl_surface_create (dst->base.device,
                                    CAIRO_CONTENT_COLOR_ALPHA,
                                    info->extents.width,
                                    info->extents.height);
    if (unlikely (mask->status))
        return mask->status;

    status = render_glyphs ((cairo_gl_surface_t *) mask,
			    info->extents.x, info->extents.y,
			    CAIRO_OPERATOR_ADD, NULL,
			    info, &has_component_alpha, NULL,
			    via_msaa_compositor);
    if (likely (status == CAIRO_STATUS_SUCCESS)) {
	cairo_surface_pattern_t mask_pattern;
	cairo_surface_pattern_t source_pattern;
	cairo_rectangle_int_t clip_extents;

	mask->is_clear = FALSE;
	_cairo_pattern_init_for_surface (&mask_pattern, mask);
	mask_pattern.base.has_component_alpha = has_component_alpha;
	mask_pattern.base.filter = CAIRO_FILTER_NEAREST;
	mask_pattern.base.extend = CAIRO_EXTEND_NONE;

	cairo_matrix_init_translate (&mask_pattern.base.matrix,
		                     dst_x-info->extents.x, dst_y-info->extents.y);

	_cairo_pattern_init_for_surface (&source_pattern, source);
	cairo_matrix_init_translate (&source_pattern.base.matrix,
		                     dst_x-info->extents.x, dst_y-info->extents.y);

	clip = _cairo_clip_copy (clip);
	clip_extents.x = info->extents.x - dst_x;
	clip_extents.y = info->extents.y - dst_y;
	clip_extents.width = info->extents.width;
	clip_extents.height = info->extents.height;
	clip = _cairo_clip_intersect_rectangle (clip, &clip_extents);

	status = _cairo_surface_mask (&dst->base, op,
		                      &source_pattern.base,
				      &mask_pattern.base,
				      clip);

	_cairo_clip_destroy (clip);

	_cairo_pattern_fini (&mask_pattern.base);
	_cairo_pattern_fini (&source_pattern.base);
    }

    cairo_surface_destroy (mask);

    return status;
}
Пример #11
0
static cairo_int_status_t
_cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
				cairo_composite_rectangles_t	*composite,
				const cairo_path_fixed_t	*path,
				cairo_fill_rule_t		 fill_rule,
				double				 tolerance,
				cairo_antialias_t		 antialias)
{
    cairo_gl_composite_t setup;
    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
    cairo_gl_context_t *ctx = NULL;
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
    cairo_traps_t traps;
    cairo_bool_t use_color_attr = FALSE;

    if (! can_use_msaa_compositor (dst, antialias))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    if (composite->is_bounded == FALSE) {
	cairo_surface_t* surface = _prepare_unbounded_surface (dst);

	if (unlikely (surface == NULL))
	    return CAIRO_INT_STATUS_UNSUPPORTED;


	status = _cairo_compositor_fill (compositor, surface,
					 CAIRO_OPERATOR_SOURCE,
					 &composite->source_pattern.base,
					 path, fill_rule, tolerance,
					 antialias, NULL);

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

	return _paint_back_unbounded_surface (compositor, composite, surface);
    }

    if (_cairo_path_fixed_fill_is_rectilinear (path) &&
	composite->clip != NULL &&
	composite->clip->num_boxes == 1 &&
	composite->clip->path == NULL) {
	cairo_clip_t *clip = _cairo_clip_copy (composite->clip);
	clip = _cairo_clip_intersect_rectilinear_path (clip,
						       path,
						       fill_rule,
						       antialias);
	if (clip->num_boxes)
		status = _cairo_gl_msaa_compositor_fill_rectilinear (compositor,
								     composite,
								     path,
								     fill_rule,
								     tolerance,
								     antialias,
								     clip);
	_cairo_clip_destroy (clip);

	return status;
    }

    status = _cairo_gl_composite_init (&setup,
				       composite->op,
				       dst,
				       FALSE /* assume_component_alpha */);
    if (unlikely (status)) {
        _cairo_gl_composite_fini (&setup);
	return status;
    }

    _cairo_traps_init (&traps);

    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
	status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
							      fill_rule,
							      antialias,
							      &traps);
	use_color_attr = TRUE;
    } else
	status = _cairo_path_fixed_fill_to_traps (path, fill_rule,
						  tolerance, &traps);
    if (unlikely (status))
	goto cleanup_traps;

    status = _cairo_gl_composite_set_source (&setup,
					     composite->original_source_pattern,
					     &composite->source_sample_area,
					     &composite->bounded,
					     use_color_attr);
    if (unlikely (status))
	goto cleanup_setup;

    _cairo_gl_msaa_compositor_set_clip (composite, &setup);

    status = _cairo_gl_composite_begin_multisample (&setup, &ctx,
	antialias != CAIRO_ANTIALIAS_NONE);
    if (unlikely (status))
	goto cleanup_setup;

    status = _draw_traps (ctx, &setup, &traps);
    if (unlikely (status))
        goto cleanup_setup;

cleanup_setup:
    _cairo_gl_composite_fini (&setup);

    if (ctx)
	status = _cairo_gl_context_release (ctx, status);

cleanup_traps:
    _cairo_traps_fini (&traps);

    return status;
}
Пример #12
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;
}
Пример #13
0
static cairo_int_status_t
_cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
					    cairo_gl_context_t *ctx,
					    int vertex_size)
{
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;

    cairo_gl_surface_t *dst = setup->dst;
    cairo_clip_t *clip = setup->clip;

    if (clip->num_boxes == 1 && clip->path == NULL) {
	_scissor_to_box (dst, &clip->boxes[0]);
	goto disable_stencil_buffer_and_return;
    }

    if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
	status = CAIRO_INT_STATUS_UNSUPPORTED;
	goto disable_stencil_buffer_and_return;
    }

    /* We only want to clear the part of the stencil buffer
     * that we are about to use. It also does not hurt to
     * scissor around the painted clip. */
    _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (clip));

    /* The clip is not rectangular, so use the stencil buffer. */
    glDepthMask (GL_TRUE);
    glEnable (GL_STENCIL_TEST);

    /* Texture surfaces have private depth/stencil buffers, so we can
     * rely on any previous clip being cached there. */
    if (_cairo_gl_surface_is_texture (setup->dst)) {
	cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer;
	if (_cairo_clip_equal (old_clip, setup->clip))
	    goto activate_stencil_buffer_and_return;

	if (old_clip) {
	    _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
	}

	setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
    }

    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 = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip);

    if (unlikely (status)) {
	glColorMask (1, 1, 1, 1);
	goto disable_stencil_buffer_and_return;
    }

    /* We want to only render to the stencil buffer, so draw everything now.
       Flushing also unbinds the VBO, which we want to rebind for regular
       drawing. */
    _cairo_gl_composite_flush (ctx);
    _cairo_gl_composite_setup_vbo (ctx, vertex_size);

activate_stencil_buffer_and_return:
    glColorMask (1, 1, 1, 1);
    glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
    glStencilFunc (GL_EQUAL, 1, 0xffffffff);
    return CAIRO_INT_STATUS_SUCCESS;

disable_stencil_buffer_and_return:
    _disable_stencil_buffer ();
    return status;
}