static cairo_int_status_t
_cairo_win32_display_surface_unmap_image (void                    *abstract_surface,
					  cairo_image_surface_t   *image)
{
    cairo_win32_display_surface_t *surface = abstract_surface;

    /* Delay the download until the next flush, which means we also need
     * to make sure our sources rare flushed.
     */
    TRACE ((stderr, "%s (surface=%d)\n",
	    __FUNCTION__, to_win32_surface(surface)->base.unique_id));

    if (surface->fallback) {
	cairo_rectangle_int_t r;

	r.x = image->base.device_transform_inverse.x0;
	r.y = image->base.device_transform_inverse.y0;
	r.width  = image->width;
	r.height = image->height;

	TRACE ((stderr, "%s: adding damage (%d,%d)x(%d,%d)\n",
		__FUNCTION__, r.x, r.y, r.width, r.height));
	surface->fallback->damage =
	    _cairo_damage_add_rectangle (surface->fallback->damage, &r);
	surface = to_win32_display_surface (surface->fallback);
    }

    return _cairo_surface_unmap_image (surface->image, image);
}
static cairo_int_status_t
_cairo_win32_gdi_compositor_glyphs (const cairo_compositor_t	*compositor,
				    cairo_composite_rectangles_t*composite,
				    cairo_scaled_font_t		*scaled_font,
				    cairo_glyph_t		*glyphs,
				    int				 num_glyphs,
				    cairo_bool_t		 overlap)
{
    cairo_int_status_t status;

    status = CAIRO_INT_STATUS_UNSUPPORTED;
    if (check_blit (composite) && check_glyphs (composite, scaled_font)) {
	cairo_win32_display_surface_t *dst = to_win32_display_surface (composite->surface);

	TRACE ((stderr, "%s\n", __FUNCTION__));
	status = _cairo_win32_display_surface_set_clip(dst, composite->clip);
	if (status)
	    return status;

	status = _cairo_win32_surface_emit_glyphs (&dst->win32,
						   &composite->source_pattern.base,
						   glyphs,
						   num_glyphs,
						   scaled_font,
						   TRUE);

	_cairo_win32_display_surface_unset_clip (dst);
    }

    return status;
}
static cairo_status_t
opacity_boxes (cairo_composite_rectangles_t *composite,
	       cairo_boxes_t *boxes)
{
    cairo_win32_display_surface_t *dst = to_win32_display_surface(composite->surface);
    cairo_operator_t op = composite->op;
    const cairo_pattern_t *src = &composite->source_pattern.base;

    TRACE ((stderr, "%s\n", __FUNCTION__));
    if (composite->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    if (boxes->num_boxes == 0 && composite->is_bounded)
	return CAIRO_STATUS_SUCCESS;

    if (!boxes->is_pixel_aligned)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    if (op != CAIRO_OPERATOR_OVER)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    if (!can_alpha_blend (dst))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    return alpha_blend_boxes (dst, src, boxes,
			      composite->mask_pattern.solid.color.alpha_short >> 8);
}
static cairo_status_t
alpha_blend_boxes (cairo_win32_display_surface_t *dst,
		   const cairo_pattern_t *source,
		   cairo_boxes_t *boxes,
		   uint8_t alpha)
{
    const cairo_surface_pattern_t *pattern;
    struct copy_box cb;
    cairo_surface_t *surface;
    cairo_win32_display_surface_t *src;
    cairo_status_t status;

    TRACE ((stderr, "%s\n", __FUNCTION__));
    if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    pattern = (const cairo_surface_pattern_t *) source;
    surface = _cairo_surface_get_source (pattern->surface, &cb.limit);
    if (surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
	surface = to_image_surface(surface)->parent;
	if (surface == NULL)
	    return CAIRO_INT_STATUS_UNSUPPORTED;
    }
    if (surface->type != CAIRO_SURFACE_TYPE_WIN32)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    if (! _cairo_matrix_is_integer_translation (&source->matrix,
						&cb.tx, &cb.ty))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    src = to_win32_display_surface (surface);
    cb.dst = dst->win32.dc;
    cb.src = src->win32.dc;

    /* First check that the data is entirely within the image */
    if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    status = __cairo_surface_flush (&src->win32.base, 0);
    if (status)
	return status;

    cb.bf.BlendOp = AC_SRC_OVER;
    cb.bf.BlendFlags = 0;
    cb.bf.SourceConstantAlpha = alpha;
    cb.bf.AlphaFormat = (src->win32.format == CAIRO_FORMAT_ARGB32) ? AC_SRC_ALPHA : 0;
    cb.alpha_blend = to_win32_device(dst->win32.base.device)->alpha_blend;

    cb.tx += cb.limit.x;
    cb.ty += cb.limit.y;
    status = CAIRO_STATUS_SUCCESS;
    if (! _cairo_boxes_for_each_box (boxes, alpha_box, &cb))
	status = CAIRO_INT_STATUS_UNSUPPORTED;

    _cairo_win32_display_surface_discard_fallback (dst);
    return status;
}
예제 #5
0
/**
 * cairo_win32_surface_get_image:
 * @surface: a #cairo_surface_t
 *
 * Returns a #cairo_surface_t image surface that refers to the same bits
 * as the DIB of the Win32 surface.  If the passed-in win32 surface
 * is not a DIB surface, %NULL is returned.
 *
 * Return value: a #cairo_surface_t (owned by the win32 #cairo_surface_t),
 * or %NULL if the win32 surface is not a DIB.
 *
 * Since: 1.4
 **/
cairo_surface_t *
cairo_win32_surface_get_image (cairo_surface_t *surface)
{

    if (! _cairo_surface_is_win32 (surface)) {
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
    }

    GdiFlush();
    return to_win32_display_surface(surface)->image;
}
static cairo_image_surface_t *
_cairo_win32_display_surface_map_to_image (void                    *abstract_surface,
					   const cairo_rectangle_int_t   *extents)
{
    cairo_win32_display_surface_t *surface = abstract_surface;
    cairo_status_t status;

    TRACE ((stderr, "%s (surface=%d)\n",
	    __FUNCTION__, surface->win32.base.unique_id));

    if (surface->image)
	goto done;

    if (surface->fallback == NULL) {
	surface->fallback =
	    _cairo_win32_display_surface_create_for_dc (surface->win32.dc,
							surface->win32.format,
							surface->win32.extents.width,
							surface->win32.extents.height);
	if (unlikely (status = surface->fallback->status))
	    goto err;

	if (!BitBlt (to_win32_surface(surface->fallback)->dc,
		     0, 0,
		     surface->win32.extents.width,
		     surface->win32.extents.height,
		     surface->win32.dc,
		     0, 0,
		     SRCCOPY)) {
	    status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
	    goto err;
	}
    }

    surface = to_win32_display_surface (surface->fallback);
done:
    GdiFlush();
    return _cairo_surface_map_to_image (surface->image, extents);

err:
    cairo_surface_destroy (surface->fallback);
    surface->fallback = NULL;

    return _cairo_image_surface_create_in_error (status);
}
static cairo_status_t
draw_boxes (cairo_composite_rectangles_t *composite,
	    cairo_boxes_t *boxes)
{
    cairo_win32_display_surface_t *dst = to_win32_display_surface(composite->surface);
    cairo_operator_t op = composite->op;
    const cairo_pattern_t *src = &composite->source_pattern.base;
    cairo_int_status_t status;

    TRACE ((stderr, "%s\n", __FUNCTION__));
    if (boxes->num_boxes == 0 && composite->is_bounded)
	return CAIRO_STATUS_SUCCESS;

    if (!boxes->is_pixel_aligned)
	return CAIRO_STATUS_SUCCESS;
	//return CAIRO_INT_STATUS_UNSUPPORTED;

    if (op == CAIRO_OPERATOR_CLEAR)
	op = CAIRO_OPERATOR_SOURCE;

    if (op == CAIRO_OPERATOR_OVER &&
	_cairo_pattern_is_opaque (src, &composite->bounded))
	op = CAIRO_OPERATOR_SOURCE;

    if (dst->win32.base.is_clear &&
	(op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))
	op = CAIRO_OPERATOR_SOURCE;

    if (op == CAIRO_OPERATOR_SOURCE) {
	status = CAIRO_INT_STATUS_UNSUPPORTED;
	if (src->type == CAIRO_PATTERN_TYPE_SURFACE) {
	    status = copy_boxes (dst, src, boxes);
	    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
		status = upload_boxes (dst, src, boxes);
	} else if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
	    status = fill_boxes (dst, src, boxes);
	}
	return status;
    }

    if (op == CAIRO_OPERATOR_OVER && can_alpha_blend (dst))
	return alpha_blend_boxes (dst, src, boxes, 255);

    return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_bool_t check_blit (cairo_composite_rectangles_t *composite)
{
    cairo_win32_display_surface_t *dst;

    if (composite->clip->path)
	return FALSE;

    dst = to_win32_display_surface (composite->surface);
    if (dst->fallback)
	return FALSE;

    if (dst->win32.format != CAIRO_FORMAT_RGB24)
	return FALSE;

    if (dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_BITBLT)
	return TRUE;

    return dst->image == NULL;
}
static cairo_status_t
_cairo_win32_display_surface_flush (void *abstract_surface, unsigned flags)
{
    cairo_win32_display_surface_t *surface = abstract_surface;
    cairo_status_t status = CAIRO_STATUS_SUCCESS;

    if (flags)
	return CAIRO_STATUS_SUCCESS;

    TRACE ((stderr, "%s (surface=%d)\n",
	    __FUNCTION__, surface->win32.base.unique_id));
    if (surface->fallback == NULL)
	return CAIRO_STATUS_SUCCESS;

    if (surface->fallback->damage) {
	cairo_win32_display_surface_t *fallback;
	cairo_damage_t *damage;

	damage = _cairo_damage_reduce (surface->fallback->damage);
	surface->fallback->damage = NULL;

	fallback = to_win32_display_surface (surface->fallback);
	assert (fallback->image);

	TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__,
		damage->region ? cairo_region_num_rectangles (damage->region) : 0));

	if (damage->status) {
	    if (!BitBlt (surface->win32.dc,
			 0, 0,
			 surface->win32.extents.width,
			 surface->win32.extents.height,
			 fallback->win32.dc,
			 0, 0,
			 SRCCOPY))
		status = _cairo_win32_print_gdi_error (__FUNCTION__);
	} else if (damage->region) {
	    int n = cairo_region_num_rectangles (damage->region), i;
	    for (i = 0; i < n; i++) {
		cairo_rectangle_int_t rect;

		cairo_region_get_rectangle (damage->region, i, &rect);
		TRACE ((stderr, "%s: damage (%d,%d)x(%d,%d)\n", __FUNCTION__,
			rect.x, rect.y,
			rect.width, rect.height));
		if (!BitBlt (surface->win32.dc,
			     rect.x, rect.y,
			     rect.width, rect.height,
			     fallback->win32.dc,
			     rect.x, rect.y,
			     SRCCOPY)) {
		    status = _cairo_win32_print_gdi_error (__FUNCTION__);
		    break;
		}
	    }
	}
	_cairo_damage_destroy (damage);
    } else {
	cairo_surface_destroy (surface->fallback);
	surface->fallback = NULL;
    }

    return status;
}