diff options
author | Alexander Larsson <alexl@redhat.com> | 2010-02-10 14:00:42 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2010-02-23 22:52:05 +0100 |
commit | bf0d038e76b1d875accb73adb04de7cba148f995 (patch) | |
tree | 20ba5aaf785fc9d88f1df55fe0eceeb5a300d589 /common | |
parent | 7fe1df4e140eec348137fa5934e33d3b968eede7 (diff) | |
download | spice-bf0d038e76b1d875accb73adb04de7cba148f995.tar.gz spice-bf0d038e76b1d875accb73adb04de7cba148f995.tar.xz spice-bf0d038e76b1d875accb73adb04de7cba148f995.zip |
Convert cairo canvas copy bits to pixman
Diffstat (limited to 'common')
-rw-r--r-- | common/cairo_canvas.c | 301 |
1 files changed, 90 insertions, 211 deletions
diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c index 34f6fa4f..97fa6c59 100644 --- a/common/cairo_canvas.c +++ b/common/cairo_canvas.c @@ -1002,6 +1002,75 @@ static void __draw_mask(void *data) cairo_mask(((DrawMaskData *)data)->cairo, ((DrawMaskData *)data)->mask); } +static void copy_region(CairoCanvas *canvas, + pixman_region32_t *dest_region, + int dx, int dy) +{ + pixman_box32_t *dest_rects; + int n_rects; + int i, j, end_line; + + dest_rects = pixman_region32_rectangles(dest_region, &n_rects); + + if (dy > 0) { + if (dx >= 0) { + /* south-east: copy x and y in reverse order */ + for (i = n_rects - 1; i >= 0; i--) { + spice_pixman_copy_rect(canvas->image, + dest_rects[i].x1 - dx, dest_rects[i].y1 - dy, + dest_rects[i].x2 - dest_rects[i].x1, + dest_rects[i].y2 - dest_rects[i].y1, + dest_rects[i].x1, dest_rects[i].y1); + } + } else { + /* south-west: Copy y in reverse order, but x in forward order */ + i = n_rects - 1; + + while (i >= 0) { + /* Copy all rects with same y in forward order */ + for (end_line = i - 1; end_line >= 0 && dest_rects[end_line].y1 == dest_rects[i].y1; end_line--) { + } + for (j = end_line + 1; j <= i; j++) { + spice_pixman_copy_rect(canvas->image, + dest_rects[j].x1 - dx, dest_rects[j].y1 - dy, + dest_rects[j].x2 - dest_rects[j].x1, + dest_rects[j].y2 - dest_rects[j].y1, + dest_rects[j].x1, dest_rects[j].y1); + } + i = end_line; + } + } + } else { + if (dx > 0) { + /* north-east: copy y in forward order, but x in reverse order */ + i = 0; + + while (i < n_rects) { + /* Copy all rects with same y in reverse order */ + for (end_line = i; end_line < n_rects && dest_rects[end_line].y1 == dest_rects[i].y1; end_line++) { + } + for (j = end_line - 1; j >= i; j--) { + spice_pixman_copy_rect(canvas->image, + dest_rects[j].x1 - dx, dest_rects[j].y1 - dy, + dest_rects[j].x2 - dest_rects[j].x1, + dest_rects[j].y2 - dest_rects[j].y1, + dest_rects[j].x1, dest_rects[j].y1); + } + i = end_line; + } + } else { + /* north-west: Copy x and y in forward order */ + for (i = 0; i < n_rects; i++) { + spice_pixman_copy_rect(canvas->image, + dest_rects[i].x1 - dx, dest_rects[i].y1 - dy, + dest_rects[i].x2 - dest_rects[i].x1, + dest_rects[i].y2 - dest_rects[i].y1, + dest_rects[i].x1, dest_rects[i].y1); + } + } + } +} + static void fill_solid_rects(CairoCanvas *canvas, pixman_region32_t *region, uint32_t color) @@ -1939,226 +2008,36 @@ void canvas_draw_rop3(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi cairo_restore(cairo); } -#define FAST_COPY_BITS - -#ifdef FAST_COPY_BITS - -static inline void __canvas_copy_bits_up(uint8_t *data, const int stride, - const int src_x, const int src_y, - const int width, const int height, - const int dest_x, const int dest_y) -{ - uint8_t *src = data + src_y * stride + src_x * sizeof(uint32_t); - uint8_t *dest = data + dest_y * stride + dest_x * sizeof(uint32_t); - uint8_t *end = dest + height * stride; - for (; dest != end; dest += stride, src += stride) { - memcpy(dest, src, width * sizeof(uint32_t)); - } -} - -static inline void __canvas_copy_bits_down(uint8_t *data, const int stride, - const int src_x, const int src_y, - const int width, const int height, - const int dest_x, const int dest_y) -{ - uint8_t *src = data + (src_y + height - 1) * stride + src_x * sizeof(uint32_t); - uint8_t *end = data + (dest_y - 1) * stride + dest_x * sizeof(uint32_t); - uint8_t *dest = end + height * stride; - - for (; dest != end; dest -= stride, src -= stride) { - memcpy(dest, src, width * sizeof(uint32_t)); - } -} - -static inline void __canvas_copy_bits_right(uint8_t *data, const int stride, - const int src_x, const int src_y, - const int width, const int height, - const int dest_x, const int dest_y) -{ - uint8_t *src = data + src_y * stride + (src_x + width - 1) * sizeof(uint32_t); - uint8_t *dest = data + dest_y * stride + (dest_x + width - 1) * sizeof(uint32_t); - uint8_t *end = dest + height * stride; - for (; dest != end; dest += stride, src += stride) { - uint32_t *src_pix = (uint32_t *)src; - uint32_t *end_pix = src_pix - width; - uint32_t *dest_pix = (uint32_t *)dest; - - for (; src_pix > end_pix; src_pix--, dest_pix--) { - *dest_pix = *src_pix; - } - } -} - -static inline void __canvas_copy_rect_bits(uint8_t *data, const int stride, SpiceRect *dest_rect, - SpicePoint *src_pos) -{ - if (dest_rect->top > src_pos->y) { - __canvas_copy_bits_down(data, stride, src_pos->x, src_pos->y, - dest_rect->right - dest_rect->left, - dest_rect->bottom - dest_rect->top, - dest_rect->left, dest_rect->top); - } else if (dest_rect->top < src_pos->y || dest_rect->left < src_pos->x) { - __canvas_copy_bits_up(data, stride, src_pos->x, src_pos->y, - dest_rect->right - dest_rect->left, - dest_rect->bottom - dest_rect->top, - dest_rect->left, dest_rect->top); - } else { - __canvas_copy_bits_right(data, stride, src_pos->x, src_pos->y, - dest_rect->right - dest_rect->left, - dest_rect->bottom - dest_rect->top, - dest_rect->left, dest_rect->top); - } -} - -static inline void canvas_copy_fix_clip_area(const SpiceRect *dest, - const SpicePoint *src_pos, - const SpiceRect *now, - SpicePoint *ret_pos, - SpiceRect *ret_dest) -{ - *ret_dest = *now; - rect_sect(ret_dest, dest); - ret_pos->x = src_pos->x + (ret_dest->left - dest->left); - ret_pos->y = src_pos->y + (ret_dest->top - dest->top); -} - -static inline void __canvas_copy_region_bits(uint8_t *data, int stride, SpiceRect *dest_rect, - SpicePoint *src_pos, QRegion *region) +void canvas_copy_bits(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos) { - SpiceRect curr_area; - SpicePoint curr_pos; - SpiceRect *now; - SpiceRect *end; - - if (dest_rect->top > src_pos->y) { - end = region->rects - 1; - now = end + region->num_rects; - if (dest_rect->left < src_pos->x) { - for (; now > end; now--) { - SpiceRect *line_end = now; - SpiceRect *line_pos; - - while (now - 1 > end && now->top == now[-1].top) { - now--; - } - - for (line_pos = now; line_pos <= line_end; line_pos++) { - canvas_copy_fix_clip_area(dest_rect, src_pos, line_pos, &curr_pos, &curr_area); - __canvas_copy_bits_down(data, stride, curr_pos.x, curr_pos.y, - curr_area.right - curr_area.left, - curr_area.bottom - curr_area.top, - curr_area.left, curr_area.top); - } - } - } else { - for (; now > end; now--) { - canvas_copy_fix_clip_area(dest_rect, src_pos, now, &curr_pos, &curr_area); - __canvas_copy_bits_down(data, stride, curr_pos.x, curr_pos.y, - curr_area.right - curr_area.left, - curr_area.bottom - curr_area.top, - curr_area.left, curr_area.top); - } - } - } else if (dest_rect->top < src_pos->y || dest_rect->left < src_pos->x) { - now = region->rects; - end = now + region->num_rects; - if (dest_rect->left > src_pos->x) { - for (; now < end; now++) { - SpiceRect *line_end = now; - SpiceRect *line_pos; - - while (now + 1 < end && now->top == now[1].top) { - now++; - } - - for (line_pos = now; line_pos >= line_end; line_pos--) { - canvas_copy_fix_clip_area(dest_rect, src_pos, line_pos, &curr_pos, &curr_area); - __canvas_copy_bits_up(data, stride, curr_pos.x, curr_pos.y, - curr_area.right - curr_area.left, - curr_area.bottom - curr_area.top, - curr_area.left, curr_area.top); - } - } - } else { - for (; now < end; now++) { - canvas_copy_fix_clip_area(dest_rect, src_pos, now, &curr_pos, &curr_area); - __canvas_copy_bits_up(data, stride, curr_pos.x, curr_pos.y, - curr_area.right - curr_area.left, - curr_area.bottom - curr_area.top, - curr_area.left, curr_area.top); - } - } - } else { - end = region->rects - 1; - now = end + region->num_rects; - for (; now > end; now--) { - canvas_copy_fix_clip_area(dest_rect, src_pos, now, &curr_pos, &curr_area); - __canvas_copy_bits_right(data, stride, curr_pos.x, curr_pos.y, - curr_area.right - curr_area.left, - curr_area.bottom - curr_area.top, - curr_area.left, curr_area.top); - } - } -} + pixman_region32_t dest_region; + int dx, dy; -#endif + pixman_region32_init_rect(&dest_region, + bbox->left, bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top); -void canvas_copy_bits(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos) -{ - cairo_t *cairo = canvas->cairo; - cairo_surface_t *cairo_surface; - pixman_image_t *surface; - int32_t width; - int32_t heigth; + canvas_clip_pixman(canvas, &dest_region, clip); - cairo_save(cairo); -#ifdef FAST_COPY_BITS - switch (clip->type) { - case SPICE_CLIP_TYPE_NONE: { - __canvas_copy_rect_bits((uint8_t *)pixman_image_get_data(canvas->image), - pixman_image_get_stride(canvas->image), - bbox, src_pos); - break; - } - case SPICE_CLIP_TYPE_RECTS: { - uint32_t *n = (uint32_t *)SPICE_GET_ADDRESS(clip->data); - access_test(&canvas->base, n, sizeof(uint32_t)); + dx = bbox->left - src_pos->x; + dy = bbox->top - src_pos->y; - SpiceRect *now = (SpiceRect *)(n + 1); - SpiceRect *end = now + *n; - access_test(&canvas->base, now, (unsigned long)end - (unsigned long)now); - uint8_t *data = (uint8_t *)pixman_image_get_data(canvas->image); - int stride = pixman_image_get_stride(canvas->image); + if (dx != 0 || dy != 0) { + pixman_region32_t src_region; - //using QRegion in order to sort and remove intersections - QRegion region; - region_init(®ion); - for (; now < end; now++) { - region_add(®ion, now); - } - __canvas_copy_region_bits(data, stride, bbox, src_pos, ®ion); - region_destroy(®ion); - break; - } - default: -#endif - canvas_clip(canvas, clip); + /* 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); - width = bbox->right - bbox->left; - heigth = bbox->bottom - bbox->top; - surface = canvas_surface_from_self(canvas, src_pos, width, heigth); - cairo_surface = surface_from_pixman_image (surface); - cairo_set_source_surface(cairo, cairo_surface, bbox->left, bbox->top); - cairo_rectangle(cairo, bbox->left, bbox->top, width, heigth); - cairo_set_operator(cairo, CAIRO_OPERATOR_RASTER_COPY); - cairo_fill(cairo); - cairo_surface_destroy(cairo_surface); - pixman_image_unref (surface); -#ifdef FAST_COPY_BITS + copy_region(canvas, &dest_region, dx, dy); } -#endif - cairo_restore(cairo); + pixman_region32_fini(&dest_region); } static void canvas_draw_raster_str(CairoCanvas *canvas, SpiceString *str, int bpp, |