summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2010-04-23 15:15:40 +0200
committerAlexander Larsson <alexl@redhat.com>2010-04-23 16:41:47 +0200
commit810caf0e779bf280370221018bee6a0d4d63160b (patch)
tree5c32bc4d8917d1c13847a65f9f8345dea90ad874 /common
parent1a590c50c03c5d752af8d8c3b3c0ff28d35ee147 (diff)
downloadspice-810caf0e779bf280370221018bee6a0d4d63160b.tar.gz
spice-810caf0e779bf280370221018bee6a0d4d63160b.tar.xz
spice-810caf0e779bf280370221018bee6a0d4d63160b.zip
Support alpha surface sources and destinations
Diffstat (limited to 'common')
-rw-r--r--common/cairo_canvas.c79
-rw-r--r--common/canvas_base.c32
-rw-r--r--common/canvas_base.h6
3 files changed, 99 insertions, 18 deletions
diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index 931fd36b..a324c446 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -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);
diff --git a/common/canvas_base.c b/common/canvas_base.c
index e1201af7..c305f4df 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -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);
}
diff --git a/common/canvas_base.h b/common/canvas_base.h
index f2b0d5bf..f78b0b8d 100644
--- a/common/canvas_base.h
+++ b/common/canvas_base.h
@@ -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,