summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2010-02-10 11:22:19 +0100
committerAlexander Larsson <alexl@redhat.com>2010-02-23 22:52:05 +0100
commiteff0aa029833a914cce7b047a48d9aa19b825c0a (patch)
tree3d202a887b9c028e720e7efed530f5b0c36eb3df /common
parent0cb87a507c912550b81af14f992900152e507cce (diff)
downloadspice-eff0aa029833a914cce7b047a48d9aa19b825c0a.tar.gz
spice-eff0aa029833a914cce7b047a48d9aa19b825c0a.tar.xz
spice-eff0aa029833a914cce7b047a48d9aa19b825c0a.zip
Convert cairo canvas draw_blend() to using pixman
Diffstat (limited to 'common')
-rw-r--r--common/cairo_canvas.c193
1 files changed, 168 insertions, 25 deletions
diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index f364201a..f871c537 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -1140,6 +1140,39 @@ static void blit_image(CairoCanvas *canvas,
pixman_image_unref(src_image);
}
+static void blit_image_rop(CairoCanvas *canvas,
+ pixman_region32_t *region,
+ SPICE_ADDRESS src_bitmap,
+ int offset_x, int offset_y,
+ SpiceROP rop)
+{
+ pixman_image_t *src_image;
+ pixman_box32_t *rects;
+ int n_rects, i;
+
+ rects = pixman_region32_rectangles(region, &n_rects);
+
+ src_image = canvas_get_image(&canvas->base, src_bitmap);
+ for (i = 0; i < n_rects; i++) {
+ int src_x, src_y, dest_x, dest_y, width, height;
+
+ dest_x = rects[i].x1;
+ dest_y = rects[i].y1;
+ width = rects[i].x2 - rects[i].x1;
+ height = rects[i].y2 - rects[i].y1;
+
+ src_x = rects[i].x1 - offset_x;
+ src_y = rects[i].y1 - offset_y;
+
+ spice_pixman_blit_rop(canvas->image,
+ src_image,
+ src_x, src_y,
+ dest_x, dest_y,
+ width, height, rop);
+ }
+ pixman_image_unref(src_image);
+}
+
static void scale_image(CairoCanvas *canvas,
pixman_region32_t *region,
SPICE_ADDRESS src_bitmap,
@@ -1187,6 +1220,79 @@ static void scale_image(CairoCanvas *canvas,
pixman_image_unref(src);
}
+static void scale_image_rop(CairoCanvas *canvas,
+ pixman_region32_t *region,
+ SPICE_ADDRESS src_bitmap,
+ int src_x, int src_y,
+ int src_width, int src_height,
+ int dest_x, int dest_y,
+ int dest_width, int dest_height,
+ int scale_mode, SpiceROP rop)
+{
+ pixman_transform_t transform;
+ pixman_image_t *src;
+ pixman_image_t *scaled;
+ pixman_box32_t *rects;
+ int n_rects, i;
+ double sx, sy;
+
+ sx = (double)(src_width) / (dest_width);
+ sy = (double)(src_height) / (dest_height);
+
+ src = canvas_get_image(&canvas->base, src_bitmap);
+
+ scaled = pixman_image_create_bits(PIXMAN_x8r8g8b8,
+ dest_width,
+ dest_height,
+ NULL, 0);
+
+ pixman_region32_translate(region, -dest_x, -dest_y);
+ pixman_image_set_clip_region32(scaled, region);
+
+ pixman_transform_init_scale(&transform,
+ pixman_double_to_fixed(sx),
+ pixman_double_to_fixed(sy));
+
+ pixman_image_set_transform(src, &transform);
+ pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
+ ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
+ scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
+ pixman_image_set_filter(src,
+ (scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
+ PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
+ NULL, 0);
+
+ pixman_image_composite32(PIXMAN_OP_SRC,
+ src, NULL, scaled,
+ ROUND(src_x / sx), ROUND(src_y / sy), /* src */
+ 0, 0, /* mask */
+ 0, 0, /* dst */
+ dest_width,
+ dest_height);
+
+ pixman_transform_init_identity(&transform);
+ pixman_image_set_transform(src, &transform);
+
+ /* Translate back */
+ pixman_region32_translate(region, dest_x, dest_y);
+
+ rects = pixman_region32_rectangles(region, &n_rects);
+
+ for (i = 0; i < n_rects; i++) {
+ spice_pixman_blit_rop(canvas->image,
+ scaled,
+ rects[i].x1 - dest_x,
+ rects[i].y1 - dest_y,
+ rects[i].x1, rects[i].y1,
+ rects[i].x2 - rects[i].x1,
+ rects[i].y2 - rects[i].y1,
+ rop);
+ }
+
+ pixman_image_unref(scaled);
+ pixman_image_unref(src);
+}
+
static void draw_brush(CairoCanvas *canvas,
pixman_region32_t *region,
SpiceBrush *brush,
@@ -1594,39 +1700,76 @@ void canvas_draw_opaque(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, S
pixman_region32_fini(&dest_region);
}
-
void canvas_draw_blend(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend)
{
- cairo_pattern_t *pattern;
- DrawMaskData mask_data;
+ pixman_region32_t dest_region;
+ SpiceROP rop;
+
+ pixman_region32_init_rect(&dest_region,
+ bbox->left, bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top);
- mask_data.cairo = canvas->cairo;
+ canvas_clip_pixman(canvas, &dest_region, clip);
+ canvas_mask_pixman(canvas, &dest_region, &blend->mask,
+ bbox->left, bbox->top);
- cairo_save(mask_data.cairo);
- canvas_clip(canvas, clip);
+ rop = ropd_descriptor_to_rop(blend->rop_decriptor,
+ ROP_INPUT_SRC,
+ ROP_INPUT_DEST);
- pattern = canvas_src_image_to_pat(canvas, blend->src_bitmap, &blend->src_area, bbox,
- blend->rop_decriptor & SPICE_ROPD_INVERS_SRC, blend->scale_mode);
+ if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) {
+ canvas_touch_image(&canvas->base, blend->src_bitmap);
+ pixman_region32_fini(&dest_region);
+ return;
+ }
- if ((mask_data.mask = canvas_get_mask_pattern(canvas, &blend->mask, bbox->left, bbox->top))) {
- cairo_rectangle(mask_data.cairo,
- bbox->left,
- bbox->top,
- bbox->right - bbox->left,
- bbox->bottom - bbox->top);
- cairo_clip(mask_data.cairo);
- canvas_draw_with_pattern(canvas, pattern, blend->rop_decriptor, __draw_mask, &mask_data);
- cairo_pattern_destroy(mask_data.mask);
+ if (rect_is_same_size(bbox, &blend->src_area)) {
+ if (rop == SPICE_ROP_COPY)
+ blit_image(canvas, &dest_region,
+ blend->src_bitmap,
+ bbox->left - blend->src_area.left,
+ bbox->top - blend->src_area.top);
+ else
+ blit_image_rop(canvas, &dest_region,
+ blend->src_bitmap,
+ bbox->left - blend->src_area.left,
+ bbox->top - blend->src_area.top,
+ rop);
} else {
- cairo_rectangle(mask_data.cairo, bbox->left, bbox->top, bbox->right - bbox->left,
- bbox->bottom - bbox->top);
- canvas_draw_with_pattern(canvas, pattern, blend->rop_decriptor,
- (DrawMethod)cairo_fill_preserve,
- mask_data.cairo);
- cairo_new_path(mask_data.cairo);
+ double sx, sy;
+
+ sx = (double)(blend->src_area.right - blend->src_area.left) / (bbox->right - bbox->left);
+ sy = (double)(blend->src_area.bottom - blend->src_area.top) / (bbox->bottom - bbox->top);
+
+ if (rop == SPICE_ROP_COPY) {
+ scale_image(canvas, &dest_region,
+ blend->src_bitmap,
+ blend->src_area.left,
+ blend->src_area.top,
+ blend->src_area.right - blend->src_area.left,
+ blend->src_area.bottom - blend->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ blend->scale_mode);
+ } else {
+ scale_image_rop(canvas, &dest_region,
+ blend->src_bitmap,
+ blend->src_area.left,
+ blend->src_area.top,
+ blend->src_area.right - blend->src_area.left,
+ blend->src_area.bottom - blend->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ blend->scale_mode, rop);
+ }
}
- cairo_pattern_destroy(pattern);
- cairo_restore(mask_data.cairo);
+
+ pixman_region32_fini(&dest_region);
}
static inline void canvas_fill_common(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip,