diff options
author | Alexander Larsson <alexl@redhat.com> | 2010-03-04 14:23:08 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2010-03-08 19:45:28 +0100 |
commit | e00bce8e25d3aaebd83a2f9bc4191bad6aff329d (patch) | |
tree | eff593d7e9811b66ce6e6d1fdc5a8064246dc330 /common | |
parent | 18606d99eaf11dbceb79dc24f0a41e85345db300 (diff) | |
download | spice-e00bce8e25d3aaebd83a2f9bc4191bad6aff329d.tar.gz spice-e00bce8e25d3aaebd83a2f9bc4191bad6aff329d.tar.xz spice-e00bce8e25d3aaebd83a2f9bc4191bad6aff329d.zip |
Move most of the shared draw_xyz() methods from CairoCanvas to CanvasBase
This adds a set of virtual methods for low-level operations. A subclass
can choose to implement those and let the default CanvasBase implementations
handle the highlevel stuff.
Diffstat (limited to 'common')
-rw-r--r-- | common/cairo_canvas.c | 1063 | ||||
-rw-r--r-- | common/canvas_base.c | 824 | ||||
-rw-r--r-- | common/canvas_base.h | 84 |
3 files changed, 1039 insertions, 932 deletions
diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c index 2c5b0d71..c5ef3b2d 100644 --- a/common/cairo_canvas.c +++ b/common/cairo_canvas.c @@ -36,304 +36,6 @@ struct CairoCanvas { pixman_image_t *image; }; -typedef enum { - ROP_INPUT_SRC, - ROP_INPUT_BRUSH, - ROP_INPUT_DEST -} ROPInput; - -SpiceROP ropd_descriptor_to_rop(int desc, - ROPInput src_input, - ROPInput dest_input) -{ - int old; - int invert_masks[] = { - SPICE_ROPD_INVERS_SRC, - SPICE_ROPD_INVERS_BRUSH, - SPICE_ROPD_INVERS_DEST - }; - - old = desc; - - desc &= ~(SPICE_ROPD_INVERS_SRC | SPICE_ROPD_INVERS_DEST); - if (old & invert_masks[src_input]) { - desc |= SPICE_ROPD_INVERS_SRC; - } - - if (old & invert_masks[dest_input]) { - desc |= SPICE_ROPD_INVERS_DEST; - } - - if (desc & SPICE_ROPD_OP_PUT) { - if (desc & SPICE_ROPD_INVERS_SRC) { - if (desc & SPICE_ROPD_INVERS_RES) { - return SPICE_ROP_COPY; - } - return SPICE_ROP_COPY_INVERTED; - } else { - if (desc & SPICE_ROPD_INVERS_RES) { - return SPICE_ROP_COPY_INVERTED; - } - return SPICE_ROP_COPY; - } - } else if (desc & SPICE_ROPD_OP_OR) { - - if (desc & SPICE_ROPD_INVERS_RES) { - if (desc & SPICE_ROPD_INVERS_SRC) { - if (desc & SPICE_ROPD_INVERS_DEST) { - /* !(!src or !dest) == src and dest*/ - return SPICE_ROP_AND; - } else { - /* ! (!src or dest) = src and !dest*/ - return SPICE_ROP_AND_REVERSE; - } - } else { - if (desc & SPICE_ROPD_INVERS_DEST) { - /* !(src or !dest) == !src and dest */ - return SPICE_ROP_AND_INVERTED; - } else { - /* !(src or dest) */ - return SPICE_ROP_NOR; - } - } - } else { - if (desc & SPICE_ROPD_INVERS_SRC) { - if (desc & SPICE_ROPD_INVERS_DEST) { - /* !src or !dest == !(src and dest)*/ - return SPICE_ROP_NAND; - } else { - /* !src or dest */ - return SPICE_ROP_OR_INVERTED; - } - } else { - if (desc & SPICE_ROPD_INVERS_DEST) { - /* src or !dest */ - return SPICE_ROP_OR_REVERSE; - } else { - /* src or dest */ - return SPICE_ROP_OR; - } - } - } - - } else if (desc & SPICE_ROPD_OP_AND) { - - if (desc & SPICE_ROPD_INVERS_RES) { - if (desc & SPICE_ROPD_INVERS_SRC) { - if (desc & SPICE_ROPD_INVERS_DEST) { - /* !(!src and !dest) == src or dest*/ - return SPICE_ROP_OR; - } else { - /* ! (!src and dest) = src or !dest*/ - return SPICE_ROP_OR_REVERSE; - } - } else { - if (desc & SPICE_ROPD_INVERS_DEST) { - /* !(src and !dest) == !src or dest */ - return SPICE_ROP_OR_INVERTED; - } else { - /* !(src and dest) */ - return SPICE_ROP_NAND; - } - } - } else { - if (desc & SPICE_ROPD_INVERS_SRC) { - if (desc & SPICE_ROPD_INVERS_DEST) { - /* !src and !dest == !(src or dest)*/ - return SPICE_ROP_NOR; - } else { - /* !src and dest */ - return SPICE_ROP_AND_INVERTED; - } - } else { - if (desc & SPICE_ROPD_INVERS_DEST) { - /* src and !dest */ - return SPICE_ROP_AND_REVERSE; - } else { - /* src and dest */ - return SPICE_ROP_AND; - } - } - } - - } else if (desc & SPICE_ROPD_OP_XOR) { - - if (desc & SPICE_ROPD_INVERS_RES) { - if (desc & SPICE_ROPD_INVERS_SRC) { - if (desc & SPICE_ROPD_INVERS_DEST) { - /* !(!src xor !dest) == !src xor dest */ - return SPICE_ROP_EQUIV; - } else { - /* ! (!src xor dest) = src xor dest*/ - return SPICE_ROP_XOR; - } - } else { - if (desc & SPICE_ROPD_INVERS_DEST) { - /* !(src xor !dest) == src xor dest */ - return SPICE_ROP_XOR; - } else { - /* !(src xor dest) */ - return SPICE_ROP_EQUIV; - } - } - } else { - if (desc & SPICE_ROPD_INVERS_SRC) { - if (desc & SPICE_ROPD_INVERS_DEST) { - /* !src xor !dest == src xor dest */ - return SPICE_ROP_XOR; - } else { - /* !src xor dest */ - return SPICE_ROP_EQUIV; - } - } else { - if (desc & SPICE_ROPD_INVERS_DEST) { - /* src xor !dest */ - return SPICE_ROP_EQUIV; - } else { - /* src xor dest */ - return SPICE_ROP_XOR; - } - } - } - - } else if (desc & SPICE_ROPD_OP_BLACKNESS) { - return SPICE_ROP_CLEAR; - } else if (desc & SPICE_ROPD_OP_WHITENESS) { - return SPICE_ROP_SET; - } else if (desc & SPICE_ROPD_OP_INVERS) { - return SPICE_ROP_INVERT; - } - return SPICE_ROP_COPY; -} - -static void canvas_clip_pixman(CairoCanvas *canvas, - pixman_region32_t *dest_region, - SpiceClip *clip) -{ - pixman_region32_intersect(dest_region, dest_region, &canvas->base.canvas_region); - - switch (clip->type) { - case SPICE_CLIP_TYPE_NONE: - break; - case SPICE_CLIP_TYPE_RECTS: { - uint32_t *n = (uint32_t *)SPICE_GET_ADDRESS(clip->data); - access_test(&canvas->base, n, sizeof(uint32_t)); - - SpiceRect *now = (SpiceRect *)(n + 1); - access_test(&canvas->base, now, (unsigned long)(now + *n) - (unsigned long)now); - - pixman_region32_t clip; - - if (spice_pixman_region32_init_rects(&clip, now, *n)) { - pixman_region32_intersect(dest_region, dest_region, &clip); - pixman_region32_fini(&clip); - } - - break; - } - case SPICE_CLIP_TYPE_PATH: - CANVAS_ERROR("clip paths not supported anymore"); - break; - default: - CANVAS_ERROR("invalid clip type"); - } -} - -static void canvas_mask_pixman(CairoCanvas *canvas, - pixman_region32_t *dest_region, - SpiceQMask *mask, int x, int y) -{ - pixman_image_t *image, *subimage; - int needs_invert; - pixman_region32_t mask_region; - uint32_t *mask_data; - int mask_x, mask_y; - int mask_width, mask_height, mask_stride; - pixman_box32_t extents; - - needs_invert = FALSE; - image = canvas_get_mask(&canvas->base, - mask, - &needs_invert); - - if (image == NULL) { - return; /* no mask */ - } - - mask_data = pixman_image_get_data(image); - mask_width = pixman_image_get_width(image); - mask_height = pixman_image_get_height(image); - mask_stride = pixman_image_get_stride(image); - - mask_x = mask->pos.x; - mask_y = mask->pos.y; - - /* We need to subset the area of the mask that we turn into a region, - because a cached mask may be much larger than what is used for - the clip operation. */ - extents = *pixman_region32_extents(dest_region); - - /* convert from destination pixels to mask pixels */ - extents.x1 -= x - mask_x; - extents.y1 -= y - mask_y; - extents.x2 -= x - mask_x; - extents.y2 -= y - mask_y; - - /* clip to mask size */ - if (extents.x1 < 0) { - extents.x1 = 0; - } - if (extents.x2 >= mask_width) { - extents.x2 = mask_width; - } - if (extents.x2 < extents.x1) { - extents.x2 = extents.x1; - } - if (extents.y1 < 0) { - extents.y1 = 0; - } - if (extents.y2 >= mask_height) { - extents.y2 = mask_height; - } - if (extents.y2 < extents.y1) { - extents.y2 = extents.y1; - } - - /* round down X to even 32 pixels (i.e. uint32_t) */ - extents.x1 = extents.x1 & ~(0x1f); - - mask_data = (uint32_t *)((uint8_t *)mask_data + mask_stride * extents.y1 + extents.x1 / 32); - mask_x -= extents.x1; - mask_y -= extents.y1; - mask_width = extents.x2 - extents.x1; - mask_height = extents.y2 - extents.y1; - - subimage = pixman_image_create_bits(PIXMAN_a1, mask_width, mask_height, - mask_data, mask_stride); - pixman_region32_init_from_image(&mask_region, - subimage); - pixman_image_unref(subimage); - - if (needs_invert) { - pixman_box32_t rect; - - rect.x1 = rect.y1 = 0; - rect.x2 = mask_width; - rect.y2 = mask_height; - - pixman_region32_inverse(&mask_region, &mask_region, &rect); - } - - pixman_region32_translate(&mask_region, - -mask_x + x, -mask_y + y); - - pixman_region32_intersect(dest_region, dest_region, &mask_region); - pixman_region32_fini(&mask_region); - - pixman_image_unref(image); -} - - static pixman_image_t* canvas_surface_from_self(CairoCanvas *canvas, int x, int y, int32_t width, int32_t heigth) @@ -401,10 +103,11 @@ static pixman_image_t *canvas_get_pixman_brush(CairoCanvas *canvas, } -static void copy_region(CairoCanvas *canvas, +static void copy_region(SpiceCanvas *spice_canvas, pixman_region32_t *dest_region, int dx, int dy) { + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_box32_t *dest_rects; int n_rects; int i, j, end_line; @@ -470,17 +173,33 @@ static void copy_region(CairoCanvas *canvas, } } -static void fill_solid_rects(CairoCanvas *canvas, - pixman_region32_t *region, +static void fill_solid_spans(SpiceCanvas *spice_canvas, + SpicePoint *points, + int *widths, + int n_spans, uint32_t color) { - pixman_box32_t *rects; - int n_rects; + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; int i; - rects = pixman_region32_rectangles(region, &n_rects); + for (i = 0; i < n_spans; i++) { + spice_pixman_fill_rect(canvas->image, + points[i].x, points[i].y, + widths[i], + 1, + color); + } +} - for (i = 0; i < n_rects; i++) { +static void fill_solid_rects(SpiceCanvas *spice_canvas, + pixman_box32_t *rects, + int n_rects, + uint32_t color) +{ + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; + int i; + + for (i = 0; i < n_rects; i++) { spice_pixman_fill_rect(canvas->image, rects[i].x1, rects[i].y1, rects[i].x2 - rects[i].x1, @@ -489,18 +208,16 @@ static void fill_solid_rects(CairoCanvas *canvas, } } -static void fill_solid_rects_rop(CairoCanvas *canvas, - pixman_region32_t *region, +static void fill_solid_rects_rop(SpiceCanvas *spice_canvas, + pixman_box32_t *rects, + int n_rects, uint32_t color, SpiceROP rop) { - pixman_box32_t *rects; - int n_rects; + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; int i; - rects = pixman_region32_rectangles(region, &n_rects); - - for (i = 0; i < n_rects; i++) { + for (i = 0; i < n_rects; i++) { spice_pixman_fill_rect_rop(canvas->image, rects[i].x1, rects[i].y1, rects[i].x2 - rects[i].x1, @@ -509,51 +226,35 @@ static void fill_solid_rects_rop(CairoCanvas *canvas, } } -static void fill_tiled_rects(CairoCanvas *canvas, - pixman_region32_t *region, - SpicePattern *pattern) +static void fill_tiled_rects(SpiceCanvas *spice_canvas, + pixman_box32_t *rects, + int n_rects, + pixman_image_t *tile, + int offset_x, int offset_y) { - pixman_image_t *tile; - int offset_x, offset_y; - pixman_box32_t *rects; - int n_rects; + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; int i; - rects = pixman_region32_rectangles(region, &n_rects); - - tile = canvas_get_image(&canvas->base, pattern->pat); - offset_x = pattern->pos.x; - offset_y = pattern->pos.y; - - for (i = 0; i < n_rects; i++) { + for (i = 0; i < n_rects; i++) { spice_pixman_tile_rect(canvas->image, rects[i].x1, rects[i].y1, rects[i].x2 - rects[i].x1, rects[i].y2 - rects[i].y1, tile, offset_x, offset_y); } - - pixman_image_unref(tile); } -static void fill_tiled_rects_rop(CairoCanvas *canvas, - pixman_region32_t *region, - SpicePattern *pattern, +static void fill_tiled_rects_rop(SpiceCanvas *spice_canvas, + pixman_box32_t *rects, + int n_rects, + pixman_image_t *tile, + int offset_x, int offset_y, SpiceROP rop) { - pixman_image_t *tile; - int offset_x, offset_y; - pixman_box32_t *rects; - int n_rects; + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; int i; - rects = pixman_region32_rectangles(region, &n_rects); - - tile = canvas_get_image(&canvas->base, pattern->pat); - offset_x = pattern->pos.x; - offset_y = pattern->pos.y; - - for (i = 0; i < n_rects; i++) { + for (i = 0; i < n_rects; i++) { spice_pixman_tile_rect_rop(canvas->image, rects[i].x1, rects[i].y1, rects[i].x2 - rects[i].x1, @@ -561,16 +262,14 @@ static void fill_tiled_rects_rop(CairoCanvas *canvas, tile, offset_x, offset_y, rop); } - - pixman_image_unref(tile); } - -static void blit_with_region(CairoCanvas *canvas, - pixman_region32_t *region, - pixman_image_t *src_image, - int offset_x, int offset_y) +static void blit_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + int offset_x, int offset_y) { + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_box32_t *rects; int n_rects, i; @@ -595,32 +294,18 @@ static void blit_with_region(CairoCanvas *canvas, } } -static void blit_image(CairoCanvas *canvas, - pixman_region32_t *region, - SPICE_ADDRESS src_bitmap, - int offset_x, int offset_y) -{ - pixman_image_t *src_image; - - src_image = canvas_get_image(&canvas->base, src_bitmap); - blit_with_region(canvas, region, src_image, - offset_x, offset_y); - pixman_image_unref(src_image); -} - -static void blit_image_rop(CairoCanvas *canvas, +static void blit_image_rop(SpiceCanvas *spice_canvas, pixman_region32_t *region, - SPICE_ADDRESS src_bitmap, + pixman_image_t *src_image, int offset_x, int offset_y, SpiceROP rop) { - pixman_image_t *src_image; + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; 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; @@ -638,27 +323,24 @@ static void blit_image_rop(CairoCanvas *canvas, dest_x, dest_y, width, height, rop); } - pixman_image_unref(src_image); } -static void scale_image(CairoCanvas *canvas, +static void scale_image(SpiceCanvas *spice_canvas, pixman_region32_t *region, - SPICE_ADDRESS src_bitmap, + pixman_image_t *src, 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) { + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_transform_t transform; - pixman_image_t *src; double sx, sy; sx = (double)(src_width) / (dest_width); sy = (double)(src_height) / (dest_height); - src = canvas_get_image(&canvas->base, src_bitmap); - pixman_image_set_clip_region32(canvas->image, region); pixman_transform_init_scale(&transform, @@ -685,20 +367,19 @@ static void scale_image(CairoCanvas *canvas, pixman_image_set_transform(src, &transform); pixman_image_set_clip_region32(canvas->image, NULL); - pixman_image_unref(src); } -static void scale_image_rop(CairoCanvas *canvas, +static void scale_image_rop(SpiceCanvas *spice_canvas, pixman_region32_t *region, - SPICE_ADDRESS src_bitmap, + pixman_image_t *src, 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) { + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_transform_t transform; - pixman_image_t *src; pixman_image_t *scaled; pixman_box32_t *rects; int n_rects, i; @@ -707,8 +388,6 @@ static void scale_image_rop(CairoCanvas *canvas, 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, @@ -758,20 +437,18 @@ static void scale_image_rop(CairoCanvas *canvas, } pixman_image_unref(scaled); - pixman_image_unref(src); } -static void blend_image(CairoCanvas *canvas, +static void blend_image(SpiceCanvas *spice_canvas, pixman_region32_t *region, - SPICE_ADDRESS src_bitmap, + pixman_image_t *src, int src_x, int src_y, int dest_x, int dest_y, int width, int height, int overall_alpha) { - pixman_image_t *src, *mask; - - src = canvas_get_image(&canvas->base, src_bitmap); + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; + pixman_image_t *mask; pixman_image_set_clip_region32(canvas->image, region); @@ -795,14 +472,13 @@ static void blend_image(CairoCanvas *canvas, if (mask) { pixman_image_unref(mask); } - pixman_image_unref(src); pixman_image_set_clip_region32(canvas->image, NULL); } -static void blend_scale_image(CairoCanvas *canvas, +static void blend_scale_image(SpiceCanvas *spice_canvas, pixman_region32_t *region, - SPICE_ADDRESS src_bitmap, + pixman_image_t *src, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y, @@ -810,15 +486,14 @@ static void blend_scale_image(CairoCanvas *canvas, int scale_mode, int overall_alpha) { + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_transform_t transform; - pixman_image_t *src, *mask; + pixman_image_t *mask; double sx, sy; sx = (double)(src_width) / (dest_width); sy = (double)(src_height) / (dest_height); - src = canvas_get_image(&canvas->base, src_bitmap); - pixman_image_set_clip_region32(canvas->image, region); pixman_transform_init_scale(&transform, @@ -854,24 +529,22 @@ static void blend_scale_image(CairoCanvas *canvas, if (mask) { pixman_image_unref(mask); } - pixman_image_unref(src); pixman_image_set_clip_region32(canvas->image, NULL); } -static void colorkey_image(CairoCanvas *canvas, +static void colorkey_image(SpiceCanvas *spice_canvas, pixman_region32_t *region, - SPICE_ADDRESS src_bitmap, + pixman_image_t *src_image, int offset_x, int offset_y, uint32_t transparent_color) { - pixman_image_t *src_image; + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; 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; @@ -890,20 +563,19 @@ static void colorkey_image(CairoCanvas *canvas, width, height, transparent_color); } - pixman_image_unref(src_image); } -static void colorkey_scale_image(CairoCanvas *canvas, +static void colorkey_scale_image(SpiceCanvas *spice_canvas, pixman_region32_t *region, - SPICE_ADDRESS src_bitmap, + pixman_image_t *src, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y, int dest_width, int dest_height, uint32_t transparent_color) { + CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_transform_t transform; - pixman_image_t *src; pixman_image_t *scaled; pixman_box32_t *rects; int n_rects, i; @@ -912,8 +584,6 @@ static void colorkey_scale_image(CairoCanvas *canvas, 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, @@ -960,60 +630,16 @@ static void colorkey_scale_image(CairoCanvas *canvas, } pixman_image_unref(scaled); - pixman_image_unref(src); } - -static void draw_brush(CairoCanvas *canvas, - pixman_region32_t *region, - SpiceBrush *brush, - SpiceROP rop) -{ - uint32_t color; - SpicePattern *pattern; - - switch (brush->type) { - case SPICE_BRUSH_TYPE_SOLID: - color = brush->u.color; - if (rop == SPICE_ROP_COPY) { - fill_solid_rects(canvas, region, color); - } else { - fill_solid_rects_rop(canvas, region, color, rop); - } - break; - case SPICE_BRUSH_TYPE_PATTERN: - pattern = &brush->u.pattern; - - if (rop == SPICE_ROP_COPY) { - fill_tiled_rects(canvas, region, pattern); - } else { - fill_tiled_rects_rop(canvas, region, pattern, rop); - } - break; - case SPICE_BRUSH_TYPE_NONE: - /* Still need to do *something* here, because rop could be e.g invert dest */ - fill_solid_rects_rop(canvas, region, 0, rop); - break; - default: - CANVAS_ERROR("invalid brush type"); - } -} - -/* If we're exiting early we may still have to load an image in case - it has to be cached or something */ -static void touch_brush(CairoCanvas *canvas, SpiceBrush *brush) -{ - SpicePattern *pattern; - if (brush->type == SPICE_BRUSH_TYPE_PATTERN) { - pattern = &brush->u.pattern; - canvas_touch_image(&canvas->base, pattern->pat); - } -} - -static void canvas_draw_fill(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceFill *fill) +static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3) { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_region32_t dest_region; - SpiceROP rop; + pixman_image_t *d; + pixman_image_t *s; + SpicePoint src_pos; + int width; + int heigth; pixman_region32_init_rect(&dest_region, bbox->left, bbox->top, @@ -1021,91 +647,51 @@ static void canvas_draw_fill(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl bbox->bottom - bbox->top); - canvas_clip_pixman(canvas, &dest_region, clip); - canvas_mask_pixman(canvas, &dest_region, &fill->mask, + canvas_clip_pixman(&canvas->base, &dest_region, clip); + canvas_mask_pixman(&canvas->base, &dest_region, &rop3->mask, bbox->left, bbox->top); - rop = ropd_descriptor_to_rop(fill->rop_decriptor, - ROP_INPUT_BRUSH, - ROP_INPUT_DEST); - - if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) { - touch_brush(canvas, &fill->brush); - pixman_region32_fini(&dest_region); - return; - } - - draw_brush(canvas, &dest_region, &fill->brush, rop); - - pixman_region32_fini(&dest_region); -} - -static void canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy) -{ - CairoCanvas *canvas = (CairoCanvas *)spice_canvas; - 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); - - canvas_clip_pixman(canvas, &dest_region, clip); - canvas_mask_pixman(canvas, &dest_region, ©->mask, - bbox->left, bbox->top); + width = bbox->right - bbox->left; + heigth = bbox->bottom - bbox->top; - rop = ropd_descriptor_to_rop(copy->rop_decriptor, - ROP_INPUT_SRC, - ROP_INPUT_DEST); + d = canvas_surface_from_self(canvas, bbox->left, bbox->top, width, heigth); + s = canvas_get_image(&canvas->base, rop3->src_bitmap); - if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) { - canvas_touch_image(&canvas->base, copy->src_bitmap); - pixman_region32_fini(&dest_region); - return; + if (!rect_is_same_size(bbox, &rop3->src_area)) { + pixman_image_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, width, heigth, + rop3->scale_mode); + pixman_image_unref(s); + s = scaled_s; + src_pos.x = 0; + src_pos.y = 0; + } else { + src_pos.x = rop3->src_area.left; + src_pos.y = rop3->src_area.top; } + if (pixman_image_get_width(s) - src_pos.x < width || + pixman_image_get_height(s) - src_pos.y < heigth) { + CANVAS_ERROR("bad src bitmap size"); + } + if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) { + pixman_image_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat); + SpicePoint pat_pos; - if (rect_is_same_size(bbox, ©->src_area)) { - if (rop == SPICE_ROP_COPY) { - blit_image(canvas, &dest_region, - copy->src_bitmap, - bbox->left - copy->src_area.left, - bbox->top - copy->src_area.top); - } else { - blit_image_rop(canvas, &dest_region, - copy->src_bitmap, - bbox->left - copy->src_area.left, - bbox->top - copy->src_area.top, - rop); - } + pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % pixman_image_get_width(p); + pat_pos.y = (bbox->top - rop3->brush.u.pattern.pos.y) % pixman_image_get_height(p); + do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos); + pixman_image_unref(p); } else { - if (rop == SPICE_ROP_COPY) { - scale_image(canvas, &dest_region, - copy->src_bitmap, - copy->src_area.left, - copy->src_area.top, - copy->src_area.right - copy->src_area.left, - copy->src_area.bottom - copy->src_area.top, - bbox->left, - bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top, - copy->scale_mode); - } else { - scale_image_rop(canvas, &dest_region, - copy->src_bitmap, - copy->src_area.left, - copy->src_area.top, - copy->src_area.right - copy->src_area.left, - copy->src_area.bottom - copy->src_area.top, - bbox->left, - bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top, - copy->scale_mode, - rop); - } + uint32_t color = (canvas->base.color_shift) == 8 ? rop3->brush.u.color : + canvas_16bpp_to_32bpp(rop3->brush.u.color); + do_rop3_with_color(rop3->rop3, d, s, &src_pos, color); } + pixman_image_unref(s); + + blit_image(spice_canvas, &dest_region, d, + bbox->left, + bbox->top); + + pixman_image_unref(d); pixman_region32_fini(&dest_region); } @@ -1168,390 +754,6 @@ static void canvas_put_image(SpiceCanvas *spice_canvas, pixman_image_unref(src); } -static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent) -{ - CairoCanvas *canvas = (CairoCanvas *)spice_canvas; - pixman_region32_t dest_region; - - pixman_region32_init_rect(&dest_region, - bbox->left, bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top); - - canvas_clip_pixman(canvas, &dest_region, clip); - - if (pixman_region32_n_rects (&dest_region) == 0) { - canvas_touch_image(&canvas->base, transparent->src_bitmap); - pixman_region32_fini(&dest_region); - return; - } - - if (rect_is_same_size(bbox, &transparent->src_area)) { - colorkey_image(canvas, &dest_region, - transparent->src_bitmap, - bbox->left - transparent->src_area.left, - bbox->top - transparent->src_area.top, - transparent->true_color); - } else { - colorkey_scale_image(canvas, &dest_region, - transparent->src_bitmap, - transparent->src_area.left, - transparent->src_area.top, - transparent->src_area.right - transparent->src_area.left, - transparent->src_area.bottom - transparent->src_area.top, - bbox->left, - bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top, - transparent->true_color); - } - - pixman_region32_fini(&dest_region); -} - -static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlnd* alpha_blend) -{ - CairoCanvas *canvas = (CairoCanvas *)spice_canvas; - pixman_region32_t dest_region; - - pixman_region32_init_rect(&dest_region, - bbox->left, bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top); - - canvas_clip_pixman(canvas, &dest_region, clip); - - if (alpha_blend->alpha == 0 || - pixman_region32_n_rects(&dest_region) == 0) { - canvas_touch_image(&canvas->base, alpha_blend->src_bitmap); - pixman_region32_fini(&dest_region); - return; - } - - if (rect_is_same_size(bbox, &alpha_blend->src_area)) { - blend_image(canvas, &dest_region, - alpha_blend->src_bitmap, - alpha_blend->src_area.left, - alpha_blend->src_area.top, - bbox->left, - bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top, - alpha_blend->alpha); - } else { - blend_scale_image(canvas, &dest_region, - alpha_blend->src_bitmap, - alpha_blend->src_area.left, - alpha_blend->src_area.top, - alpha_blend->src_area.right - alpha_blend->src_area.left, - alpha_blend->src_area.bottom - alpha_blend->src_area.top, - bbox->left, - bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top, - SPICE_IMAGE_SCALE_MODE_INTERPOLATE, - alpha_blend->alpha); - } - - pixman_region32_fini(&dest_region); -} - -static void canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque) -{ - CairoCanvas *canvas = (CairoCanvas *)spice_canvas; - 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); - - canvas_clip_pixman(canvas, &dest_region, clip); - canvas_mask_pixman(canvas, &dest_region, &opaque->mask, - bbox->left, bbox->top); - - rop = ropd_descriptor_to_rop(opaque->rop_decriptor, - ROP_INPUT_BRUSH, - ROP_INPUT_SRC); - - if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) { - canvas_touch_image(&canvas->base, opaque->src_bitmap); - touch_brush(canvas, &opaque->brush); - pixman_region32_fini(&dest_region); - return; - } - - if (rect_is_same_size(bbox, &opaque->src_area)) { - blit_image(canvas, &dest_region, - opaque->src_bitmap, - bbox->left - opaque->src_area.left, - bbox->top - opaque->src_area.top); - } else { - scale_image(canvas, &dest_region, - opaque->src_bitmap, - opaque->src_area.left, - opaque->src_area.top, - opaque->src_area.right - opaque->src_area.left, - opaque->src_area.bottom - opaque->src_area.top, - bbox->left, - bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top, - opaque->scale_mode); - } - - draw_brush(canvas, &dest_region, &opaque->brush, rop); - - pixman_region32_fini(&dest_region); -} - -static void canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend) -{ - CairoCanvas *canvas = (CairoCanvas *)spice_canvas; - 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); - - canvas_clip_pixman(canvas, &dest_region, clip); - canvas_mask_pixman(canvas, &dest_region, &blend->mask, - bbox->left, bbox->top); - - rop = ropd_descriptor_to_rop(blend->rop_decriptor, - ROP_INPUT_SRC, - ROP_INPUT_DEST); - - 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 (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 { - 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); - } - } - - pixman_region32_fini(&dest_region); -} - -static void canvas_draw_blackness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness) -{ - CairoCanvas *canvas = (CairoCanvas *)spice_canvas; - pixman_region32_t dest_region; - - pixman_region32_init_rect(&dest_region, - bbox->left, bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top); - - - canvas_clip_pixman(canvas, &dest_region, clip); - canvas_mask_pixman(canvas, &dest_region, &blackness->mask, - bbox->left, bbox->top); - - if (pixman_region32_n_rects(&dest_region) == 0) { - pixman_region32_fini (&dest_region); - return; - } - - fill_solid_rects(canvas, &dest_region, 0x000000); - - pixman_region32_fini(&dest_region); -} - -static void canvas_draw_whiteness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness) -{ - CairoCanvas *canvas = (CairoCanvas *)spice_canvas; - pixman_region32_t dest_region; - - pixman_region32_init_rect(&dest_region, - bbox->left, bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top); - - - canvas_clip_pixman(canvas, &dest_region, clip); - canvas_mask_pixman(canvas, &dest_region, &whiteness->mask, - bbox->left, bbox->top); - - if (pixman_region32_n_rects(&dest_region) == 0) { - pixman_region32_fini(&dest_region); - return; - } - - fill_solid_rects(canvas, &dest_region, 0xffffffff); - - pixman_region32_fini(&dest_region); -} - -static void canvas_draw_invers(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceInvers *invers) -{ - CairoCanvas *canvas = (CairoCanvas *)spice_canvas; - pixman_region32_t dest_region; - - pixman_region32_init_rect(&dest_region, - bbox->left, bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top); - - - canvas_clip_pixman(canvas, &dest_region, clip); - canvas_mask_pixman(canvas, &dest_region, &invers->mask, - bbox->left, bbox->top); - - if (pixman_region32_n_rects(&dest_region) == 0) { - pixman_region32_fini(&dest_region); - return; - } - - fill_solid_rects_rop(canvas, &dest_region, 0x00000000, - SPICE_ROP_INVERT); - - pixman_region32_fini(&dest_region); -} - -static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3) -{ - CairoCanvas *canvas = (CairoCanvas *)spice_canvas; - pixman_region32_t dest_region; - pixman_image_t *d; - pixman_image_t *s; - SpicePoint src_pos; - int width; - int heigth; - - pixman_region32_init_rect(&dest_region, - bbox->left, bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top); - - - canvas_clip_pixman(canvas, &dest_region, clip); - canvas_mask_pixman(canvas, &dest_region, &rop3->mask, - bbox->left, bbox->top); - - width = bbox->right - bbox->left; - heigth = bbox->bottom - bbox->top; - - d = canvas_surface_from_self(canvas, bbox->left, bbox->top, width, heigth); - s = canvas_get_image(&canvas->base, rop3->src_bitmap); - - if (!rect_is_same_size(bbox, &rop3->src_area)) { - pixman_image_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, width, heigth, - rop3->scale_mode); - pixman_image_unref(s); - s = scaled_s; - src_pos.x = 0; - src_pos.y = 0; - } else { - src_pos.x = rop3->src_area.left; - src_pos.y = rop3->src_area.top; - } - if (pixman_image_get_width(s) - src_pos.x < width || - pixman_image_get_height(s) - src_pos.y < heigth) { - CANVAS_ERROR("bad src bitmap size"); - } - if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) { - pixman_image_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat); - SpicePoint pat_pos; - - pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % pixman_image_get_width(p); - pat_pos.y = (bbox->top - rop3->brush.u.pattern.pos.y) % pixman_image_get_height(p); - do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos); - pixman_image_unref(p); - } else { - uint32_t color = (canvas->base.color_shift) == 8 ? rop3->brush.u.color : - canvas_16bpp_to_32bpp(rop3->brush.u.color); - do_rop3_with_color(rop3->rop3, d, s, &src_pos, color); - } - pixman_image_unref(s); - - blit_with_region(canvas, &dest_region, d, - bbox->left, - bbox->top); - - pixman_image_unref(d); - - pixman_region32_fini(&dest_region); -} - -static void canvas_copy_bits(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos) -{ - CairoCanvas *canvas = (CairoCanvas *)spice_canvas; - pixman_region32_t dest_region; - int dx, dy; - - pixman_region32_init_rect(&dest_region, - bbox->left, bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top); - - canvas_clip_pixman(canvas, &dest_region, clip); - - dx = bbox->left - src_pos->x; - dy = bbox->top - src_pos->y; - - if (dx != 0 || dy != 0) { - pixman_region32_t src_region; - - /* Clip so we don't read outside canvas */ - pixman_region32_init_rect(&src_region, - dx, dy, - pixman_image_get_width (canvas->image), - pixman_image_get_height (canvas->image)); - pixman_region32_intersect(&dest_region, &dest_region, &src_region); - pixman_region32_fini(&src_region); - - copy_region(canvas, &dest_region, dx, dy); - } - - pixman_region32_fini(&dest_region); -} static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text) { @@ -1567,11 +769,11 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl bbox->right - bbox->left, bbox->bottom - bbox->top); - canvas_clip_pixman(canvas, &dest_region, clip); + canvas_clip_pixman(&canvas->base, &dest_region, clip); if (pixman_region32_n_rects(&dest_region) == 0) { - touch_brush(canvas, &text->fore_brush); - touch_brush(canvas, &text->back_brush); + touch_brush(&canvas->base, &text->fore_brush); + touch_brush(&canvas->base, &text->back_brush); pixman_region32_fini(&dest_region); return; } @@ -1592,7 +794,7 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl pixman_region32_intersect(&back_region, &back_region, &dest_region); if (pixman_region32_not_empty(&back_region)) { - draw_brush(canvas, &back_region, &text->back_brush, SPICE_ROP_COPY); + draw_brush(spice_canvas, &back_region, &text->back_brush, SPICE_ROP_COPY); } pixman_region32_fini(&back_region); @@ -1942,10 +1144,10 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spice bbox->right - bbox->left, bbox->bottom - bbox->top); - canvas_clip_pixman(canvas, &gc.dest_region, clip); + canvas_clip_pixman(&canvas->base, &gc.dest_region, clip); if (pixman_region32_n_rects(&gc.dest_region) == 0) { - touch_brush(canvas, &stroke->brush); + touch_brush(&canvas->base, &stroke->brush); pixman_region32_fini(&gc.dest_region); return; } @@ -2194,25 +1396,28 @@ void cairo_canvas_init() //unsafe global function need_init = 0; canvas_base_init_ops(&cairo_canvas_ops); - cairo_canvas_ops.draw_fill = canvas_draw_fill; - cairo_canvas_ops.draw_copy = canvas_draw_copy; - cairo_canvas_ops.draw_opaque = canvas_draw_opaque; - cairo_canvas_ops.copy_bits = canvas_copy_bits; cairo_canvas_ops.draw_text = canvas_draw_text; cairo_canvas_ops.draw_stroke = canvas_draw_stroke; cairo_canvas_ops.draw_rop3 = canvas_draw_rop3; - cairo_canvas_ops.draw_blend = canvas_draw_blend; - cairo_canvas_ops.draw_blackness = canvas_draw_blackness; - cairo_canvas_ops.draw_whiteness = canvas_draw_whiteness; - cairo_canvas_ops.draw_invers = canvas_draw_invers; - cairo_canvas_ops.draw_transparent = canvas_draw_transparent; - cairo_canvas_ops.draw_alpha_blend = canvas_draw_alpha_blend; cairo_canvas_ops.put_image = canvas_put_image; cairo_canvas_ops.clear = canvas_clear; cairo_canvas_ops.read_bits = canvas_read_bits; cairo_canvas_ops.set_access_params = canvas_set_access_params; cairo_canvas_ops.destroy = canvas_destroy; + cairo_canvas_ops.fill_solid_spans = fill_solid_spans; + cairo_canvas_ops.fill_solid_rects = fill_solid_rects; + cairo_canvas_ops.fill_solid_rects_rop = fill_solid_rects_rop; + cairo_canvas_ops.fill_tiled_rects = fill_tiled_rects; + cairo_canvas_ops.fill_tiled_rects_rop = fill_tiled_rects_rop; + cairo_canvas_ops.blit_image = blit_image; + cairo_canvas_ops.blit_image_rop = blit_image_rop; + cairo_canvas_ops.scale_image = scale_image; + cairo_canvas_ops.scale_image_rop = scale_image_rop; + cairo_canvas_ops.blend_image = blend_image; + cairo_canvas_ops.blend_scale_image = blend_scale_image; + cairo_canvas_ops.colorkey_image = colorkey_image; + cairo_canvas_ops.colorkey_scale_image = colorkey_scale_image; + cairo_canvas_ops.copy_region = copy_region; rop3_init(); } - diff --git a/common/canvas_base.c b/common/canvas_base.c index 4bf2be7e..231b5ed7 100644 --- a/common/canvas_base.c +++ b/common/canvas_base.c @@ -231,6 +231,176 @@ typedef struct ATTR_PACKED DataChunk { #endif +typedef enum { + ROP_INPUT_SRC, + ROP_INPUT_BRUSH, + ROP_INPUT_DEST +} ROPInput; + +static SpiceROP ropd_descriptor_to_rop(int desc, + ROPInput src_input, + ROPInput dest_input) +{ + int old; + int invert_masks[] = { + SPICE_ROPD_INVERS_SRC, + SPICE_ROPD_INVERS_BRUSH, + SPICE_ROPD_INVERS_DEST + }; + + old = desc; + + desc &= ~(SPICE_ROPD_INVERS_SRC | SPICE_ROPD_INVERS_DEST); + if (old & invert_masks[src_input]) { + desc |= SPICE_ROPD_INVERS_SRC; + } + + if (old & invert_masks[dest_input]) { + desc |= SPICE_ROPD_INVERS_DEST; + } + + if (desc & SPICE_ROPD_OP_PUT) { + if (desc & SPICE_ROPD_INVERS_SRC) { + if (desc & SPICE_ROPD_INVERS_RES) { + return SPICE_ROP_COPY; + } + return SPICE_ROP_COPY_INVERTED; + } else { + if (desc & SPICE_ROPD_INVERS_RES) { + return SPICE_ROP_COPY_INVERTED; + } + return SPICE_ROP_COPY; + } + } else if (desc & SPICE_ROPD_OP_OR) { + + if (desc & SPICE_ROPD_INVERS_RES) { + if (desc & SPICE_ROPD_INVERS_SRC) { + if (desc & SPICE_ROPD_INVERS_DEST) { + /* !(!src or !dest) == src and dest*/ + return SPICE_ROP_AND; + } else { + /* ! (!src or dest) = src and !dest*/ + return SPICE_ROP_AND_REVERSE; + } + } else { + if (desc & SPICE_ROPD_INVERS_DEST) { + /* !(src or !dest) == !src and dest */ + return SPICE_ROP_AND_INVERTED; + } else { + /* !(src or dest) */ + return SPICE_ROP_NOR; + } + } + } else { + if (desc & SPICE_ROPD_INVERS_SRC) { + if (desc & SPICE_ROPD_INVERS_DEST) { + /* !src or !dest == !(src and dest)*/ + return SPICE_ROP_NAND; + } else { + /* !src or dest */ + return SPICE_ROP_OR_INVERTED; + } + } else { + if (desc & SPICE_ROPD_INVERS_DEST) { + /* src or !dest */ + return SPICE_ROP_OR_REVERSE; + } else { + /* src or dest */ + return SPICE_ROP_OR; + } + } + } + + } else if (desc & SPICE_ROPD_OP_AND) { + + if (desc & SPICE_ROPD_INVERS_RES) { + if (desc & SPICE_ROPD_INVERS_SRC) { + if (desc & SPICE_ROPD_INVERS_DEST) { + /* !(!src and !dest) == src or dest*/ + return SPICE_ROP_OR; + } else { + /* ! (!src and dest) = src or !dest*/ + return SPICE_ROP_OR_REVERSE; + } + } else { + if (desc & SPICE_ROPD_INVERS_DEST) { + /* !(src and !dest) == !src or dest */ + return SPICE_ROP_OR_INVERTED; + } else { + /* !(src and dest) */ + return SPICE_ROP_NAND; + } + } + } else { + if (desc & SPICE_ROPD_INVERS_SRC) { + if (desc & SPICE_ROPD_INVERS_DEST) { + /* !src and !dest == !(src or dest)*/ + return SPICE_ROP_NOR; + } else { + /* !src and dest */ + return SPICE_ROP_AND_INVERTED; + } + } else { + if (desc & SPICE_ROPD_INVERS_DEST) { + /* src and !dest */ + return SPICE_ROP_AND_REVERSE; + } else { + /* src and dest */ + return SPICE_ROP_AND; + } + } + } + + } else if (desc & SPICE_ROPD_OP_XOR) { + + if (desc & SPICE_ROPD_INVERS_RES) { + if (desc & SPICE_ROPD_INVERS_SRC) { + if (desc & SPICE_ROPD_INVERS_DEST) { + /* !(!src xor !dest) == !src xor dest */ + return SPICE_ROP_EQUIV; + } else { + /* ! (!src xor dest) = src xor dest*/ + return SPICE_ROP_XOR; + } + } else { + if (desc & SPICE_ROPD_INVERS_DEST) { + /* !(src xor !dest) == src xor dest */ + return SPICE_ROP_XOR; + } else { + /* !(src xor dest) */ + return SPICE_ROP_EQUIV; + } + } + } else { + if (desc & SPICE_ROPD_INVERS_SRC) { + if (desc & SPICE_ROPD_INVERS_DEST) { + /* !src xor !dest == src xor dest */ + return SPICE_ROP_XOR; + } else { + /* !src xor dest */ + return SPICE_ROP_EQUIV; + } + } else { + if (desc & SPICE_ROPD_INVERS_DEST) { + /* src xor !dest */ + return SPICE_ROP_EQUIV; + } else { + /* src xor dest */ + return SPICE_ROP_XOR; + } + } + } + + } else if (desc & SPICE_ROPD_OP_BLACKNESS) { + return SPICE_ROP_CLEAR; + } else if (desc & SPICE_ROPD_OP_WHITENESS) { + return SPICE_ROP_SET; + } else if (desc & SPICE_ROPD_OP_INVERS) { + return SPICE_ROP_INVERT; + } + return SPICE_ROP_COPY; +} + static inline void canvas_localize_palette(CanvasBase *canvas, SpicePalette *palette) { if (canvas->color_shift == 5) { @@ -874,7 +1044,7 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE #else -static pixman_image_t *canvas_get_image_internal(CairoCanvas *canvas, SPICE_ADDRESS addr, int real_get) +static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRESS addr, int real_get) { SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr); @@ -908,12 +1078,10 @@ static pixman_image_t *canvas_get_image(CanvasBase *canvas, SPICE_ADDRESS addr) return canvas_get_image_internal(canvas, addr, TRUE); } -#ifdef CANVAS_USE_PIXMAN static void canvas_touch_image(CanvasBase *canvas, SPICE_ADDRESS addr) { canvas_get_image_internal(canvas, addr, FALSE); } -#endif static inline uint8_t revers_bits(uint8_t byte) { @@ -1582,6 +1750,646 @@ void *spice_canvas_get_usr_data(SpiceCanvas *spice_canvas) } #endif + +static void canvas_clip_pixman(CanvasBase *canvas, + pixman_region32_t *dest_region, + SpiceClip *clip) +{ + pixman_region32_intersect(dest_region, dest_region, &canvas->canvas_region); + + switch (clip->type) { + case SPICE_CLIP_TYPE_NONE: + break; + case SPICE_CLIP_TYPE_RECTS: { + uint32_t *n = (uint32_t *)SPICE_GET_ADDRESS(clip->data); + access_test(canvas, n, sizeof(uint32_t)); + + SpiceRect *now = (SpiceRect *)(n + 1); + access_test(canvas, now, (unsigned long)(now + *n) - (unsigned long)now); + + pixman_region32_t clip; + + if (spice_pixman_region32_init_rects(&clip, now, *n)) { + pixman_region32_intersect(dest_region, dest_region, &clip); + pixman_region32_fini(&clip); + } + + break; + } + case SPICE_CLIP_TYPE_PATH: + CANVAS_ERROR("clip paths not supported anymore"); + break; + default: + CANVAS_ERROR("invalid clip type"); + } +} + +static void canvas_mask_pixman(CanvasBase *canvas, + pixman_region32_t *dest_region, + SpiceQMask *mask, int x, int y) +{ + pixman_image_t *image, *subimage; + int needs_invert; + pixman_region32_t mask_region; + uint32_t *mask_data; + int mask_x, mask_y; + int mask_width, mask_height, mask_stride; + pixman_box32_t extents; + + needs_invert = FALSE; + image = canvas_get_mask(canvas, + mask, + &needs_invert); + + if (image == NULL) { + return; /* no mask */ + } + + mask_data = pixman_image_get_data(image); + mask_width = pixman_image_get_width(image); + mask_height = pixman_image_get_height(image); + mask_stride = pixman_image_get_stride(image); + + mask_x = mask->pos.x; + mask_y = mask->pos.y; + + /* We need to subset the area of the mask that we turn into a region, + because a cached mask may be much larger than what is used for + the clip operation. */ + extents = *pixman_region32_extents(dest_region); + + /* convert from destination pixels to mask pixels */ + extents.x1 -= x - mask_x; + extents.y1 -= y - mask_y; + extents.x2 -= x - mask_x; + extents.y2 -= y - mask_y; + + /* clip to mask size */ + if (extents.x1 < 0) { + extents.x1 = 0; + } + if (extents.x2 >= mask_width) { + extents.x2 = mask_width; + } + if (extents.x2 < extents.x1) { + extents.x2 = extents.x1; + } + if (extents.y1 < 0) { + extents.y1 = 0; + } + if (extents.y2 >= mask_height) { + extents.y2 = mask_height; + } + if (extents.y2 < extents.y1) { + extents.y2 = extents.y1; + } + + /* round down X to even 32 pixels (i.e. uint32_t) */ + extents.x1 = extents.x1 & ~(0x1f); + + mask_data = (uint32_t *)((uint8_t *)mask_data + mask_stride * extents.y1 + extents.x1 / 32); + mask_x -= extents.x1; + mask_y -= extents.y1; + mask_width = extents.x2 - extents.x1; + mask_height = extents.y2 - extents.y1; + + subimage = pixman_image_create_bits(PIXMAN_a1, mask_width, mask_height, + mask_data, mask_stride); + pixman_region32_init_from_image(&mask_region, + subimage); + pixman_image_unref(subimage); + + if (needs_invert) { + pixman_box32_t rect; + + rect.x1 = rect.y1 = 0; + rect.x2 = mask_width; + rect.y2 = mask_height; + + pixman_region32_inverse(&mask_region, &mask_region, &rect); + } + + pixman_region32_translate(&mask_region, + -mask_x + x, -mask_y + y); + + pixman_region32_intersect(dest_region, dest_region, &mask_region); + pixman_region32_fini(&mask_region); + + pixman_image_unref(image); +} + +static void draw_brush(SpiceCanvas *canvas, + pixman_region32_t *region, + SpiceBrush *brush, + SpiceROP rop) +{ + CanvasBase *canvas_base = (CanvasBase *)canvas; + uint32_t color; + SpicePattern *pattern; + pixman_image_t *tile; + int offset_x, offset_y; + pixman_box32_t *rects; + int n_rects; + + rects = pixman_region32_rectangles(region, &n_rects); + + switch (brush->type) { + case SPICE_BRUSH_TYPE_SOLID: + color = brush->u.color; + if (rop == SPICE_ROP_COPY) { + canvas->ops->fill_solid_rects(canvas, rects, n_rects, color); + } else { + canvas->ops->fill_solid_rects_rop(canvas, rects, n_rects, color, rop); + } + break; + case SPICE_BRUSH_TYPE_PATTERN: + pattern = &brush->u.pattern; + tile = canvas_get_image(canvas_base, pattern->pat); + offset_x = pattern->pos.x; + offset_y = pattern->pos.y; + + if (rop == SPICE_ROP_COPY) { + canvas->ops->fill_tiled_rects(canvas, rects, n_rects, tile, offset_x, offset_y); + } else { + canvas->ops->fill_tiled_rects_rop(canvas, rects, n_rects, + tile, offset_x, offset_y, rop); + } + pixman_image_unref(tile); + break; + case SPICE_BRUSH_TYPE_NONE: + /* Still need to do *something* here, because rop could be e.g invert dest */ + canvas->ops->fill_solid_rects_rop(canvas, rects, n_rects, 0, rop); + break; + default: + CANVAS_ERROR("invalid brush type"); + } +} + +/* If we're exiting early we may still have to load an image in case + it has to be cached or something */ +static void touch_brush(CanvasBase *canvas, SpiceBrush *brush) +{ + SpicePattern *pattern; + + if (brush->type == SPICE_BRUSH_TYPE_PATTERN) { + pattern = &brush->u.pattern; + canvas_touch_image(canvas, pattern->pat); + } +} + +static void canvas_draw_fill(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceFill *fill) +{ + CanvasBase *canvas = (CanvasBase *)spice_canvas; + 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); + + + canvas_clip_pixman(canvas, &dest_region, clip); + canvas_mask_pixman(canvas, &dest_region, &fill->mask, + bbox->left, bbox->top); + + rop = ropd_descriptor_to_rop(fill->rop_decriptor, + ROP_INPUT_BRUSH, + ROP_INPUT_DEST); + + if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) { + touch_brush(canvas, &fill->brush); + pixman_region32_fini(&dest_region); + return; + } + + draw_brush(spice_canvas, &dest_region, &fill->brush, rop); + + pixman_region32_fini(&dest_region); +} + +static void canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy) +{ + CanvasBase *canvas = (CanvasBase *)spice_canvas; + pixman_region32_t dest_region; + pixman_image_t *src_image; + SpiceROP rop; + + pixman_region32_init_rect(&dest_region, + bbox->left, bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top); + + canvas_clip_pixman(canvas, &dest_region, clip); + canvas_mask_pixman(canvas, &dest_region, ©->mask, + bbox->left, bbox->top); + + rop = ropd_descriptor_to_rop(copy->rop_decriptor, + ROP_INPUT_SRC, + ROP_INPUT_DEST); + + if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) { + canvas_touch_image(canvas, copy->src_bitmap); + pixman_region32_fini(&dest_region); + return; + } + + src_image = canvas_get_image(canvas, copy->src_bitmap); + + if (rect_is_same_size(bbox, ©->src_area)) { + if (rop == SPICE_ROP_COPY) { + spice_canvas->ops->blit_image(spice_canvas, &dest_region, + src_image, + bbox->left - copy->src_area.left, + bbox->top - copy->src_area.top); + } else { + spice_canvas->ops->blit_image_rop(spice_canvas, &dest_region, + src_image, + bbox->left - copy->src_area.left, + bbox->top - copy->src_area.top, + rop); + } + } else { + if (rop == SPICE_ROP_COPY) { + spice_canvas->ops->scale_image(spice_canvas, &dest_region, + src_image, + copy->src_area.left, + copy->src_area.top, + copy->src_area.right - copy->src_area.left, + copy->src_area.bottom - copy->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + copy->scale_mode); + } else { + spice_canvas->ops->scale_image_rop(spice_canvas, &dest_region, + src_image, + copy->src_area.left, + copy->src_area.top, + copy->src_area.right - copy->src_area.left, + copy->src_area.bottom - copy->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + copy->scale_mode, + rop); + } + } + + pixman_image_unref(src_image); + pixman_region32_fini(&dest_region); +} + +static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent) +{ + CanvasBase *canvas = (CanvasBase *)spice_canvas; + pixman_image_t *src_image; + pixman_region32_t dest_region; + + pixman_region32_init_rect(&dest_region, + bbox->left, bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top); + + canvas_clip_pixman(canvas, &dest_region, clip); + + if (pixman_region32_n_rects (&dest_region) == 0) { + canvas_touch_image(canvas, transparent->src_bitmap); + pixman_region32_fini(&dest_region); + return; + } + + src_image = canvas_get_image(canvas, transparent->src_bitmap); + + if (rect_is_same_size(bbox, &transparent->src_area)) { + spice_canvas->ops->colorkey_image(spice_canvas, &dest_region, + src_image, + bbox->left - transparent->src_area.left, + bbox->top - transparent->src_area.top, + transparent->true_color); + } else { + spice_canvas->ops->colorkey_scale_image(spice_canvas, &dest_region, + src_image, + transparent->src_area.left, + transparent->src_area.top, + transparent->src_area.right - transparent->src_area.left, + transparent->src_area.bottom - transparent->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + transparent->true_color); + } + + pixman_image_unref(src_image); + pixman_region32_fini(&dest_region); +} + +static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlnd* alpha_blend) +{ + CanvasBase *canvas = (CanvasBase *)spice_canvas; + pixman_region32_t dest_region; + pixman_image_t *src_image; + + pixman_region32_init_rect(&dest_region, + bbox->left, bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top); + + canvas_clip_pixman(canvas, &dest_region, clip); + + if (alpha_blend->alpha == 0 || + pixman_region32_n_rects(&dest_region) == 0) { + canvas_touch_image(canvas, alpha_blend->src_bitmap); + pixman_region32_fini(&dest_region); + return; + } + + src_image = canvas_get_image(canvas, alpha_blend->src_bitmap); + + if (rect_is_same_size(bbox, &alpha_blend->src_area)) { + spice_canvas->ops->blend_image(spice_canvas, &dest_region, + src_image, + alpha_blend->src_area.left, + alpha_blend->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + alpha_blend->alpha); + } else { + spice_canvas->ops->blend_scale_image(spice_canvas, &dest_region, + src_image, + alpha_blend->src_area.left, + alpha_blend->src_area.top, + alpha_blend->src_area.right - alpha_blend->src_area.left, + alpha_blend->src_area.bottom - alpha_blend->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + SPICE_IMAGE_SCALE_MODE_INTERPOLATE, + alpha_blend->alpha); + } + + pixman_image_unref(src_image); + pixman_region32_fini(&dest_region); +} + +static void canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque) +{ + CanvasBase *canvas = (CanvasBase *)spice_canvas; + pixman_image_t *src_image; + 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); + + canvas_clip_pixman(canvas, &dest_region, clip); + canvas_mask_pixman(canvas, &dest_region, &opaque->mask, + bbox->left, bbox->top); + + rop = ropd_descriptor_to_rop(opaque->rop_decriptor, + ROP_INPUT_BRUSH, + ROP_INPUT_SRC); + + if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) { + canvas_touch_image(canvas, opaque->src_bitmap); + touch_brush(canvas, &opaque->brush); + pixman_region32_fini(&dest_region); + return; + } + + src_image = canvas_get_image(canvas, opaque->src_bitmap); + + if (rect_is_same_size(bbox, &opaque->src_area)) { + spice_canvas->ops->blit_image(spice_canvas, &dest_region, + src_image, + bbox->left - opaque->src_area.left, + bbox->top - opaque->src_area.top); + } else { + spice_canvas->ops->scale_image(spice_canvas, &dest_region, + src_image, + opaque->src_area.left, + opaque->src_area.top, + opaque->src_area.right - opaque->src_area.left, + opaque->src_area.bottom - opaque->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + opaque->scale_mode); + } + + draw_brush(spice_canvas, &dest_region, &opaque->brush, rop); + + pixman_image_unref(src_image); + pixman_region32_fini(&dest_region); +} + +static void canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend) +{ + CanvasBase *canvas = (CanvasBase *)spice_canvas; + pixman_image_t *src_image; + 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); + + canvas_clip_pixman(canvas, &dest_region, clip); + canvas_mask_pixman(canvas, &dest_region, &blend->mask, + bbox->left, bbox->top); + + rop = ropd_descriptor_to_rop(blend->rop_decriptor, + ROP_INPUT_SRC, + ROP_INPUT_DEST); + + if (rop == SPICE_ROP_NOOP || pixman_region32_n_rects(&dest_region) == 0) { + canvas_touch_image(canvas, blend->src_bitmap); + pixman_region32_fini(&dest_region); + return; + } + + src_image = canvas_get_image(canvas, blend->src_bitmap); + + if (rect_is_same_size(bbox, &blend->src_area)) { + if (rop == SPICE_ROP_COPY) + spice_canvas->ops->blit_image(spice_canvas, &dest_region, + src_image, + bbox->left - blend->src_area.left, + bbox->top - blend->src_area.top); + else + spice_canvas->ops->blit_image_rop(spice_canvas, &dest_region, + src_image, + bbox->left - blend->src_area.left, + bbox->top - blend->src_area.top, + rop); + } else { + 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) { + spice_canvas->ops->scale_image(spice_canvas, &dest_region, + src_image, + 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 { + spice_canvas->ops->scale_image_rop(spice_canvas, &dest_region, + src_image, + 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); + } + } + + pixman_image_unref(src_image); + pixman_region32_fini(&dest_region); +} + +static void canvas_draw_blackness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness) +{ + CanvasBase *canvas = (CanvasBase *)spice_canvas; + pixman_region32_t dest_region; + pixman_box32_t *rects; + int n_rects; + + pixman_region32_init_rect(&dest_region, + bbox->left, bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top); + + + canvas_clip_pixman(canvas, &dest_region, clip); + canvas_mask_pixman(canvas, &dest_region, &blackness->mask, + bbox->left, bbox->top); + + if (pixman_region32_n_rects(&dest_region) == 0) { + pixman_region32_fini (&dest_region); + return; + } + + rects = pixman_region32_rectangles(&dest_region, &n_rects); + + spice_canvas->ops->fill_solid_rects(spice_canvas, rects, n_rects, 0x000000); + + pixman_region32_fini(&dest_region); +} + +static void canvas_draw_whiteness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness) +{ + CanvasBase *canvas = (CanvasBase *)spice_canvas; + pixman_region32_t dest_region; + pixman_box32_t *rects; + int n_rects; + + pixman_region32_init_rect(&dest_region, + bbox->left, bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top); + + + canvas_clip_pixman(canvas, &dest_region, clip); + canvas_mask_pixman(canvas, &dest_region, &whiteness->mask, + bbox->left, bbox->top); + + if (pixman_region32_n_rects(&dest_region) == 0) { + pixman_region32_fini(&dest_region); + return; + } + + rects = pixman_region32_rectangles(&dest_region, &n_rects); + spice_canvas->ops->fill_solid_rects(spice_canvas, rects, n_rects, 0xffffffff); + + pixman_region32_fini(&dest_region); +} + +static void canvas_draw_invers(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceInvers *invers) +{ + CanvasBase *canvas = (CanvasBase *)spice_canvas; + pixman_region32_t dest_region; + pixman_box32_t *rects; + int n_rects; + + pixman_region32_init_rect(&dest_region, + bbox->left, bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top); + + + canvas_clip_pixman(canvas, &dest_region, clip); + canvas_mask_pixman(canvas, &dest_region, &invers->mask, + bbox->left, bbox->top); + + if (pixman_region32_n_rects(&dest_region) == 0) { + pixman_region32_fini(&dest_region); + return; + } + + rects = pixman_region32_rectangles(&dest_region, &n_rects); + spice_canvas->ops->fill_solid_rects_rop(spice_canvas, rects, n_rects, 0x00000000, + SPICE_ROP_INVERT); + + pixman_region32_fini(&dest_region); +} + +static void canvas_copy_bits(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos) +{ + CanvasBase *canvas = (CanvasBase *)spice_canvas; + pixman_region32_t dest_region; + int dx, dy; + + pixman_region32_init_rect(&dest_region, + bbox->left, bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top); + + canvas_clip_pixman(canvas, &dest_region, clip); + + dx = bbox->left - src_pos->x; + dy = bbox->top - src_pos->y; + + if (dx != 0 || dy != 0) { + pixman_region32_t src_region; + + /* Clip so we don't read outside canvas */ + pixman_region32_init_rect(&src_region, + dx, dy, + canvas->width, + canvas->height); + pixman_region32_intersect(&dest_region, &dest_region, &src_region); + pixman_region32_fini(&src_region); + + spice_canvas->ops->copy_region(spice_canvas, &dest_region, dx, dy); + } + + pixman_region32_fini(&dest_region); +} + + + static void canvas_base_group_start(SpiceCanvas *spice_canvas, QRegion *region) { CanvasBase *canvas = (CanvasBase *)spice_canvas; @@ -1622,6 +2430,16 @@ inline static void canvas_base_init_ops(SpiceCanvasOps *ops) ops_cast[i] = (void *) unimplemented_op; } + ops->draw_fill = canvas_draw_fill; + ops->draw_copy = canvas_draw_copy; + ops->draw_opaque = canvas_draw_opaque; + ops->copy_bits = canvas_copy_bits; + ops->draw_blend = canvas_draw_blend; + ops->draw_blackness = canvas_draw_blackness; + ops->draw_whiteness = canvas_draw_whiteness; + ops->draw_invers = canvas_draw_invers; + ops->draw_transparent = canvas_draw_transparent; + ops->draw_alpha_blend = canvas_draw_alpha_blend; ops->group_start = canvas_base_group_start; ops->group_end = canvas_base_group_end; } diff --git a/common/canvas_base.h b/common/canvas_base.h index 48e921e6..bed1e1ba 100644 --- a/common/canvas_base.h +++ b/common/canvas_base.h @@ -106,6 +106,90 @@ typedef struct { void (*group_end)(SpiceCanvas *canvas); void (*set_access_params)(SpiceCanvas *canvas, unsigned long base, unsigned long max); void (*destroy)(SpiceCanvas *canvas); + + /* Implementation vfuncs */ + void (*fill_solid_spans)(SpiceCanvas *canvas, + SpicePoint *points, + int *widths, + int n_spans, + uint32_t color); + void (*fill_solid_rects)(SpiceCanvas *canvas, + pixman_box32_t *rects, + int n_rects, + uint32_t color); + void (*fill_solid_rects_rop)(SpiceCanvas *canvas, + pixman_box32_t *rects, + int n_rects, + uint32_t color, + SpiceROP rop); + void (*fill_tiled_rects)(SpiceCanvas *canvas, + pixman_box32_t *rects, + int n_rects, + pixman_image_t *tile, + int offset_x, int offset_y); + void (*fill_tiled_rects_rop)(SpiceCanvas *canvas, + pixman_box32_t *rects, + int n_rects, + pixman_image_t *tile, + int offset_x, int offset_y, + SpiceROP rop); + void (*blit_image)(SpiceCanvas *canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + int offset_x, int offset_y); + void (*blit_image_rop)(SpiceCanvas *canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + int offset_x, int offset_y, + SpiceROP rop); + void (*scale_image)(SpiceCanvas *canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + 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); + void (*scale_image_rop)(SpiceCanvas *canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + 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); + void (*blend_image)(SpiceCanvas *canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + 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, + pixman_image_t *src_image, + 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, + int overall_alpha); + void (*colorkey_image)(SpiceCanvas *canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + int offset_x, int offset_y, + uint32_t transparent_color); + void (*colorkey_scale_image)(SpiceCanvas *canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + uint32_t transparent_color); + void (*copy_region)(SpiceCanvas *canvas, + pixman_region32_t *dest_region, + int dx, int dy); } SpiceCanvasOps; void spice_canvas_set_usr_data(SpiceCanvas *canvas, void *data, spice_destroy_fn_t destroy_fn); |