static cairo_status_t
_cairo_win32_display_surface_mark_dirty (void *abstract_surface,
					 int x, int y, int width, int height)
{
    _cairo_win32_display_surface_discard_fallback (abstract_surface);
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_win32_display_surface_finish (void *abstract_surface)
{
    cairo_win32_display_surface_t *surface = abstract_surface;

    if (surface->image && to_image_surface(surface->image)->parent) {
	assert (to_image_surface(surface->image)->parent == &surface->win32.base);
	/* Unhook ourselves first to avoid the double-unref from the image */
	to_image_surface(surface->image)->parent = NULL;
	cairo_surface_finish (surface->image);
	cairo_surface_destroy (surface->image);
    }

    /* If we created the Bitmap and DC, destroy them */
    if (surface->bitmap) {
	SelectObject (surface->win32.dc, surface->saved_dc_bitmap);
	DeleteObject (surface->bitmap);
	DeleteDC (surface->win32.dc);
    }

    _cairo_win32_display_surface_discard_fallback (surface);

    if (surface->initial_clip_rgn)
	DeleteObject (surface->initial_clip_rgn);

    return CAIRO_STATUS_SUCCESS;
}
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;
}
static cairo_status_t
copy_boxes (cairo_win32_display_surface_t *dst,
	    const cairo_pattern_t *source,
	    cairo_boxes_t *boxes)
{
    const cairo_surface_pattern_t *pattern;
    struct copy_box cb;
    cairo_surface_t *surface;
    cairo_status_t status;
    cairo_win32_surface_t *src;

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

    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_surface(surface);

    if (src->format != dst->win32.format &&
	!(src->format == CAIRO_FORMAT_ARGB32 && dst->win32.format == CAIRO_FORMAT_RGB24))
    {
	/* forbid copy different surfaces unless it is from argb32 to
	 * rgb (dropping alpha) */
        return CAIRO_INT_STATUS_UNSUPPORTED;
    }
    cb.dst = dst->win32.dc;
    cb.src = src->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 (surface, 0);
    if (status)
	return status;

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

    _cairo_win32_display_surface_discard_fallback (dst);
    return status;
}
static cairo_int_status_t
_cairo_win32_display_surface_mask (void				*surface,
				   cairo_operator_t		 op,
				   const cairo_pattern_t	*source,
				   const cairo_pattern_t	*mask,
				   const cairo_clip_t		*clip)
{
    cairo_win32_device_t *device = to_win32_device_from_surface (surface);

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

    if (clip == NULL && op == CAIRO_OPERATOR_SOURCE)
	_cairo_win32_display_surface_discard_fallback (surface);

    return _cairo_compositor_mask (device->compositor,
				   surface, op, source, mask, clip);
}
static cairo_status_t
upload_boxes (cairo_win32_display_surface_t *dst,
	      const cairo_pattern_t *source,
	      cairo_boxes_t *boxes)
{
    const cairo_surface_pattern_t *pattern;
    struct upload_box cb;
    cairo_surface_t *surface;
    cairo_image_surface_t *image;
    void *image_extra;
    cairo_status_t status;

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

    if ((dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB) == 0)
	return CAIRO_INT_STATUS_UNSUPPORTED;

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

    pattern = (const cairo_surface_pattern_t *) source;
    surface = _cairo_surface_get_source (pattern->surface, &cb.limit);

    /* 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;

    if (surface->type != CAIRO_SURFACE_TYPE_IMAGE) {
	status = _cairo_surface_acquire_source_image (surface,
						      &image, &image_extra);
	if (status)
	    return status;
    } else
	image = to_image_surface(surface);

    status = CAIRO_INT_STATUS_UNSUPPORTED;
    if (!(image->format == CAIRO_FORMAT_ARGB32 ||
	  image->format == CAIRO_FORMAT_RGB24))
	goto err;
    if (image->stride != 4*image->width)
	goto err;

    cb.dst = dst->win32.dc;
    cb.data = image->data;

    cb.bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
    cb.bi.bmiHeader.biWidth = image->width;
    cb.bi.bmiHeader.biHeight = -image->height;
    cb.bi.bmiHeader.biSizeImage = 0;
    cb.bi.bmiHeader.biXPelsPerMeter = PELS_72DPI;
    cb.bi.bmiHeader.biYPelsPerMeter = PELS_72DPI;
    cb.bi.bmiHeader.biPlanes = 1;
    cb.bi.bmiHeader.biBitCount = 32;
    cb.bi.bmiHeader.biCompression = BI_RGB;
    cb.bi.bmiHeader.biClrUsed = 0;
    cb.bi.bmiHeader.biClrImportant = 0;

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

    _cairo_win32_display_surface_discard_fallback (dst);
err:
    if (&image->base != surface)
	_cairo_surface_release_source_image (surface, image, image_extra);

    return status;
}