mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-common
synced 2026-01-05 06:37:29 +00:00
Support alpha surface sources and destinations
This commit is contained in:
parent
c9a827ffd1
commit
39969cea2f
@ -555,8 +555,28 @@ static void scale_image_rop_from_surface(SpiceCanvas *spice_canvas,
|
||||
src_height, dest_x, dest_y, dest_width, dest_height, scale_mode, rop);
|
||||
}
|
||||
|
||||
static pixman_image_t *canvas_get_as_surface(CairoCanvas *canvas,
|
||||
int with_alpha)
|
||||
{
|
||||
pixman_image_t *target;
|
||||
|
||||
if (with_alpha &&
|
||||
canvas->base.format == SPICE_SURFACE_FMT_32_xRGB) {
|
||||
target = pixman_image_create_bits(PIXMAN_a8r8g8b8,
|
||||
pixman_image_get_width(canvas->image),
|
||||
pixman_image_get_height(canvas->image),
|
||||
pixman_image_get_data(canvas->image),
|
||||
pixman_image_get_stride(canvas->image));
|
||||
} else {
|
||||
target = pixman_image_ref(canvas->image);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
static void __blend_image(SpiceCanvas *spice_canvas,
|
||||
pixman_region32_t *region,
|
||||
int dest_has_alpha,
|
||||
pixman_image_t *src,
|
||||
int src_x, int src_y,
|
||||
int dest_x, int dest_y,
|
||||
@ -564,9 +584,11 @@ static void __blend_image(SpiceCanvas *spice_canvas,
|
||||
int overall_alpha)
|
||||
{
|
||||
CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
|
||||
pixman_image_t *mask;
|
||||
pixman_image_t *mask, *dest;
|
||||
|
||||
pixman_image_set_clip_region32(canvas->image, region);
|
||||
dest = canvas_get_as_surface(canvas, dest_has_alpha);
|
||||
|
||||
pixman_image_set_clip_region32(dest, region);
|
||||
|
||||
mask = NULL;
|
||||
if (overall_alpha != 0xff) {
|
||||
@ -578,7 +600,7 @@ static void __blend_image(SpiceCanvas *spice_canvas,
|
||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
|
||||
|
||||
pixman_image_composite32(PIXMAN_OP_OVER,
|
||||
src, mask, canvas->image,
|
||||
src, mask, dest,
|
||||
src_x, src_y, /* src */
|
||||
0, 0, /* mask */
|
||||
dest_x, dest_y, /* dst */
|
||||
@ -589,36 +611,48 @@ static void __blend_image(SpiceCanvas *spice_canvas,
|
||||
pixman_image_unref(mask);
|
||||
}
|
||||
|
||||
pixman_image_set_clip_region32(canvas->image, NULL);
|
||||
pixman_image_set_clip_region32(dest, NULL);
|
||||
pixman_image_unref(dest);
|
||||
}
|
||||
|
||||
static void blend_image(SpiceCanvas *spice_canvas,
|
||||
pixman_region32_t *region,
|
||||
int dest_has_alpha,
|
||||
pixman_image_t *src,
|
||||
int src_x, int src_y,
|
||||
int dest_x, int dest_y,
|
||||
int width, int height,
|
||||
int overall_alpha)
|
||||
{
|
||||
__blend_image(spice_canvas, region, src, src_x, src_y, dest_x, dest_y, width, height,
|
||||
__blend_image(spice_canvas, region, dest_has_alpha, src, src_x, src_y,
|
||||
dest_x, dest_y, width, height,
|
||||
overall_alpha);
|
||||
}
|
||||
|
||||
static void blend_image_from_surface(SpiceCanvas *spice_canvas,
|
||||
pixman_region32_t *region,
|
||||
int dest_has_alpha,
|
||||
SpiceCanvas *surface_canvas,
|
||||
int src_has_alpha,
|
||||
int src_x, int src_y,
|
||||
int dest_x, int dest_y,
|
||||
int width, int height,
|
||||
int overall_alpha)
|
||||
{
|
||||
CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas;
|
||||
__blend_image(spice_canvas, region, cairo_surface_canvas->image, src_x, src_y, dest_x, dest_y,
|
||||
pixman_image_t *src;
|
||||
|
||||
src = canvas_get_as_surface(cairo_surface_canvas, src_has_alpha);
|
||||
__blend_image(spice_canvas, region, dest_has_alpha,
|
||||
src, src_x, src_y,
|
||||
dest_x, dest_y,
|
||||
width, height, overall_alpha);
|
||||
pixman_image_unref(src);
|
||||
}
|
||||
|
||||
static void __blend_scale_image(SpiceCanvas *spice_canvas,
|
||||
pixman_region32_t *region,
|
||||
int dest_has_alpha,
|
||||
pixman_image_t *src,
|
||||
int src_x, int src_y,
|
||||
int src_width, int src_height,
|
||||
@ -629,13 +663,15 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas,
|
||||
{
|
||||
CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
|
||||
pixman_transform_t transform;
|
||||
pixman_image_t *mask;
|
||||
pixman_image_t *mask, *dest;
|
||||
double sx, sy;
|
||||
|
||||
sx = (double)(src_width) / (dest_width);
|
||||
sy = (double)(src_height) / (dest_height);
|
||||
|
||||
pixman_image_set_clip_region32(canvas->image, region);
|
||||
dest = canvas_get_as_surface(canvas, dest_has_alpha);
|
||||
|
||||
pixman_image_set_clip_region32(dest, region);
|
||||
|
||||
pixman_transform_init_scale(&transform,
|
||||
pixman_double_to_fixed(sx),
|
||||
@ -658,7 +694,7 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas,
|
||||
NULL, 0);
|
||||
|
||||
pixman_image_composite32(PIXMAN_OP_OVER,
|
||||
src, mask, canvas->image,
|
||||
src, mask, dest,
|
||||
ROUND(src_x / sx), ROUND(src_y / sy), /* src */
|
||||
0, 0, /* mask */
|
||||
dest_x, dest_y, /* dst */
|
||||
@ -671,11 +707,13 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas,
|
||||
pixman_image_unref(mask);
|
||||
}
|
||||
|
||||
pixman_image_set_clip_region32(canvas->image, NULL);
|
||||
pixman_image_set_clip_region32(dest, NULL);
|
||||
pixman_image_unref(dest);
|
||||
}
|
||||
|
||||
static void blend_scale_image(SpiceCanvas *spice_canvas,
|
||||
pixman_region32_t *region,
|
||||
int dest_has_alpha,
|
||||
pixman_image_t *src,
|
||||
int src_x, int src_y,
|
||||
int src_width, int src_height,
|
||||
@ -684,13 +722,17 @@ static void blend_scale_image(SpiceCanvas *spice_canvas,
|
||||
int scale_mode,
|
||||
int overall_alpha)
|
||||
{
|
||||
__blend_scale_image(spice_canvas, region, src, src_x, src_y, src_width, src_height, dest_x,
|
||||
dest_y, dest_width, dest_height, scale_mode, overall_alpha);
|
||||
__blend_scale_image(spice_canvas, region, dest_has_alpha,
|
||||
src, src_x, src_y, src_width, src_height,
|
||||
dest_x, dest_y, dest_width, dest_height,
|
||||
scale_mode, overall_alpha);
|
||||
}
|
||||
|
||||
static void blend_scale_image_from_surface(SpiceCanvas *spice_canvas,
|
||||
pixman_region32_t *region,
|
||||
int dest_has_alpha,
|
||||
SpiceCanvas *surface_canvas,
|
||||
int src_has_alpha,
|
||||
int src_x, int src_y,
|
||||
int src_width, int src_height,
|
||||
int dest_x, int dest_y,
|
||||
@ -699,9 +741,13 @@ static void blend_scale_image_from_surface(SpiceCanvas *spice_canvas,
|
||||
int overall_alpha)
|
||||
{
|
||||
CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas;
|
||||
__blend_scale_image(spice_canvas, region, cairo_surface_canvas->image, src_x, src_y, src_width,
|
||||
pixman_image_t *src;
|
||||
|
||||
src = canvas_get_as_surface(cairo_surface_canvas, src_has_alpha);
|
||||
__blend_scale_image(spice_canvas, region, dest_has_alpha, src, src_x, src_y, src_width,
|
||||
src_height, dest_x, dest_y, dest_width, dest_height, scale_mode,
|
||||
overall_alpha);
|
||||
pixman_image_unref(src);
|
||||
}
|
||||
|
||||
static void __colorkey_image(SpiceCanvas *spice_canvas,
|
||||
@ -1116,6 +1162,9 @@ SpiceCanvas *canvas_create(int width, int height, uint32_t format
|
||||
{
|
||||
pixman_image_t *image;
|
||||
|
||||
if (format == SPICE_SURFACE_FMT_32_ARGB) {
|
||||
format = SPICE_SURFACE_FMT_32_xRGB;
|
||||
}
|
||||
image = pixman_image_create_bits(spice_surface_format_to_pixman (format),
|
||||
width, height, NULL, 0);
|
||||
|
||||
@ -1151,6 +1200,10 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
|
||||
{
|
||||
pixman_image_t *image;
|
||||
|
||||
if (format == SPICE_SURFACE_FMT_32_ARGB) {
|
||||
format = SPICE_SURFACE_FMT_32_xRGB;
|
||||
}
|
||||
|
||||
image = pixman_image_create_bits(spice_surface_format_to_pixman (format),
|
||||
width, height, (uint32_t *)data, stride);
|
||||
|
||||
|
||||
@ -414,10 +414,26 @@ static pixman_format_code_t canvas_get_target_format(CanvasBase *canvas,
|
||||
/* Convert to target surface format */
|
||||
format = spice_surface_format_to_pixman (canvas->format);
|
||||
|
||||
if (!source_has_alpha) {
|
||||
if (source_has_alpha) {
|
||||
/* Even though the destination has no alpha, we make the source
|
||||
* remember there are alpha bits instead of throwing away this
|
||||
* information. The results are the same if alpha is not
|
||||
* interpreted, and if need to interpret alpha, don't use
|
||||
* conversion to target format.
|
||||
* This is needed for instance when doing the final
|
||||
* canvas_get_target_format() in canvas_get_image_internal
|
||||
* as otherwise we wouldn't know if the bitmap source
|
||||
* really had alpha.
|
||||
*/
|
||||
if (format == PIXMAN_x8r8g8b8) {
|
||||
format = PIXMAN_a8r8g8b8;
|
||||
}
|
||||
} else { /* !source_has_alpha */
|
||||
/* If the source doesn't have alpha, but the destination has,
|
||||
don't convert to alpha, since that would fill the alpha bytes
|
||||
with 0xff which is not expected if we just use the raw bits */
|
||||
don't convert to alpha, since that would just do an unnecessary
|
||||
copy to fill the alpha bytes with 0xff which is not expected if
|
||||
we just use the raw bits, (and handled implicitly by pixman if
|
||||
we're interpreting data) */
|
||||
if (format == PIXMAN_a8r8g8b8) {
|
||||
format = PIXMAN_x8r8g8b8;
|
||||
}
|
||||
@ -914,7 +930,7 @@ static SpiceCanvas *canvas_get_surface_internal(CanvasBase *canvas, SPICE_ADDRES
|
||||
static SpiceCanvas *canvas_get_surface_mask_internal(CanvasBase *canvas, SPICE_ADDRESS addr)
|
||||
{
|
||||
SpiceImageDescriptor *descriptor;
|
||||
|
||||
|
||||
descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
|
||||
access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
|
||||
|
||||
@ -2222,7 +2238,9 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
|
||||
if (surface_canvas) {
|
||||
if (rect_is_same_size(bbox, &alpha_blend->src_area)) {
|
||||
spice_canvas->ops->blend_image_from_surface(spice_canvas, &dest_region,
|
||||
alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA,
|
||||
surface_canvas,
|
||||
alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_SRC_SURFACE_HAS_ALPHA,
|
||||
alpha_blend->src_area.left,
|
||||
alpha_blend->src_area.top,
|
||||
bbox->left,
|
||||
@ -2232,7 +2250,9 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
|
||||
alpha_blend->alpha);
|
||||
} else {
|
||||
spice_canvas->ops->blend_scale_image_from_surface(spice_canvas, &dest_region,
|
||||
alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA,
|
||||
surface_canvas,
|
||||
alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_SRC_SURFACE_HAS_ALPHA,
|
||||
alpha_blend->src_area.left,
|
||||
alpha_blend->src_area.top,
|
||||
alpha_blend->src_area.right - alpha_blend->src_area.left,
|
||||
@ -2248,6 +2268,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
|
||||
src_image = canvas_get_image(canvas, alpha_blend->src_bitmap, TRUE);
|
||||
if (rect_is_same_size(bbox, &alpha_blend->src_area)) {
|
||||
spice_canvas->ops->blend_image(spice_canvas, &dest_region,
|
||||
alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA,
|
||||
src_image,
|
||||
alpha_blend->src_area.left,
|
||||
alpha_blend->src_area.top,
|
||||
@ -2258,6 +2279,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
|
||||
alpha_blend->alpha);
|
||||
} else {
|
||||
spice_canvas->ops->blend_scale_image(spice_canvas, &dest_region,
|
||||
alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA,
|
||||
src_image,
|
||||
alpha_blend->src_area.left,
|
||||
alpha_blend->src_area.top,
|
||||
@ -2270,7 +2292,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
|
||||
SPICE_IMAGE_SCALE_MODE_NEAREST,
|
||||
alpha_blend->alpha);
|
||||
}
|
||||
|
||||
|
||||
pixman_image_unref(src_image);
|
||||
}
|
||||
|
||||
|
||||
@ -206,6 +206,7 @@ typedef struct {
|
||||
int scale_mode, SpiceROP rop);
|
||||
void (*blend_image)(SpiceCanvas *canvas,
|
||||
pixman_region32_t *region,
|
||||
int dest_has_alpha,
|
||||
pixman_image_t *src_image,
|
||||
int src_x, int src_y,
|
||||
int dest_x, int dest_y,
|
||||
@ -213,13 +214,16 @@ typedef struct {
|
||||
int overall_alpha);
|
||||
void (*blend_image_from_surface)(SpiceCanvas *canvas,
|
||||
pixman_region32_t *region,
|
||||
int dest_has_alpha,
|
||||
SpiceCanvas *src_image,
|
||||
int src_has_alpha,
|
||||
int src_x, int src_y,
|
||||
int dest_x, int dest_y,
|
||||
int width, int height,
|
||||
int overall_alpha);
|
||||
void (*blend_scale_image)(SpiceCanvas *canvas,
|
||||
pixman_region32_t *region,
|
||||
int dest_has_alpha,
|
||||
pixman_image_t *src_image,
|
||||
int src_x, int src_y,
|
||||
int src_width, int src_height,
|
||||
@ -229,7 +233,9 @@ typedef struct {
|
||||
int overall_alpha);
|
||||
void (*blend_scale_image_from_surface)(SpiceCanvas *canvas,
|
||||
pixman_region32_t *region,
|
||||
int dest_has_alpha,
|
||||
SpiceCanvas *src_image,
|
||||
int src_has_alpha,
|
||||
int src_x, int src_y,
|
||||
int src_width, int src_height,
|
||||
int dest_x, int dest_y,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user