static cairo_bool_t check_glyphs (cairo_composite_rectangles_t *composite,
				  cairo_scaled_font_t *scaled_font)
{
    if (! _cairo_clip_is_region (composite->clip))
	return FALSE;

    if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_WIN32)
	return FALSE;

    if (! _cairo_pattern_is_opaque_solid (&composite->source_pattern.base))
	return FALSE;

    return (composite->op == CAIRO_OPERATOR_CLEAR ||
	    composite->op == CAIRO_OPERATOR_SOURCE ||
	    composite->op == CAIRO_OPERATOR_OVER);
}
Exemple #2
0
cairo_status_t
_cairo_clip_combine_with_surface (const cairo_clip_t *clip,
				  cairo_surface_t *dst,
				  int dst_x, int dst_y)
{
    cairo_clip_path_t *copy_path;
    cairo_clip_path_t *clip_path;
    cairo_clip_t *copy;
    cairo_status_t status = CAIRO_STATUS_SUCCESS;

    copy = _cairo_clip_copy_with_translation (clip, -dst_x, -dst_y);
    copy_path = copy->path;
    copy->path = NULL;

    if (copy->boxes) {
	status = _cairo_surface_paint (dst,
				       CAIRO_OPERATOR_IN,
				       &_cairo_pattern_white.base,
				       copy);
    }

    clip = NULL;
    if (_cairo_clip_is_region (copy))
	clip = copy;
    clip_path = copy_path;
    while (status == CAIRO_STATUS_SUCCESS && clip_path) {
	status = _cairo_surface_fill (dst,
				      CAIRO_OPERATOR_IN,
				      &_cairo_pattern_white.base,
				      &clip_path->path,
				      clip_path->fill_rule,
				      clip_path->tolerance,
				      clip_path->antialias,
				      clip);
	clip_path = clip_path->prev;
    }

    copy->path = copy_path;
    _cairo_clip_destroy (copy);
    return status;
}
static cairo_status_t
clip_and_composite (cairo_composite_rectangles_t *extents,
		    draw_func_t		 draw_func,
		    void		*draw_closure)
{
    cairo_status_t status;

    status = set_clip_region (extents);
    if (unlikely (status))
	return status;

    if (extents->op == CAIRO_OPERATOR_SOURCE) {
	status = clip_and_composite_source (extents, draw_func, draw_closure);
    } else {
	if (extents->op == CAIRO_OPERATOR_CLEAR) {
	    extents->source_pattern.solid = _cairo_pattern_white;
	    extents->op = CAIRO_OPERATOR_DEST_OUT;
	}
	if (! _cairo_clip_is_region (extents->clip)) {
	    if (extents->is_bounded)
		status = clip_and_composite_with_mask (extents, draw_func, draw_closure);
	    else
		status = clip_and_composite_combine (extents, draw_func, draw_closure);
	} else {
	    status = draw_func ((cairo_image_surface_t *) extents->surface,
				draw_closure,
				extents->op,
				&extents->source_pattern.base,
				0, 0,
				&extents->bounded);
	}
    }

    if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
	status = fixup_unbounded (extents);

    return status;
}
cairo_status_t
_cairo_win32_display_surface_set_clip (cairo_win32_display_surface_t *surface,
				       cairo_clip_t *clip)
{
    char stack[512];
    cairo_rectangle_int_t extents;
    int num_rects;
    RGNDATA *data;
    size_t data_size;
    RECT *rects;
    int i;
    HRGN gdi_region;
    cairo_status_t status;
    cairo_region_t *region;

    /* The semantics we want is that any clip set by cairo combines
     * is intersected with the clip on device context that the
     * surface was created for. To implement this, we need to
     * save the original clip when first setting a clip on surface.
     */

    assert (_cairo_clip_is_region (clip));
    region = _cairo_clip_get_region (clip);
    if (region == NULL)
	return CAIRO_STATUS_SUCCESS;

    cairo_region_get_extents (region, &extents);
    num_rects = cairo_region_num_rectangles (region);

    /* XXX see notes in _cairo_win32_save_initial_clip --
     * this code will interact badly with a HDC which had an initial
     * world transform -- we should probably manually transform the
     * region rects, because SelectClipRgn takes device units, not
     * logical units (unlike IntersectClipRect).
     */

    data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT);
    if (data_size > sizeof (stack)) {
	data = malloc (data_size);
	if (!data)
	    return _cairo_error(CAIRO_STATUS_NO_MEMORY);
    } else
	data = (RGNDATA *)stack;

    data->rdh.dwSize = sizeof (RGNDATAHEADER);
    data->rdh.iType = RDH_RECTANGLES;
    data->rdh.nCount = num_rects;
    data->rdh.nRgnSize = num_rects * sizeof (RECT);
    data->rdh.rcBound.left = extents.x;
    data->rdh.rcBound.top = extents.y;
    data->rdh.rcBound.right = extents.x + extents.width;
    data->rdh.rcBound.bottom = extents.y + extents.height;

    rects = (RECT *)data->Buffer;
    for (i = 0; i < num_rects; i++) {
	cairo_rectangle_int_t rect;

	cairo_region_get_rectangle (region, i, &rect);

	rects[i].left   = rect.x;
	rects[i].top    = rect.y;
	rects[i].right  = rect.x + rect.width;
	rects[i].bottom = rect.y + rect.height;
    }

    gdi_region = ExtCreateRegion (NULL, data_size, data);
    if ((char *)data != stack)
	free (data);

    if (!gdi_region)
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    /* AND the new region into our DC */
    status = CAIRO_STATUS_SUCCESS;
    if (ExtSelectClipRgn (surface->win32.dc, gdi_region, RGN_AND) == ERROR)
	status = _cairo_win32_print_gdi_error (__FUNCTION__);

    DeleteObject (gdi_region);

    return status;
}
static cairo_status_t
fixup_unbounded (const cairo_composite_rectangles_t *extents)
{
    cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
    pixman_image_t *mask;
    int mask_x, mask_y;

    if (! _cairo_clip_is_region (extents->clip)) {
	cairo_image_surface_t *clip;

	clip = get_clip_surface (dst, extents, &mask_x, &mask_y);
	if (unlikely (clip->base.status))
	    return clip->base.status;

	mask = pixman_image_ref (clip->pixman_image);
	cairo_surface_destroy (&clip->base);
    } else {
	mask_x = mask_y = 0;
	mask = _pixman_image_for_color (CAIRO_COLOR_WHITE);
	if (unlikely (mask == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    /* top */
    if (extents->bounded.y != extents->unbounded.y) {
	int x = extents->unbounded.x;
	int y = extents->unbounded.y;
	int width = extents->unbounded.width;
	int height = extents->bounded.y - y;

	pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
				  mask, NULL, dst->pixman_image,
				  x - mask_x, y - mask_y,
				  0, 0,
				  x, y,
				  width, height);
    }

    /* left */
    if (extents->bounded.x != extents->unbounded.x) {
	int x = extents->unbounded.x;
	int y = extents->bounded.y;
	int width = extents->bounded.x - x;
	int height = extents->bounded.height;

	pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
				  mask, NULL, dst->pixman_image,
				  x - mask_x, y - mask_y,
				  0, 0,
				  x, y,
				  width, height);
    }

    /* right */
    if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
	int x = extents->bounded.x + extents->bounded.width;
	int y = extents->bounded.y;
	int width = extents->unbounded.x + extents->unbounded.width - x;
	int height = extents->bounded.height;

	pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
				  mask, NULL, dst->pixman_image,
				  x - mask_x, y - mask_y,
				  0, 0,
				  x, y,
				  width, height);
    }

    /* bottom */
    if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
	int x = extents->unbounded.x;
	int y = extents->bounded.y + extents->bounded.height;
	int width = extents->unbounded.width;
	int height = extents->unbounded.y + extents->unbounded.height - y;

	pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
				  mask, NULL, dst->pixman_image,
				  x - mask_x, y - mask_y,
				  0, 0,
				  x, y,
				  width, height);
    }

    pixman_image_unref (mask);

    return CAIRO_STATUS_SUCCESS;
}
Exemple #6
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
_cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor,
				     cairo_composite_rectangles_t *extents,
				     const cairo_path_fixed_t	*path,
				     const cairo_stroke_style_t	*style,
				     const cairo_matrix_t	*ctm,
				     const cairo_matrix_t	*ctm_inverse,
				     double		 tolerance,
				     cairo_antialias_t	 antialias)
{
    cairo_surface_t *mask;
    cairo_surface_pattern_t pattern;
    cairo_int_status_t status;
    cairo_clip_t *clip;

    if (! extents->is_bounded)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    TRACE ((stderr, "%s\n", __FUNCTION__));
    mask = _cairo_surface_create_scratch (extents->surface,
					  CAIRO_CONTENT_ALPHA,
					  extents->bounded.width,
					  extents->bounded.height,
					  NULL);
    if (unlikely (mask->status))
	return mask->status;

    clip = extents->clip;
    if (! _cairo_clip_is_region (clip))
	clip = _cairo_clip_copy_region (clip);

    if (! mask->is_clear) {
	status = _cairo_surface_offset_paint (mask,
					      extents->bounded.x,
					      extents->bounded.y,
					      CAIRO_OPERATOR_CLEAR,
					      &_cairo_pattern_clear.base,
					      clip);
	if (unlikely (status))
	    goto error;
    }

    status = _cairo_surface_offset_stroke (mask,
					   extents->bounded.x,
					   extents->bounded.y,
					   CAIRO_OPERATOR_ADD,
					   &_cairo_pattern_white.base,
					   path, style, ctm, ctm_inverse,
					   tolerance, antialias,
					   clip);
    if (unlikely (status))
	goto error;

    if (clip != extents->clip) {
	status = _cairo_clip_combine_with_surface (extents->clip, mask,
						   extents->bounded.x,
						   extents->bounded.y);
	if (unlikely (status))
	    goto error;
    }

    _cairo_pattern_init_for_surface (&pattern, mask);
    cairo_matrix_init_translate (&pattern.base.matrix,
				 -extents->bounded.x,
				 -extents->bounded.y);
    pattern.base.filter = CAIRO_FILTER_NEAREST;
    pattern.base.extend = CAIRO_EXTEND_NONE;
    if (extents->op == CAIRO_OPERATOR_SOURCE) {
	status = _cairo_surface_mask (extents->surface,
				      CAIRO_OPERATOR_DEST_OUT,
				      &_cairo_pattern_white.base,
				      &pattern.base,
				      clip);
	if ((status == CAIRO_INT_STATUS_SUCCESS)) {
	    status = _cairo_surface_mask (extents->surface,
					  CAIRO_OPERATOR_ADD,
					  &extents->source_pattern.base,
					  &pattern.base,
					  clip);
	}
    } else {
	status = _cairo_surface_mask (extents->surface,
				      extents->op,
				      &extents->source_pattern.base,
				      &pattern.base,
				      clip);
    }
    _cairo_pattern_fini (&pattern.base);

error:
    cairo_surface_destroy (mask);
    if (clip != extents->clip)
	_cairo_clip_destroy (clip);
    return status;
}