summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2010-02-17 21:33:23 +0100
committerAlexander Larsson <alexl@redhat.com>2010-02-23 22:52:06 +0100
commit98dde80ed3c01f6ac08bcd14d34d6643da9f8418 (patch)
treea872eb82b7012195c4dd08dc7d2115f0cfac7e71
parent8f912e49179803fa640b3bddf75b62e81b2f7178 (diff)
downloadspice-98dde80ed3c01f6ac08bcd14d34d6643da9f8418.tar.gz
spice-98dde80ed3c01f6ac08bcd14d34d6643da9f8418.tar.xz
spice-98dde80ed3c01f6ac08bcd14d34d6643da9f8418.zip
Replace custom region implementation with pixman_region32_t
pixman_region32_t is an efficient well tested region implementation (its the one used in X) that we already depend on via pixman and use in some places. No need to have a custom region implementation.
-rw-r--r--client/application.cpp20
-rw-r--r--client/canvas.h3
-rw-r--r--client/cursor_channel.cpp14
-rw-r--r--client/gui/gui.cpp26
-rw-r--r--client/red_cairo_canvas.cpp15
-rw-r--r--client/red_gl_canvas.cpp16
-rw-r--r--client/screen.cpp50
-rw-r--r--client/screen_layer.cpp21
-rw-r--r--client/x11/red_window.cpp5
-rw-r--r--common/cairo_canvas.c30
-rw-r--r--common/cairo_canvas.h2
-rw-r--r--common/gl_canvas.c35
-rw-r--r--common/gl_canvas.h2
-rw-r--r--common/region.c1172
-rw-r--r--common/region.h20
-rw-r--r--server/red_worker.c57
16 files changed, 618 insertions, 870 deletions
diff --git a/client/application.cpp b/client/application.cpp
index cca7d434..0fa25b4f 100644
--- a/client/application.cpp
+++ b/client/application.cpp
@@ -171,13 +171,23 @@ InfoLayer::InfoLayer()
void InfoLayer::draw_info(const QRegion& dest_region, RedDrawable& dest)
{
- for (int i = 0; i < (int)dest_region.num_rects; i++) {
- SpiceRect* r = &dest_region.rects[i];
+ pixman_box32_t *rects;
+ int num_rects;
+
+ rects = pixman_region32_rectangles((pixman_region32_t *)&dest_region, &num_rects);
+ for (int i = 0; i < num_rects; i++) {
+ SpiceRect r;
+
+ r.left = rects[i].x1;
+ r.top = rects[i].y1;
+ r.right = rects[i].x2;
+ r.bottom = rects[i].y2;
+
/* is rect inside sticky region or info region? */
- if (_sticky_on && rect_intersects(*r, _sticky_rect)) {
- dest.blend_pixels(_sticky_pixmap, r->left - _sticky_pos.x, r->top - _sticky_pos.y, *r);
+ if (_sticky_on && rect_intersects(r, _sticky_rect)) {
+ dest.blend_pixels(_sticky_pixmap, r.left - _sticky_pos.x, r.top - _sticky_pos.y, r);
} else {
- dest.blend_pixels(_info_pixmap, r->left - _info_pos.x, r->top - _info_pos.y, *r);
+ dest.blend_pixels(_info_pixmap, r.left - _info_pos.x, r.top - _info_pos.y, r);
}
}
}
diff --git a/client/canvas.h b/client/canvas.h
index 1bd3180f..65856565 100644
--- a/client/canvas.h
+++ b/client/canvas.h
@@ -20,6 +20,7 @@
#include "common.h"
#include "debug.h"
+#include "region.h"
#include "cairo.h"
#include <spice/protocol.h>
#include "cache.hpp"
@@ -36,8 +37,6 @@ enum CanvasType {
CANVAS_TYPE_GDI,
};
-struct QRegion;
-
class PixmapCacheTreat {
public:
static inline pixman_image_t *get(pixman_image_t *surf)
diff --git a/client/cursor_channel.cpp b/client/cursor_channel.cpp
index 30c52d9d..0909f5c6 100644
--- a/client/cursor_channel.cpp
+++ b/client/cursor_channel.cpp
@@ -434,16 +434,26 @@ void CursorChannel::remove_cursor()
void CursorChannel::copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc)
{
+ pixman_box32_t *rects;
+ int num_rects;
+
Lock lock(_update_lock);
if (!_cursor_visible) {
return;
}
- for (int i = 0; i < (int)dest_region.num_rects; i++) {
+ rects = pixman_region32_rectangles((pixman_region32_t *)&dest_region, &num_rects);
+ for (int i = 0; i < num_rects; i++) {
+ SpiceRect r;
+
+ r.left = rects[i].x1;
+ r.top = rects[i].y1;
+ r.right = rects[i].x2;
+ r.bottom = rects[i].y2;
ASSERT(_cursor && _cursor->get_opaque());
((NaitivCursor*)_cursor->get_opaque())->draw(dest_dc, _cursor_rect.left, _cursor_rect.top,
- dest_region.rects[i]);
+ r);
}
}
diff --git a/client/gui/gui.cpp b/client/gui/gui.cpp
index e4d69ee0..0ff442e5 100644
--- a/client/gui/gui.cpp
+++ b/client/gui/gui.cpp
@@ -1025,19 +1025,33 @@ void GUI::update_layer_area()
void GUI::copy_pixels(const QRegion& dest_region, RedDrawable& dest)
{
+ pixman_box32_t *rects;
+ int num_rects;
+
if (region_is_empty(&dest_region)) {
return;
}
- for (int i = 0; i < (int)dest_region.num_rects; i++) {
- SpiceRect* r = &dest_region.rects[i];
- _pixmap->copy_pixels(dest, r->left, r->top, *r);
+ rects = pixman_region32_rectangles((pixman_region32_t *)&dest_region, &num_rects);
+ for (int i = 0; i < num_rects; i++) {
+ SpiceRect r;
+
+ r.left = rects[i].x1;
+ r.top = rects[i].y1;
+ r.right = rects[i].x2;
+ r.bottom = rects[i].y2;
+ _pixmap->copy_pixels(dest, r.left, r.top, r);
}
_gui_system->renderGUI();
- for (int i = 0; i < (int)dest_region.num_rects; i++) {
- SpiceRect* r = &dest_region.rects[i];
- dest.copy_pixels(*_pixmap, r->left, r->top, *r);
+ for (int i = 0; i < num_rects; i++) {
+ SpiceRect r;
+
+ r.left = rects[i].x1;
+ r.top = rects[i].y1;
+ r.right = rects[i].x2;
+ r.bottom = rects[i].y2;
+ dest.copy_pixels(*_pixmap, r.left, r.top, r);
}
}
diff --git a/client/red_cairo_canvas.cpp b/client/red_cairo_canvas.cpp
index 80a89b75..c2496ff4 100644
--- a/client/red_cairo_canvas.cpp
+++ b/client/red_cairo_canvas.cpp
@@ -68,9 +68,18 @@ void CCanvas::create_pixmap(int width, int height, RedWindow *win)
void CCanvas::copy_pixels(const QRegion& region, RedDrawable& dest_dc)
{
- for (int i = 0; i < (int)region.num_rects; i++) {
- SpiceRect* r = &region.rects[i];
- dest_dc.copy_pixels(*_pixmap, r->left, r->top, *r);
+ pixman_box32_t *rects;
+ int num_rects;
+
+ rects = pixman_region32_rectangles((pixman_region32_t *)&region, &num_rects);
+ for (int i = 0; i < num_rects; i++) {
+ SpiceRect r;
+
+ r.left = rects[i].x1;
+ r.top = rects[i].y1;
+ r.right = rects[i].x2;
+ r.bottom = rects[i].y2;
+ dest_dc.copy_pixels(*_pixmap, r.left, r.top, r);
}
}
diff --git a/client/red_gl_canvas.cpp b/client/red_gl_canvas.cpp
index 43bf4249..65984257 100644
--- a/client/red_gl_canvas.cpp
+++ b/client/red_gl_canvas.cpp
@@ -69,9 +69,19 @@ void GCanvas::create_pixmap(int width, int height, RedWindow *win,
void GCanvas::copy_pixels(const QRegion& region, RedDrawable& dest_dc)
{
- for (int i = 0; i < (int)region.num_rects; i++) {
- SpiceRect* r = &region.rects[i];
- dest_dc.copy_pixels(*_pixmap, r->left, r->top, *r);
+ pixman_box32_t *rects;
+ int num_rects;
+
+ rects = pixman_region32_rectangles((pixman_region32_t *)&region, &num_rects);
+ for (int i = 0; i < num_rects; i++) {
+ SpiceRect r;
+
+ r.left = rects[i].x1;
+ r.top = rects[i].y1;
+ r.right = rects[i].x2;
+ r.bottom = rects[i].y2;
+
+ dest_dc.copy_pixels(*_pixmap, r.left, r.top, r);
}
}
diff --git a/client/screen.cpp b/client/screen.cpp
index 9e6b04ee..40e06764 100644
--- a/client/screen.cpp
+++ b/client/screen.cpp
@@ -288,9 +288,18 @@ void RedScreen::detach_layer(ScreenLayer& layer)
void RedScreen::composit_to_screen(RedDrawable& win_dc, const QRegion& region)
{
- for (int i = 0; i < (int)region.num_rects; i++) {
- SpiceRect* r = &region.rects[i];
- win_dc.copy_pixels(*_composit_area, r->left, r->top, *r);
+ pixman_box32_t *rects;
+ int num_rects;
+
+ rects = pixman_region32_rectangles((pixman_region32_t *)&region, &num_rects);
+ for (int i = 0; i < num_rects; i++) {
+ SpiceRect r;
+
+ r.left = rects[i].x1;
+ r.top = rects[i].y1;
+ r.right = rects[i].x2;
+ r.bottom = rects[i].y2;
+ win_dc.copy_pixels(*_composit_area, r.left, r.top, r);
}
}
@@ -474,17 +483,40 @@ uint64_t RedScreen::invalidate(const SpiceRect& rect, bool urgent)
void RedScreen::invalidate(const QRegion &region)
{
- SpiceRect *r = region.rects;
- SpiceRect *end = r + region.num_rects;
- while (r != end) {
- invalidate(*r++, false);
+ pixman_box32_t *rects, *end;
+ int num_rects;
+
+ rects = pixman_region32_rectangles((pixman_region32_t *)&region, &num_rects);
+ end = rects + num_rects;
+
+ while (rects != end) {
+ SpiceRect r;
+
+ r.left = rects->x1;
+ r.top = rects->y1;
+ r.right = rects->x2;
+ r.bottom = rects->y2;
+ rects++;
+
+ invalidate(r, false);
}
}
inline void RedScreen::erase_background(RedDrawable& dc, const QRegion& composit_rgn)
{
- for (int i = 0; i < (int)composit_rgn.num_rects; i++) {
- dc.fill_rect(composit_rgn.rects[i], 0);
+ pixman_box32_t *rects;
+ int num_rects;
+
+ rects = pixman_region32_rectangles((pixman_region32_t *)&composit_rgn, &num_rects);
+ for (int i = 0; i < num_rects; i++) {
+ SpiceRect r;
+
+ r.left = rects[i].x1;
+ r.top = rects[i].y1;
+ r.right = rects[i].x2;
+ r.bottom = rects[i].y2;
+
+ dc.fill_rect(r, 0);
}
}
diff --git a/client/screen_layer.cpp b/client/screen_layer.cpp
index af25211e..ef5ef95e 100644
--- a/client/screen_layer.cpp
+++ b/client/screen_layer.cpp
@@ -93,13 +93,26 @@ uint64_t ScreenLayer::invalidate(const SpiceRect& r, bool urgent)
void ScreenLayer::invalidate(const QRegion& region)
{
+ pixman_box32_t *rects, *end;
+ int num_rects;
+
if (!_screen) {
return;
}
- SpiceRect *r = region.rects;
- SpiceRect *end = r + region.num_rects;
- while (r != end) {
- invalidate_rect(*r++, false);
+
+ rects = pixman_region32_rectangles((pixman_region32_t *)&region, &num_rects);
+ end = rects + num_rects;
+
+ while (rects != end) {
+ SpiceRect r;
+
+ r.left = rects->x1;
+ r.top = rects->y1;
+ r.right = rects->x2;
+ r.bottom = rects->y2;
+ rects++;
+
+ invalidate_rect(r, false);
}
}
diff --git a/client/x11/red_window.cpp b/client/x11/red_window.cpp
index 49c5533c..a38f7db6 100644
--- a/client/x11/red_window.cpp
+++ b/client/x11/red_window.cpp
@@ -1835,7 +1835,10 @@ public:
if (region_is_empty(_region)) {
bbox.left = bbox.right = bbox.top = bbox.bottom = 0;
} else {
- bbox = _region->bbox;
+ bbox.left = _region->extents.x1;
+ bbox.top = _region->extents.y1;
+ bbox.right = _region->extents.x2;
+ bbox.bottom = _region->extents.y2;
}
}
diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index 1f92c345..a1f79d04 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -1130,11 +1130,14 @@ void canvas_put_image(CairoCanvas *canvas, const SpiceRect *dest, const uint8_t
cairo_save(cairo);
if (clip) {
- const SpiceRect *now = clip->rects;
- const SpiceRect *end = clip->rects + clip->num_rects;
+ int num_rects;
+ pixman_box32_t *rects = pixman_region32_rectangles((pixman_region32_t *)clip,
+ &num_rects);
+ const pixman_box32_t *now = rects;
+ const pixman_box32_t *end = rects + num_rects;
for (; now < end; now++) {
- cairo_rectangle(cairo, now->left, now->top, now->right - now->left,
- now->bottom - now->top);
+ cairo_rectangle(cairo, now->x1, now->y1, now->x2 - now->x1,
+ now->y2 - now->y1);
}
cairo_clip(cairo);
}
@@ -2137,23 +2140,16 @@ void canvas_read_bits(CairoCanvas *canvas, uint8_t *dest, int dest_stride, const
}
}
-void canvas_group_start(CairoCanvas *canvas, int n_clip_rects, SpiceRect *clip_rects)
+void canvas_group_start(CairoCanvas *canvas, QRegion *region)
{
- pixman_region32_t dest_region;
-
pixman_region32_fini(&canvas->canvas_region);
- spice_pixman_region32_init_rects(&canvas->canvas_region,
- clip_rects, n_clip_rects);
-
- pixman_region32_init_rect(&dest_region,
- 0, 0,
- pixman_image_get_width(canvas->image),
- pixman_image_get_height(canvas->image));
-
/* Make sure we always clip to canvas size */
- pixman_region32_intersect(&canvas->canvas_region, &canvas->canvas_region, &dest_region);
+ pixman_region32_init_rect(&canvas->canvas_region,
+ 0, 0,
+ pixman_image_get_width (canvas->image),
+ pixman_image_get_height (canvas->image));
- pixman_region32_fini(&dest_region);
+ pixman_region32_intersect(&canvas->canvas_region, &canvas->canvas_region, region);
}
void canvas_group_end(CairoCanvas *canvas)
diff --git a/common/cairo_canvas.h b/common/cairo_canvas.h
index b0c0820e..2b935098 100644
--- a/common/cairo_canvas.h
+++ b/common/cairo_canvas.h
@@ -52,7 +52,7 @@ void canvas_put_image(CairoCanvas *canvas, const SpiceRect *dest, const uint8_t
#endif
void canvas_clear(CairoCanvas *canvas);
void canvas_read_bits(CairoCanvas *canvas, uint8_t *dest, int dest_stride, const SpiceRect *area);
-void canvas_group_start(CairoCanvas *canvas, int n_clip_rects, SpiceRect *clip_rects);
+void canvas_group_start(CairoCanvas *canvas, QRegion *region);
void canvas_group_end(CairoCanvas *canvas);
void canvas_set_addr_delta(CairoCanvas *canvas, SPICE_ADDRESS delta);
#ifdef CAIRO_CANVAS_ACCESS_TEST
diff --git a/common/gl_canvas.c b/common/gl_canvas.c
index 8d152eee..076090e9 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -164,6 +164,13 @@ static GLCPath get_path(GLCanvas *canvas, void *addr)
(dest)->height = (src)->bottom - (src)->top; \
}
+#define SET_GLC_BOX(dest, src) { \
+ (dest)->x = (src)->x1; \
+ (dest)->y = (src)->y1; \
+ (dest)->width = (src)->x2 - (src)->x1; \
+ (dest)->height = (src)->y2 - (src)->y1; \
+}
+
static void set_clip(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip)
{
GLCRect rect;
@@ -706,14 +713,21 @@ void gl_canvas_read_pixels(GLCanvas *canvas, uint8_t *dest, int dest_stride, con
glc_read_pixels(canvas->glc, area->left, area->top, &image);
}
-void gl_canvas_set_top_mask(GLCanvas *canvas, int num_rect, const SpiceRect *rects)
+void gl_canvas_set_top_mask(GLCanvas *canvas, QRegion *region)
{
- GLCRect *glc_rects = (GLCRect *)malloc(num_rect * sizeof(GLCRect));
- GLCRect *now = glc_rects;
- GLCRect *end = glc_rects + num_rect;
+ GLCRect *glc_rects;
+ GLCRect *now, *end;
+ int num_rect;
+ pixman_box32_t *rects;
+
+ rects = pixman_region32_rectangles(region, &num_rect);
+
+ glc_rects = (GLCRect *)malloc(num_rect * sizeof(GLCRect));
+ now = glc_rects;
+ end = glc_rects + num_rect;
for (; now < end; now++, rects++) {
- SET_GLC_RECT(now, rects);
+ SET_GLC_BOX(now, rects);
}
glc_mask_rects(canvas->glc, num_rect, glc_rects, GLC_MASK_B);
@@ -733,15 +747,18 @@ void gl_canvas_put_image(GLCanvas *canvas, const SpiceRect *dest, const uint8_t
glc_clip_reset(canvas->glc);
if (clip) {
+ int num_rects;
+ pixman_box32_t *rects = pixman_region32_rectangles((pixman_region32_t *)clip,
+ &num_rects);
GLCRect rect;
- if (clip->num_rects == 0) {
+ if (num_rects == 0) {
rect.x = rect.y = rect.width = rect.height = 0;
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
} else {
- SET_GLC_RECT(&rect, clip->rects);
+ SET_GLC_BOX(&rect, rects);
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
- for (i = 1; i < clip->num_rects; i++) {
- SET_GLC_RECT(&rect, clip->rects + i);
+ for (i = 1; i < num_rects; i++) {
+ SET_GLC_BOX(&rect, rects + i);
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_OR);
}
}
diff --git a/common/gl_canvas.h b/common/gl_canvas.h
index 794b1ea0..39b27923 100644
--- a/common/gl_canvas.h
+++ b/common/gl_canvas.h
@@ -45,7 +45,7 @@ void gl_canvas_put_image(GLCanvas *canvas, const SpiceRect *dest, const uint8_t
void gl_canvas_clear(GLCanvas *canvas);
-void gl_canvas_set_top_mask(GLCanvas *canvas, int num_rect, const SpiceRect *rects);
+void gl_canvas_set_top_mask(GLCanvas *canvas, QRegion *region);
void gl_canvas_clear_top_mask(GLCanvas *canvas);
#ifdef CAIRO_CANVAS_ACCESS_TEST
diff --git a/common/region.c b/common/region.c
index f0bb614f..06b76d56 100644
--- a/common/region.c
+++ b/common/region.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
@@ -22,9 +23,6 @@
#include "region.h"
#include "rect.h"
-//#define ALLOC_ON_STEAL
-//#define REGION_DEBUG
-
#define FALSE 0
#define TRUE 1
@@ -36,927 +34,540 @@
abort(); \
}
-#ifdef REGION_DEBUG
-#define REGION_IS_VALID(region) region_is_valid(region)
-#else
-#define REGION_IS_VALID(region) TRUE
-#endif
+/* true iff two Boxes overlap */
+#define EXTENTCHECK(r1, r2) \
+ (!( ((r1)->x2 <= (r2)->x1) || \
+ ((r1)->x1 >= (r2)->x2) || \
+ ((r1)->y2 <= (r2)->y1) || \
+ ((r1)->y1 >= (r2)->y2) ) )
-static int rect_is_valid(const SpiceRect *r)
-{
- if (r->top > r->bottom || r->left > r->right) {
- printf("%s: invalid rect\n", __FUNCTION__);
- return FALSE;
- }
- return TRUE;
-}
+/* true iff Box r1 contains Box r2 */
+#define SUBSUMES(r1, r2) \
+ ( ((r1)->x1 <= (r2)->x1) && \
+ ((r1)->x2 >= (r2)->x2) && \
+ ((r1)->y1 <= (r2)->y1) && \
+ ((r1)->y2 >= (r2)->y2) )
-#ifdef REGION_TEST
-static void rect_set(SpiceRect *r, int32_t top, int32_t left, int32_t bottom, int32_t right)
-{
- r->top = top;
- r->left = left;
- r->bottom = bottom;
- r->right = right;
- ASSERT(rect_is_valid(r));
-}
-
-#endif
-
-static inline void __region_init(QRegion *rgn)
-{
- rgn->num_rects = 0;
- rgn->rects = rgn->buf;
- rgn->rects_size = RECTS_BUF_SIZE;
-}
void region_init(QRegion *rgn)
{
- __region_init(rgn);
- ASSERT(REGION_IS_VALID(rgn));
+ pixman_region32_init(rgn);
}
void region_clear(QRegion *rgn)
{
- rgn->num_rects = 0;
+ pixman_region32_fini(rgn);
+ pixman_region32_init(rgn);
}
void region_destroy(QRegion *rgn)
{
- ASSERT(REGION_IS_VALID(rgn));
- if (rgn->rects != rgn->buf) {
- free(rgn->rects);
- }
+ pixman_region32_fini(rgn);
}
void region_clone(QRegion *dest, const QRegion *src)
{
- ASSERT(REGION_IS_VALID(src));
- dest->bbox = src->bbox;
- if ((dest->num_rects = src->num_rects) <= RECTS_BUF_SIZE) {
- dest->rects = dest->buf;
- dest->rects_size = RECTS_BUF_SIZE;
- } else {
- dest->rects = (SpiceRect *)malloc(sizeof(SpiceRect) * dest->num_rects);
- dest->rects_size = dest->num_rects;
- }
- memcpy(dest->rects, src->rects, dest->num_rects * sizeof(SpiceRect));
- ASSERT(REGION_IS_VALID(src));
- ASSERT(REGION_IS_VALID(dest));
+ pixman_region32_init(dest);
+ pixman_region32_copy(dest, (pixman_region32_t *)src);
}
-int region_is_valid(const QRegion *rgn)
+#define FIND_BAND(r, r_band_end, r_end, ry1) \
+ do { \
+ ry1 = r->y1; \
+ r_band_end = r + 1; \
+ while ((r_band_end != r_end) && (r_band_end->y1 == ry1)) { \
+ r_band_end++; \
+ } \
+ } while (0)
+
+static int test_band(int query,
+ int res,
+ pixman_box32_t *r1,
+ pixman_box32_t *r1_end,
+ pixman_box32_t *r2,
+ pixman_box32_t *r2_end)
{
- if (rgn->num_rects) {
- uint32_t i;
- SpiceRect bbox;
+ int x1;
+ int x2;
- if (!rect_is_valid(&rgn->bbox)) {
- return FALSE;
- }
- bbox = rgn->rects[0];
- if (!rect_is_valid(&bbox) || rect_is_empty(&bbox)) {
- return FALSE;
- }
- for (i = 1; i < rgn->num_rects; i++) {
- SpiceRect *r;
+ do {
+ x1 = MAX(r1->x1, r2->x1);
+ x2 = MIN(r1->x2, r2->x2);
+
+ /*
+ * Is there any overlap between the two rectangles?
+ */
+ if (x1 < x2) {
+ res |= REGION_TEST_SHARED;
- r = &rgn->rects[i];
- if (!rect_is_valid(r) || rect_is_empty(r)) {
- return FALSE;
+ if (r1->x1 < r2->x1 || r1->x2 > r2->x2) {
+ res |= REGION_TEST_LEFT_EXCLUSIVE;
}
- SpiceRect *priv = r - 1;
- if (r->top < priv->top) {
- return FALSE;
- } else if (r->top == priv->top) {
- if (r->bottom != priv->bottom) {
- return FALSE;
- }
- if (r->left < priv->right) {
- return FALSE;
- }
- } else if (priv->bottom > r->top) {
- return FALSE;
+ if (r2->x1 < r1->x1 || r2->x2 > r1->x2) {
+ res |= REGION_TEST_RIGHT_EXCLUSIVE;
+ }
+ } else {
+ /* No overlap at all, the leftmost is exclusive */
+ if (r1->x1 < r2->x1) {
+ res |= REGION_TEST_LEFT_EXCLUSIVE;
+ } else {
+ res |= REGION_TEST_RIGHT_EXCLUSIVE;
}
- bbox.top = MIN(bbox.top, r->top);
- bbox.left = MIN(bbox.left, r->left);
- bbox.bottom = MAX(bbox.bottom, r->bottom);
- bbox.right = MAX(bbox.right, r->right);
}
- return rect_is_equal(&bbox, &rgn->bbox);
- }
- return TRUE;
-}
-
-void region_dump(const QRegion *rgn, const char *prefix)
-{
- char *indent;
- int len;
- uint32_t i;
-
- len = strlen(prefix);
- if (!(indent = (char *)malloc(len + 1))) {
- printf("%s: malloc failed\n", __FUNCTION__);
- return;
- }
- memset(indent, ' ', len);
- indent[len] = 0;
+ if ((res & query) == query) {
+ return res;
+ }
- printf("%sREGION: %p, size %u storage is %s, ",
- prefix,
- rgn,
- rgn->rects_size,
- (rgn->rects == rgn->buf) ? "BUF" : "MALLOC");
+ /*
+ * Advance the pointer(s) with the leftmost right side, since the next
+ * rectangle on that list may still overlap the other region's
+ * current rectangle.
+ */
+ if (r1->x2 == x2) {
+ r1++;
+ }
+ if (r2->x2 == x2) {
+ r2++;
+ }
+ } while ((r1 != r1_end) && (r2 != r2_end));
+
+ /*
+ * Deal with whichever band (if any) still has rectangles left.
+ */
+ if (r1 != r1_end) {
+ res |= REGION_TEST_LEFT_EXCLUSIVE;
+ } else if (r2 != r2_end) {
+ res |= REGION_TEST_RIGHT_EXCLUSIVE;
+ }
+
+ return res;
+}
+
+static int test_generic (pixman_region32_t *reg1,
+ pixman_region32_t *reg2,
+ int query)
+{
+ pixman_box32_t *r1; /* Pointer into first region */
+ pixman_box32_t *r2; /* Pointer into 2d region */
+ pixman_box32_t *r1_end; /* End of 1st region */
+ pixman_box32_t *r2_end; /* End of 2d region */
+ int ybot; /* Bottom of intersection */
+ int ytop; /* Top of intersection */
+ pixman_box32_t * r1_band_end; /* End of current band in r1 */
+ pixman_box32_t * r2_band_end; /* End of current band in r2 */
+ int top; /* Top of non-overlapping band */
+ int bot; /* Bottom of non-overlapping band*/
+ int r1y1; /* Temps for r1->y1 and r2->y1 */
+ int r2y1;
+ int r1_num_rects;
+ int r2_num_rects;
+ int res;
+
+ r1 = pixman_region32_rectangles(reg1, &r1_num_rects);
+ r1_end = r1 + r1_num_rects;
+
+ r2 = pixman_region32_rectangles(reg2, &r2_num_rects);
+ r2_end = r2 + r2_num_rects;
+
+ res = 0;
+
+ /*
+ * Initialize ybot.
+ * In the upcoming loop, ybot and ytop serve different functions depending
+ * on whether the band being handled is an overlapping or non-overlapping
+ * band.
+ * In the case of a non-overlapping band (only one of the regions
+ * has points in the band), ybot is the bottom of the most recent
+ * intersection and thus clips the top of the rectangles in that band.
+ * ytop is the top of the next intersection between the two regions and
+ * serves to clip the bottom of the rectangles in the current band.
+ * For an overlapping band (where the two regions intersect), ytop clips
+ * the top of the rectangles of both regions and ybot clips the bottoms.
+ */
+
+ ybot = MIN(r1->y1, r2->y1);
- if (rgn->num_rects == 0) {
- printf("EMPTY\n");
- return;
- }
+ do {
+ /*
+ * This algorithm proceeds one source-band (as opposed to a
+ * destination band, which is determined by where the two regions
+ * intersect) at a time. r1_band_end and r2_band_end serve to mark the
+ * rectangle after the last one in the current band for their
+ * respective regions.
+ */
+ FIND_BAND(r1, r1_band_end, r1_end, r1y1);
+ FIND_BAND(r2, r2_band_end, r2_end, r2y1);
+
+ /*
+ * First handle the band that doesn't intersect, if any.
+ *
+ * Note that attention is restricted to one band in the
+ * non-intersecting region at once, so if a region has n
+ * bands between the current position and the next place it overlaps
+ * the other, this entire loop will be passed through n times.
+ */
+ if (r1y1 < r2y1) {
+ top = MAX (r1y1, ybot);
+ bot = MIN (r1->y2, r2y1);
+ if (top != bot) {
+ res |= REGION_TEST_LEFT_EXCLUSIVE;
+
+ if ((res & query) == query) {
+ return res & query;
+ }
+ }
- printf("num %u bounds (%d, %d, %d, %d)\n",
- rgn->num_rects,
- rgn->bbox.top,
- rgn->bbox.left,
- rgn->bbox.bottom,
- rgn->bbox.right);
-
- for (i = 0; i < rgn->num_rects; i++) {
- printf("%s %12d %12d %12d %12d\n",
- indent,
- rgn->rects[i].top,
- rgn->rects[i].left,
- rgn->rects[i].bottom,
- rgn->rects[i].right);
- }
- free(indent);
- ASSERT(region_is_valid(rgn));
-}
+ ytop = r2y1;
+ } else if (r2y1 < r1y1) {
+ top = MAX (r2y1, ybot);
+ bot = MIN (r2->y2, r1y1);
-int region_is_empty(const QRegion *rgn)
-{
- ASSERT(REGION_IS_VALID(rgn));
- return !rgn->num_rects;
-}
+ if (top != bot) {
+ res |= REGION_TEST_RIGHT_EXCLUSIVE;
-#ifdef REGION_USE_IMPROVED
+ if ((res & query) == query) {
+ return res & query;
+ }
+ }
+ ytop = r1y1;
+ } else {
+ ytop = r1y1;
+ }
-int region_is_equal(const QRegion *rgn1, const QRegion *rgn2)
-{
- int test_res;
+ /*
+ * Now see if we've hit an intersecting band. The two bands only
+ * intersect if ybot > ytop
+ */
+ ybot = MIN (r1->y2, r2->y2);
+ if (ybot > ytop) {
+ res = test_band(query, res,
+ r1, r1_band_end,
+ r2, r2_band_end);
+ if ((res & query) == query) {
+ return res & query;
+ }
+ }
- ASSERT(REGION_IS_VALID(rgn1));
- ASSERT(REGION_IS_VALID(rgn2));
+ /*
+ * If we've finished with a band (y2 == ybot) we skip forward
+ * in the region to the next band.
+ */
+ if (r1->y2 == ybot) {
+ r1 = r1_band_end;
+ }
- if (rgn1->num_rects == 0 || rgn2->num_rects == 0) {
- return rgn1->num_rects == rgn2->num_rects;
- }
+ if (r2->y2 == ybot) {
+ r2 = r2_band_end;
+ }
- if (!rect_is_equal(&rgn1->bbox, &rgn2->bbox)) {
- return FALSE;
}
+ while (r1 != r1_end && r2 != r2_end);
- test_res = region_test(rgn1, rgn2, REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE);
- return !test_res;
-}
-
-#else
-
-int region_is_equal(const QRegion *rgn1, const QRegion *rgn2)
-{
- QRegion tmp_rgn;
- int ret;
-
- ASSERT(REGION_IS_VALID(rgn1));
- ASSERT(REGION_IS_VALID(rgn2));
+ /*
+ * Deal with whichever region (if any) still has rectangles left.
+ */
- if (rgn1->num_rects == 0 || rgn2->num_rects == 0) {
- return rgn1->num_rects == rgn2->num_rects;
+ if (r1 != r1_end) {
+ res |= REGION_TEST_LEFT_EXCLUSIVE;
+ } else if (r2 != r2_end) {
+ res |= REGION_TEST_RIGHT_EXCLUSIVE;
}
- if (!rect_is_equal(&rgn1->bbox, &rgn2->bbox)) {
- return FALSE;
- }
-
- region_clone(&tmp_rgn, rgn1);
- region_xor(&tmp_rgn, rgn2);
- ret = region_is_empty(&tmp_rgn);
- region_destroy(&tmp_rgn);
- return ret;
+ return res & query;
}
-#endif
-
-typedef struct RgnOpCtx {
- SpiceRect *now;
- SpiceRect *end;
- SpiceRect *scan_line;
- SpiceRect r;
- SpiceRect split;
-#ifdef REGION_USE_IMPROVED
- int abort;
-#endif
-} RgnOpCtx;
-
-static inline int op_ctx_is_valid(RgnOpCtx *ctx)
+int region_test(const QRegion *_reg1, const QRegion *_reg2, int query)
{
- return ctx->now != ctx->end;
-}
+ int res;
+ pixman_region32_t *reg1 = (pixman_region32_t *)_reg1;
+ pixman_region32_t *reg2 = (pixman_region32_t *)_reg2;
-static void op_context_next(RgnOpCtx *ctx)
-{
- SpiceRect *now;
- SpiceRect *next;
-
- ASSERT(op_ctx_is_valid(ctx));
- now = ctx->now;
- next = now + 1;
-
- if (next == ctx->end || now->top != next->top) {
- if (now->bottom != ctx->r.bottom) { //h_split
- ctx->r.top = ctx->r.bottom;
- ctx->r.bottom = now->bottom;
- next = ctx->scan_line;
- } else {
- if (next == ctx->end) {
-#ifdef REGION_USE_IMPROVED
- ctx->scan_line = ++ctx->now;
-#else
- ++ctx->now;
-#endif
- ctx->r.top = ctx->r.left = ctx->r.bottom = ctx->r.right = (1U << 31) - 1;
- return;
- }
- ctx->scan_line = next;
- ctx->r.top = next->top;
- ctx->r.bottom = next->bottom;
- }
- }
- ctx->r.left = next->left;
- ctx->r.right = next->right;
- ctx->now = next;
-}
+ query = (query) ? query & REGION_TEST_ALL : REGION_TEST_ALL;
-static void op_context_init(RgnOpCtx *ctx, uint32_t num_rects, SpiceRect *rects)
-{
- ctx->scan_line = ctx->now = rects;
- ctx->end = ctx->now + num_rects;
-#ifdef REGION_USE_IMPROVED
- ctx->abort = FALSE;
-#endif
- if (!op_ctx_is_valid(ctx)) {
- ctx->r.top = ctx->r.left = ctx->r.bottom = ctx->r.right = (1U << 31) - 1;
- } else {
- ctx->r = *ctx->now;
- }
-}
+ res = 0;
-static inline void op_ctx_h_split(RgnOpCtx *ctx, int32_t h_line)
-{
- ctx->r.bottom = h_line;
- ctx->split = ctx->r;
- op_context_next(ctx);
-}
-
-static inline void op_ctx_v_split(RgnOpCtx *ctx, int32_t v_line)
-{
- ctx->split = ctx->r;
- ctx->r.left = ctx->split.right = v_line;
- if (rect_is_empty(&ctx->r)) {
- op_context_next(ctx);
- }
-}
+ if (!pixman_region32_not_empty(reg1) || !pixman_region32_not_empty(reg2) ||
+ !EXTENTCHECK (&reg1->extents, &reg2->extents)) {
+ /* One or more regions are empty or they are disjoint */
-static inline void op_ctx_split(RgnOpCtx *ctx, int32_t h_line)
-{
- ASSERT(ctx->now == ctx->scan_line);
- ctx->r.bottom = h_line;
-}
-
-static void region_steal_rects(QRegion *rgn, uint32_t *num_rects, SpiceRect **rects)
-{
- ASSERT(REGION_IS_VALID(rgn));
- if ((*num_rects = rgn->num_rects)) {
- if (rgn->rects == rgn->buf) {
- *rects = (SpiceRect *)malloc(sizeof(SpiceRect) * rgn->num_rects);
- memcpy(*rects, rgn->rects, sizeof(SpiceRect) * rgn->num_rects);
- } else {
- *rects = rgn->rects;
-#ifdef ALLOC_ON_STEAL
- rgn->rects = (SpiceRect *)malloc(sizeof(SpiceRect) * rgn->num_rects);
- rgn->rects_size = rgn->num_rects;
- rgn->num_rects = 0;
- return;
-#endif
+ if (pixman_region32_not_empty(reg1)) {
+ res |= REGION_TEST_LEFT_EXCLUSIVE;
}
- } else {
- *rects = NULL;
- }
- __region_init(rgn);
- ASSERT(REGION_IS_VALID(rgn));
-}
-typedef struct JoinContext {
- QRegion *rgn;
- SpiceRect *line0;
- SpiceRect *line1;
- SpiceRect *end;
-} JoinContext;
+ if (pixman_region32_not_empty(reg2)) {
+ res |= REGION_TEST_RIGHT_EXCLUSIVE;
+ }
-static inline SpiceRect *__get_line(QRegion *rgn, SpiceRect *pos)
-{
- SpiceRect *end = rgn->rects + rgn->num_rects;
+ return res & query;
+ } else if (!reg1->data && !reg2->data) {
+ /* Just two rectangles that intersect */
+ res |= REGION_TEST_SHARED;
- if (pos < end) {
- int32_t line_top = pos->top;
- while (++pos < end && pos->top == line_top) {
- ASSERT((pos - 1)->right < pos->left); //join in region_push_rect
+ if (!SUBSUMES(&reg1->extents, &reg2->extents)) {
+ res |= REGION_TEST_RIGHT_EXCLUSIVE;
}
- }
- return pos;
-}
-static inline int region_join_init(QRegion *rgn, JoinContext *context)
-{
- context->rgn = rgn;
- context->end = __get_line(rgn, (context->line1 = rgn->rects));
- return context->end != context->line1;
-}
+ if (!SUBSUMES(&reg2->extents, &reg1->extents)) {
+ res |= REGION_TEST_LEFT_EXCLUSIVE;
+ }
-static inline int region_join_next(JoinContext *context)
-{
- context->line0 = context->line1;
- context->line1 = context->end;
- context->end = __get_line(context->rgn, context->line1);
- return context->end != context->line1;
-}
+ return res & query;
+ } else if (!reg2->data && SUBSUMES (&reg2->extents, &reg1->extents)) {
+ /* reg2 is just a rect that contains all of reg1 */
-static inline void region_join_join(JoinContext *context)
-{
- SpiceRect *pos_0 = context->line0;
- SpiceRect *pos_1 = context->line1;
- int32_t bottom;
- QRegion *rgn;
+ res |= REGION_TEST_SHARED; /* some piece must be shared, because reg is not empty */
+ res |= REGION_TEST_RIGHT_EXCLUSIVE; /* reg2 contains all of reg1 and then some */
- if (pos_0->bottom != pos_1->top) {
- return;
- }
+ return res & query;
+ } else if (!reg1->data && SUBSUMES (&reg1->extents, &reg2->extents)) {
+ /* reg1 is just a rect that contains all of reg2 */
- if (pos_1 - pos_0 != context->end - pos_1) {
- return;
- }
+ res |= REGION_TEST_SHARED; /* some piece must be shared, because reg is not empty */
+ res |= REGION_TEST_LEFT_EXCLUSIVE; /* reg1 contains all of reg2 and then some */
- for (; pos_1 < context->end; pos_0++, pos_1++) {
- if (pos_0->left != pos_1->left || pos_0->right != pos_1->right) {
- return;
- }
- }
- bottom = context->line1->bottom;
- pos_0 = context->line0;
- for (; pos_0 < context->line1; pos_0++) {
- pos_0->bottom = bottom;
+ return res & query;
+ } else if (reg1 == reg2) {
+ res |= REGION_TEST_SHARED;
+ return res & query;
+ } else {
+ /* General purpose intersection */
+ return test_generic (reg1, reg2, query);
}
- rgn = context->rgn;
- memmove(context->line1, context->end,
- (unsigned long)(rgn->rects + rgn->num_rects) - (unsigned long)context->end);
- rgn->num_rects -= (context->line1 - context->line0);
- context->end = context->line1;
- context->line1 = context->line0;
}
-static inline void region_join(QRegion *rgn)
+int region_is_valid(const QRegion *rgn)
{
- JoinContext context;
-
- ASSERT(REGION_IS_VALID(rgn));
-
- if (!region_join_init(rgn, &context)) {
- return;
- }
- while (region_join_next(&context)) {
- region_join_join(&context);
- }
-
- ASSERT(REGION_IS_VALID(rgn));
+ return pixman_region32_selfcheck((pixman_region32_t *)rgn);
}
-static void region_push_rect(QRegion *rgn, SpiceRect *r)
+int region_is_empty(const QRegion *rgn)
{
- ASSERT(REGION_IS_VALID(rgn));
- ASSERT(rect_is_valid(r));
- if (rgn->num_rects == 0) {
- rgn->num_rects++;
- rgn->rects[0] = rgn->bbox = *r;
- return;
- } else {
- SpiceRect *priv = &rgn->rects[rgn->num_rects - 1];
-
- if (priv->top == r->top && priv->right == r->left) {
- ASSERT(priv->bottom == r->bottom);
- priv->right = r->right;
- rgn->bbox.right = MAX(rgn->bbox.right, priv->right);
- return;
- }
- if (rgn->rects_size == rgn->num_rects) {
- SpiceRect *old = rgn->rects;
- rgn->rects_size = rgn->rects_size * 2;
- rgn->rects = (SpiceRect *)malloc(sizeof(SpiceRect) * rgn->rects_size);
- memcpy(rgn->rects, old, sizeof(SpiceRect) * rgn->num_rects);
- if (old != rgn->buf) {
- free(old);
- }
- }
- rgn->rects[rgn->num_rects++] = *r;
- rect_union(&rgn->bbox, r);
- }
+ return !pixman_region32_not_empty((pixman_region32_t *)rgn);
}
-#ifdef REGION_USE_IMPROVED
-
-static SpiceRect *op_context_find_area_below(RgnOpCtx *ctx, int32_t val)
+SpiceRect *region_dup_rects(const QRegion *rgn, uint32_t *num_rects)
{
- SpiceRect *start = ctx->now;
- SpiceRect *end = ctx->end;
+ pixman_box32_t *boxes;
+ SpiceRect *rects;
+ int n, i;
- while (start != end) {
- int pos = (end - start) / 2;
- if (start[pos].bottom <= val) {
- start = &start[pos + 1];
- } else {
- end = &start[pos];
- }
+ boxes = pixman_region32_rectangles((pixman_region32_t *)rgn, &n);
+ if (num_rects) {
+ *num_rects = n;
}
- return start;
-}
-
-static int op_context_skip_v(RgnOpCtx *ctx, int32_t top)
-{
- SpiceRect *end = op_context_find_area_below(ctx, top);
- if (end != ctx->now) {
- ctx->now = ctx->scan_line = end;
- if (ctx->now == ctx->end) {
- ctx->r.top = ctx->r.left = ctx->r.bottom = ctx->r.right = (1U << 31) - 1;
- } else {
- ctx->r = *ctx->now;
- }
- return TRUE;
+ rects = (SpiceRect *)malloc(sizeof(SpiceRect)*n);
+ for (i = 0; i < n; i++) {
+ rects[i].left = boxes[i].x1;
+ rects[i].top = boxes[i].y1;
+ rects[i].right = boxes[i].x2;
+ rects[i].bottom = boxes[i].y2;
}
- return FALSE;
+ return rects;
}
-typedef void (*op_callback_t)(RgnOpCtx *context, SpiceRect *, SpiceRect *);
-static void op_context_skip(RgnOpCtx *self, RgnOpCtx *other, op_callback_t on_self,
- op_callback_t on_other)
+int region_is_equal(const QRegion *rgn1, const QRegion *rgn2)
{
- SpiceRect *save1 = self->now;
- SpiceRect *save2 = other->now;
- int more;
- do {
- op_context_skip_v(self, other->r.top);
- if (save1 != self->now) {
- if (on_self) {
- on_self(self, save1, self->now);
- }
- save1 = self->now;
- }
- more = op_context_skip_v(other, self->r.top);
- if (save2 != other->now) {
- if (on_other) {
- on_other(self, save2, other->now);
- }
- save2 = other->now;
- }
- } while (more && !self->abort);
+ return pixman_region32_equal((pixman_region32_t *)rgn1, (pixman_region32_t *)rgn2);
}
-static inline int op_context_more_overlap(RgnOpCtx *ctx, int32_t *bottom)
+int region_intersects(const QRegion *rgn1, const QRegion *rgn2)
{
- if (!op_ctx_is_valid(ctx)) {
+ int test_res;
+
+ if (!region_bounds_intersects(rgn1, rgn2)) {
return FALSE;
}
- if (ctx->scan_line->bottom > *bottom && ctx->scan_line->top < *bottom) {
- *bottom = ctx->scan_line->bottom;
- }
- return ctx->scan_line->top < *bottom;
+ test_res = region_test(rgn1, rgn2, REGION_TEST_SHARED);
+ return !!test_res;
}
-static inline void op_context_overlap(RgnOpCtx *self, RgnOpCtx *other, op_callback_t on_self,
- op_callback_t on_other, op_callback_t on_both)
+int region_bounds_intersects(const QRegion *rgn1, const QRegion *rgn2)
{
- int32_t bottom = MAX(self->scan_line->bottom, other->scan_line->bottom);
+ pixman_box32_t *extents1, *extents2;
- do {
- if (self->r.top < other->r.top) {
- op_ctx_h_split(self, MIN(other->r.top, self->r.bottom));
- if (on_self) {
- on_self(self, &self->split, &self->split + 1);
- }
- } else if (self->r.top > other->r.top) {
- op_ctx_h_split(other, MIN(self->r.top, other->r.bottom));
- if (on_other) {
- on_other(self, &other->split, &other->split + 1);
- }
- } else {
- if (self->r.bottom > other->r.bottom) {
- op_ctx_split(self, other->r.bottom);
- } else if (other->r.bottom > self->r.bottom) {
- op_ctx_split(other, self->r.bottom);
- }
- if (self->r.left < other->r.left) {
- op_ctx_v_split(self, MIN(other->r.left, self->r.right));
- if (on_self) {
- on_self(self, &self->split, &self->split + 1);
- }
- } else if (self->r.left > other->r.left) {
- op_ctx_v_split(other, MIN(self->r.left, other->r.right));
- if (on_other) {
- on_other(self, &other->split, &other->split + 1);
- }
- } else {
- int32_t right = MIN(self->r.right, other->r.right);
- op_ctx_v_split(self, right);
- op_ctx_v_split(other, right);
- if (on_both) {
- on_both(self, &self->split, &self->split + 1);
- }
- }
- }
- } while (!self->abort && (op_context_more_overlap(self, &bottom) ||
- op_context_more_overlap(other, &bottom)));
-}
+ extents1 = pixman_region32_extents((pixman_region32_t *)rgn1);
+ extents2 = pixman_region32_extents((pixman_region32_t *)rgn1);
-static inline void op_context_op(RgnOpCtx *self, RgnOpCtx *other, op_callback_t on_self,
- op_callback_t on_other, op_callback_t on_both)
-{
- for (;;) {
- op_context_skip(self, other, on_self, on_other);
- if (self->abort || !op_ctx_is_valid(self)) {
- ASSERT(self->abort || !op_ctx_is_valid(other));
- return;
- }
- op_context_overlap(self, other, on_self, on_other, on_both);
- }
+ return EXTENTCHECK(extents1, extents2);
}
-typedef struct SelfOpCtx {
- RgnOpCtx ctx;
- QRegion *rgn;
-} SelfOpCtx;
-
-static void add_rects(RgnOpCtx *ctx, SpiceRect *now, SpiceRect *end)
+int region_contains(const QRegion *rgn, const QRegion *other)
{
- SelfOpCtx *self_ctx = (SelfOpCtx *)ctx;
- for (; now < end; now++) {
- region_push_rect(self_ctx->rgn, now);
- }
+ int test_res;
+
+ test_res = region_test(rgn, other, REGION_TEST_RIGHT_EXCLUSIVE);
+ return !test_res;
}
-static void region_op(QRegion *rgn, const QRegion *other_rgn, op_callback_t on_self,
- op_callback_t on_other, op_callback_t on_both)
+int region_contains_point(const QRegion *rgn, int32_t x, int32_t y)
{
- SelfOpCtx self;
- RgnOpCtx other;
- uint32_t num_rects;
- SpiceRect *rects;
-
- region_steal_rects(rgn, &num_rects, &rects);
- op_context_init(&self.ctx, num_rects, rects);
- self.rgn = rgn;
- op_context_init(&other, other_rgn->num_rects, other_rgn->rects);
- op_context_op(&self.ctx, &other, on_self, on_other, on_both);
- free(rects);
- region_join(rgn);
+ return pixman_region32_contains_point((pixman_region32_t *)rgn, x, y, NULL);
}
void region_or(QRegion *rgn, const QRegion *other_rgn)
{
- region_op(rgn, other_rgn, add_rects, add_rects, add_rects);
+ pixman_region32_union(rgn, rgn, (pixman_region32_t *)other_rgn);
}
void region_and(QRegion *rgn, const QRegion *other_rgn)
{
- if (!region_bounds_intersects(rgn, other_rgn)) {
- region_clear(rgn);
- return;
- }
- region_op(rgn, other_rgn, NULL, NULL, add_rects);
+ pixman_region32_intersect(rgn, rgn, (pixman_region32_t *)other_rgn);
}
void region_xor(QRegion *rgn, const QRegion *other_rgn)
{
- region_op(rgn, other_rgn, add_rects, add_rects, NULL);
-}
+ pixman_region32_t intersection;
-void region_exclude(QRegion *rgn, const QRegion *other_rgn)
-{
- if (!region_bounds_intersects(rgn, other_rgn)) {
- return;
- }
- region_op(rgn, other_rgn, add_rects, NULL, NULL);
+ pixman_region32_copy(&intersection, rgn);
+ pixman_region32_intersect(&intersection,
+ &intersection,
+ (pixman_region32_t *)other_rgn);
+ pixman_region32_union(rgn, rgn, (pixman_region32_t *)other_rgn);
+ pixman_region32_subtract(rgn, rgn, &intersection);
+ pixman_region32_fini(&intersection);
}
-typedef struct TestOpCtx {
- RgnOpCtx ctx;
- int result;
- int abort_on;
-} TestOpCtx;
-
-
-static void region_test_on_self(RgnOpCtx *ctx, SpiceRect *now, SpiceRect *end)
+void region_exclude(QRegion *rgn, const QRegion *other_rgn)
{
- TestOpCtx *test_ctx = (TestOpCtx *)ctx;
- test_ctx->result |= REGION_TEST_LEFT_EXCLUSIVE;
- test_ctx->result &= test_ctx->abort_on;
- if (test_ctx->result == test_ctx->abort_on) {
- test_ctx->ctx.abort = TRUE;
- }
+ pixman_region32_subtract(rgn, rgn, (pixman_region32_t *)other_rgn);
}
-static void region_test_on_other(RgnOpCtx *ctx, SpiceRect *now, SpiceRect *end)
+void region_add(QRegion *rgn, const SpiceRect *r)
{
- TestOpCtx *test_ctx = (TestOpCtx *)ctx;
- test_ctx->result |= REGION_TEST_RIGHT_EXCLUSIVE;
- test_ctx->result &= test_ctx->abort_on;
- if (test_ctx->result == test_ctx->abort_on) {
- test_ctx->ctx.abort = TRUE;
- }
+ pixman_region32_union_rect(rgn, rgn, r->left, r->top,
+ r->right - r->left,
+ r->bottom - r->top);
}
-static void region_test_on_both(RgnOpCtx *ctx, SpiceRect *now, SpiceRect *end)
+void region_remove(QRegion *rgn, const SpiceRect *r)
{
- TestOpCtx *test_ctx = (TestOpCtx *)ctx;
- test_ctx->result |= REGION_TEST_SHARED;
- test_ctx->result &= test_ctx->abort_on;
- if (test_ctx->result == test_ctx->abort_on) {
- test_ctx->ctx.abort = TRUE;
- }
-}
+ pixman_region32_t rg;
-int region_test(const QRegion *rgn, const QRegion *other_rgn, int query)
-{
- TestOpCtx self;
- RgnOpCtx other;
-
- op_context_init(&self.ctx, rgn->num_rects, rgn->rects);
- self.result = 0;
- self.abort_on = (query) ? query & REGION_TEST_ALL : REGION_TEST_ALL;
- op_context_init(&other, other_rgn->num_rects, other_rgn->rects);
- op_context_op(&self.ctx, &other, region_test_on_self, region_test_on_other,
- region_test_on_both);
- return self.result;
+ pixman_region32_init_rect(&rg, r->left, r->top,
+ r->right - r->left,
+ r->bottom - r->top);
+ pixman_region32_subtract(rgn, rgn, &rg);
+ pixman_region32_fini(&rg);
}
-#else
-
-#define RIGION_OP_ADD_SELF (1 << 0)
-#define RIGION_OP_ADD_OTHER (1 << 1)
-#define RIGION_OP_ADD_COMMON (1 << 2)
-static inline void region_on_self(QRegion *rgn, SpiceRect *r, uint32_t op)
+void region_offset(QRegion *rgn, int32_t dx, int32_t dy)
{
- ASSERT(REGION_IS_VALID(rgn));
- if (op & RIGION_OP_ADD_SELF) {
- region_push_rect(rgn, r);
- }
+ pixman_region32_translate(rgn, dx, dy);
}
-static inline void region_on_other(QRegion *rgn, SpiceRect *r, uint32_t op)
+void region_dump(const QRegion *rgn, const char *prefix)
{
- ASSERT(REGION_IS_VALID(rgn));
- if (op & RIGION_OP_ADD_OTHER) {
- region_push_rect(rgn, r);
- }
-}
+ pixman_box32_t *rects, *extents;
+ int n_rects, i;
-static inline void region_on_both(QRegion *rgn, SpiceRect *r, uint32_t op)
-{
- ASSERT(REGION_IS_VALID(rgn));
- if (op & RIGION_OP_ADD_COMMON) {
- region_push_rect(rgn, r);
- }
-}
+ printf("%sREGION: %p, ", prefix, rgn);
-static void region_op(QRegion *rgn, const QRegion *other_rgn, uint32_t op)
-{
- RgnOpCtx self;
- RgnOpCtx other;
- uint32_t num_rects;
- SpiceRect *rects;
+ if (!pixman_region32_not_empty((pixman_region32_t *)rgn)) {
+ printf("EMPTY\n");
+ return;
+ }
- ASSERT(REGION_IS_VALID(rgn));
- ASSERT(REGION_IS_VALID(other_rgn));
- region_steal_rects(rgn, &num_rects, &rects);
+ extents = pixman_region32_extents((pixman_region32_t *)rgn);
+ rects = pixman_region32_rectangles((pixman_region32_t *)rgn, &n_rects);
+ printf("num %u bounds (%d, %d, %d, %d)\n",
+ n_rects,
+ extents->x1,
+ extents->y1,
+ extents->x2,
+ extents->y2);
- op_context_init(&self, num_rects, rects);
- op_context_init(&other, other_rgn->num_rects, other_rgn->rects);
- while (op_ctx_is_valid(&self) || op_ctx_is_valid(&other)) {
- if (self.r.top < other.r.top) {
- op_ctx_h_split(&self, MIN(other.r.top, self.r.bottom));
- region_on_self(rgn, &self.split, op);
- } else if (self.r.top > other.r.top) {
- op_ctx_h_split(&other, MIN(self.r.top, other.r.bottom));
- region_on_other(rgn, &other.split, op);
- } else {
- if (self.r.bottom > other.r.bottom) {
- op_ctx_split(&self, other.r.bottom);
- } else if (other.r.bottom > self.r.bottom) {
- op_ctx_split(&other, self.r.bottom);
- }
- if (self.r.left < other.r.left) {
- op_ctx_v_split(&self, MIN(other.r.left, self.r.right));
- region_on_self(rgn, &self.split, op);
- } else if (self.r.left > other.r.left) {
- op_ctx_v_split(&other, MIN(self.r.left, other.r.right));
- region_on_other(rgn, &other.split, op);
- } else {
- int32_t right = MIN(self.r.right, other.r.right);
- op_ctx_v_split(&self, right);
- op_ctx_v_split(&other, right);
- region_on_both(rgn, &self.split, op);
- }
- }
+ for (i = 0; i < n_rects; i++) {
+ printf("%*s %12d %12d %12d %12d\n",
+ (int)strlen(prefix), "",
+ rects[i].x1,
+ rects[i].y1,
+ rects[i].x2,
+ rects[i].y2);
}
- free(rects);
- region_join(rgn);
-}
-
-void region_or(QRegion *rgn, const QRegion *other_rgn)
-{
- region_op(rgn, other_rgn, RIGION_OP_ADD_SELF | RIGION_OP_ADD_OTHER | RIGION_OP_ADD_COMMON);
-}
-
-void region_and(QRegion *rgn, const QRegion *other_rgn)
-{
- region_op(rgn, other_rgn, RIGION_OP_ADD_COMMON);
}
-void region_xor(QRegion *rgn, const QRegion *other_rgn)
-{
- region_op(rgn, other_rgn, RIGION_OP_ADD_SELF | RIGION_OP_ADD_OTHER);
-}
+#ifdef REGION_TEST
-void region_exclude(QRegion *rgn, const QRegion *other_rgn)
+static int slow_region_test(const QRegion *rgn, const QRegion *other_rgn, int query)
{
- region_op(rgn, other_rgn, RIGION_OP_ADD_SELF);
-}
+ pixman_region32_t intersection;
+ int res;
-#endif
+ pixman_region32_init(&intersection);
+ pixman_region32_intersect(&intersection,
+ (pixman_region32_t *)rgn,
+ (pixman_region32_t *)other_rgn);
+ res = 0;
-void region_offset(QRegion *rgn, int32_t dx, int32_t dy)
-{
- SpiceRect *now;
- SpiceRect *end;
- ASSERT(REGION_IS_VALID(rgn));
- if (region_is_empty(rgn)) {
- return;
- }
- rect_offset(&rgn->bbox, dx, dy);
- now = rgn->rects;
- end = now + rgn->num_rects;
- for (; now < end; now++) {
- rect_offset(now, dx, dy);
+ if (query & REGION_TEST_SHARED &&
+ pixman_region32_not_empty(&intersection)) {
+ res |= REGION_TEST_SHARED;
}
-}
-void region_add(QRegion *rgn, const SpiceRect *r)
-{
- ASSERT(REGION_IS_VALID(rgn));
- ASSERT(rect_is_valid(r));
+ if (query & REGION_TEST_LEFT_EXCLUSIVE &&
+ !pixman_region32_equal(&intersection, (pixman_region32_t *)rgn)) {
+ res |= REGION_TEST_LEFT_EXCLUSIVE;
+ }
- if (!rgn->num_rects) {
- if (rect_is_empty(r)) {
- return;
- }
- rgn->num_rects++;
- rgn->rects[0] = rgn->bbox = *r;
- } else {
- QRegion rect_rgn;
- region_init(&rect_rgn);
- region_add(&rect_rgn, r);
- region_or(rgn, &rect_rgn);
+ if (query & REGION_TEST_RIGHT_EXCLUSIVE &&
+ !pixman_region32_equal(&intersection, (pixman_region32_t *)other_rgn)) {
+ res |= REGION_TEST_RIGHT_EXCLUSIVE;
}
-}
-void region_remove(QRegion *rgn, const SpiceRect *r)
-{
- ASSERT(REGION_IS_VALID(rgn));
- ASSERT(rect_is_valid(r));
- if (rgn->num_rects) {
- QRegion rect_rgn;
+ pixman_region32_fini(&intersection);
- region_init(&rect_rgn);
- region_add(&rect_rgn, r);
- region_exclude(rgn, &rect_rgn);
- }
+ return res;
}
-#ifdef REGION_USE_IMPROVED
-int region_intersects(const QRegion *rgn1, const QRegion *rgn2)
+static int rect_is_valid(const SpiceRect *r)
{
- int test_res;
-
- ASSERT(REGION_IS_VALID(rgn1));
- ASSERT(REGION_IS_VALID(rgn2));
-
- if (!region_bounds_intersects(rgn1, rgn2)) {
+ if (r->top > r->bottom || r->left > r->right) {
+ printf("%s: invalid rect\n", __FUNCTION__);
return FALSE;
}
-
- test_res = region_test(rgn1, rgn2, REGION_TEST_SHARED);
- return !!test_res;
-}
-
-#else
-
-int region_intersects(const QRegion *rgn1, const QRegion *rgn2)
-{
- QRegion tmp;
- int ret;
-
- ASSERT(REGION_IS_VALID(rgn1));
- ASSERT(REGION_IS_VALID(rgn2));
-
- region_clone(&tmp, rgn1);
- region_and(&tmp, rgn2);
- ret = !region_is_empty(&tmp);
- region_destroy(&tmp);
- return ret;
-}
-
-#endif
-
-int region_bounds_intersects(const QRegion *rgn1, const QRegion *rgn2)
-{
- return !region_is_empty(rgn1) && !region_is_empty(rgn2) &&
- rect_intersects(&rgn1->bbox, &rgn2->bbox);
-}
-
-#ifdef REGION_USE_IMPROVED
-
-int region_contains(const QRegion *rgn, const QRegion *other)
-{
- int test_res;
-
- ASSERT(REGION_IS_VALID(rgn));
- ASSERT(REGION_IS_VALID(other));
-
- test_res = region_test(rgn, other, REGION_TEST_RIGHT_EXCLUSIVE);
- return !test_res;
+ return TRUE;
}
-#else
-
-int region_contains(const QRegion *rgn, const QRegion *other)
+static void rect_set(SpiceRect *r, int32_t top, int32_t left, int32_t bottom, int32_t right)
{
- QRegion tmp;
- int ret;
-
- ASSERT(REGION_IS_VALID(rgn));
- ASSERT(REGION_IS_VALID(other));
-
- region_clone(&tmp, rgn);
- region_and(&tmp, other);
- ret = region_is_equal(&tmp, other);
- region_destroy(&tmp);
- return ret;
+ r->top = top;
+ r->left = left;
+ r->bottom = bottom;
+ r->right = right;
+ ASSERT(rect_is_valid(r));
}
-#endif
-
-int region_contains_point(const QRegion *rgn, int32_t x, int32_t y)
+static void random_region(QRegion *reg)
{
- if (region_is_empty(rgn)) {
- return FALSE;
- }
- SpiceRect point;
- point.left = x;
- point.right = point.left + 1;
- point.top = y;
- point.bottom = point.top + 1;
-
- if (!rect_intersects(&rgn->bbox, &point)) {
- return FALSE;
- }
+ int i;
+ int num_rects;
+ int x, y, w, h;
+ SpiceRect _r;
+ SpiceRect *r = &_r;
- SpiceRect* now = rgn->rects;
- SpiceRect* end = now + rgn->num_rects;
+ region_clear(reg);
- for (; now < end; now++) {
- if (rect_intersects(now, &point)) {
- return TRUE;
- }
+ num_rects = rand() % 20;
+ for (i = 0; i < num_rects; i++) {
+ x = rand()%100;
+ y = rand()%100;
+ w = rand()%100;
+ h = rand()%100;
+ rect_set(r,
+ x, y,
+ x+w, y+h);
+ region_add(reg, r);
}
- return FALSE;
}
-#ifdef REGION_TEST
-
static void test(const QRegion *r1, const QRegion *r2, int *expected)
{
printf("r1 is_empty %s [%s]\n",
@@ -993,6 +604,7 @@ int main(void)
SpiceRect _r;
SpiceRect *r = &_r;
int expected[5];
+ int i, j;
region_init(r1);
region_init(r2);
@@ -1218,6 +830,36 @@ int main(void)
test(r1, r3, expected);
printf("\n");
+ j = 0;
+ for (i = 0; i < 1000000; i++) {
+ int res1, res2, test;
+ int tests[] = {
+ REGION_TEST_LEFT_EXCLUSIVE,
+ REGION_TEST_RIGHT_EXCLUSIVE,
+ REGION_TEST_SHARED,
+ REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE,
+ REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_SHARED,
+ REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED,
+ REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED
+ };
+
+ random_region(r1);
+ random_region(r2);
+
+ for (test = 0; test < 7; test++) {
+ res1 = region_test(r1, r2, tests[test]);
+ res2 = slow_region_test(r1, r2, tests[test]);
+ if (res1 != res2) {
+ printf ("Error in region_test %d, got %d, expected %d, query=%d\n",
+ j, res1, res2, tests[test]);
+ printf ("r1:\n");
+ region_dump(r1, "");
+ printf ("r2:\n");
+ region_dump(r2, "");
+ }
+ j++;
+ }
+ }
region_destroy(r3);
region_destroy(r1);
diff --git a/common/region.h b/common/region.h
index f981ef3d..c0bf4087 100644
--- a/common/region.h
+++ b/common/region.h
@@ -21,20 +21,9 @@
#include <stdint.h>
#include <spice/draw.h>
+#include <pixman_utils.h>
-#define REGION_USE_IMPROVED
-
-#define RECTS_BUF_SIZE 4
-
-typedef struct QRegion {
- uint32_t num_rects;
- SpiceRect bbox;
- SpiceRect *rects;
- uint32_t rects_size;
- SpiceRect buf[RECTS_BUF_SIZE];
-} QRegion;
-
-#ifdef REGION_USE_IMPROVED
+typedef pixman_region32_t QRegion;
#define REGION_TEST_LEFT_EXCLUSIVE (1 << 0)
#define REGION_TEST_RIGHT_EXCLUSIVE (1 << 1)
@@ -42,16 +31,13 @@ typedef struct QRegion {
#define REGION_TEST_ALL \
(REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED)
-#endif
-
void region_init(QRegion *rgn);
void region_clear(QRegion *rgn);
void region_destroy(QRegion *rgn);
void region_clone(QRegion *dest, const QRegion *src);
+SpiceRect *region_dup_rects(const QRegion *rgn, uint32_t *num_rects);
-#ifdef REGION_USE_IMPROVED
int region_test(const QRegion *rgn, const QRegion *other_rgn, int query);
-#endif
int region_is_valid(const QRegion *rgn);
int region_is_empty(const QRegion *rgn);
int region_is_equal(const QRegion *rgn1, const QRegion *rgn2);
diff --git a/server/red_worker.c b/server/red_worker.c
index b2cb1f6e..fd0b20c2 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -427,7 +427,8 @@ typedef struct StreamClipItem {
int refs;
StreamAgent *stream_agent;
int clip_type;
- QRegion region;
+ SpiceRect *rects;
+ uint32_t n_rects;
} StreamClipItem;
typedef struct RedCompressBuf RedCompressBuf;
@@ -826,7 +827,8 @@ typedef struct UpgradeItem {
PipeItem base;
int refs;
Drawable *drawable;
- QRegion region;
+ SpiceRect *rects;
+ uint32_t n_rects;
} UpgradeItem;
typedef void (*draw_fill_t)(void *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceFill *fill);
@@ -843,7 +845,7 @@ typedef void (*draw_invers_t)(void *canvas, SpiceRect *bbox, SpiceClip *clip, Sp
typedef void (*draw_transparent_t)(void *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent);
typedef void (*draw_alpha_blend_t)(void *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlnd* alpha_blend);
typedef void (*read_pixels_t)(void *canvas, uint8_t *dest, int dest_stride, const SpiceRect *area);
-typedef void (*set_top_mask_t)(void *canvas, int num_rect, const SpiceRect *rects);
+typedef void (*set_top_mask_t)(void *canvas, QRegion *region);
typedef void (*clear_top_mask_t)(void *canvas);
typedef void (*validate_area_t)(void *canvas, int32_t stride, uint8_t *line_0, const SpiceRect *area);
typedef void (*destroy_t)(void *canvas);
@@ -1306,10 +1308,10 @@ static void show_draw_item(RedWorker *worker, DrawItem *draw_item, const char *p
}
printf("effect %d bbox(%d %d %d %d)\n",
draw_item->effect,
- draw_item->base.rgn.bbox.top,
- draw_item->base.rgn.bbox.left,
- draw_item->base.rgn.bbox.bottom,
- draw_item->base.rgn.bbox.right);
+ draw_item->base.rgn.extents.x1,
+ draw_item->base.rgn.extents.y1,
+ draw_item->base.rgn.extents.x2,
+ draw_item->base.rgn.extents.y2);
}
static inline void red_pipe_item_init(PipeItem *item, int type)
@@ -1428,7 +1430,7 @@ static void release_upgrade_item(RedWorker* worker, UpgradeItem *item)
{
if (!--item->refs) {
release_drawable(worker, item->drawable);
- region_destroy(&item->region);
+ free(item->rects);
free(item);
}
}
@@ -1904,13 +1906,13 @@ static inline void __exclude_region(RedWorker *worker, TreeItem *item, QRegion *
if (draw->shadow) {
Shadow *shadow;
- int32_t x = item->rgn.bbox.left;
- int32_t y = item->rgn.bbox.top;
+ int32_t x = item->rgn.extents.x1;
+ int32_t y = item->rgn.extents.y1;
region_exclude(&draw->base.rgn, &and_rgn);
shadow = draw->shadow;
- region_offset(&and_rgn, shadow->base.rgn.bbox.left - x,
- shadow->base.rgn.bbox.top - y);
+ region_offset(&and_rgn, shadow->base.rgn.extents.x1 - x,
+ shadow->base.rgn.extents.y1 - y);
region_exclude(&shadow->base.rgn, &and_rgn);
region_and(&and_rgn, &shadow->on_hold);
if (!region_is_empty(&and_rgn)) {
@@ -2295,11 +2297,13 @@ static void push_stream_clip_by_drawable(DisplayChannel* channel, StreamAgent *a
}
if (drawable->qxl_drawable->clip.type == SPICE_CLIP_TYPE_NONE) {
- region_init(&item->region);
+ item->n_rects = 0;
+ item->rects = NULL;
item->clip_type = SPICE_CLIP_TYPE_NONE;
} else {
item->clip_type = SPICE_CLIP_TYPE_RECTS;
- region_clone(&item->region, &drawable->tree_item.base.rgn);
+ item->rects = region_dup_rects(&drawable->tree_item.base.rgn,
+ &item->n_rects);
}
red_pipe_add((RedChannel*)channel, (PipeItem *)item);
}
@@ -2311,7 +2315,8 @@ static void push_stream_clip(DisplayChannel* channel, StreamAgent *agent)
PANIC("alloc failed");
}
item->clip_type = SPICE_CLIP_TYPE_RECTS;
- region_clone(&item->region, &agent->vis_region);
+ item->rects = region_dup_rects(&agent->vis_region,
+ &item->n_rects);
red_pipe_add((RedChannel*)channel, (PipeItem *)item);
}
@@ -2319,7 +2324,9 @@ static void red_display_release_stream_clip(DisplayChannel* channel, StreamClipI
{
if (!--item->refs) {
red_display_release_stream(channel, item->stream_agent);
- region_destroy(&item->region);
+ if (item->rects) {
+ free(item->rects);
+ }
free(item);
}
}
@@ -2387,7 +2394,8 @@ static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *strea
red_pipe_item_init(&upgrade_item->base, PIPE_ITEM_TYPE_UPGRADE);
upgrade_item->drawable = stream->current;
upgrade_item->drawable->refs++;
- region_clone(&upgrade_item->region, &upgrade_item->drawable->tree_item.base.rgn);
+ upgrade_item->rects = region_dup_rects(&upgrade_item->drawable->tree_item.base.rgn,
+ &upgrade_item->n_rects);
red_pipe_add((RedChannel *)channel, &upgrade_item->base);
}
red_detach_stream(worker, stream);
@@ -2404,7 +2412,8 @@ static inline void red_stop_stream_gracefully(RedWorker *worker, Stream *stream)
red_pipe_item_init(&item->base, PIPE_ITEM_TYPE_UPGRADE);
item->drawable = stream->current;
item->drawable->refs++;
- region_clone(&item->region, &item->drawable->tree_item.base.rgn);
+ item->rects = region_dup_rects(&item->drawable->tree_item.base.rgn,
+ &item->n_rects);
red_pipe_add((RedChannel *)worker->display_channel, &item->base);
}
}
@@ -4304,8 +4313,7 @@ static void red_draw_drawable(RedWorker *worker, Drawable *drawable)
#ifdef UPDATE_AREA_BY_TREE
//todo: add need top mask flag
worker->draw_funcs.set_top_mask(worker->surface.context.canvas,
- drawable->tree_item.base.rgn.num_rects,
- drawable->tree_item.base.rgn.rects);
+ &drawable->tree_item.base.rgn);
#endif
red_draw_qxl_drawable(worker, drawable);
#ifdef UPDATE_AREA_BY_TREE
@@ -6980,8 +6988,8 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
copy->base.box = qxl_drawable->bbox;
copy->base.clip.type = SPICE_CLIP_TYPE_RECTS;
copy->base.clip.data = channel->send_data.header.size;
- add_buf(channel, BUF_TYPE_RAW, &item->region.num_rects, sizeof(uint32_t), 0, 0);
- add_buf(channel, BUF_TYPE_RAW, item->region.rects, sizeof(SpiceRect) * item->region.num_rects, 0, 0);
+ add_buf(channel, BUF_TYPE_RAW, &item->n_rects, sizeof(uint32_t), 0, 0);
+ add_buf(channel, BUF_TYPE_RAW, item->rects, sizeof(SpiceRect) * item->n_rects, 0, 0);
copy->data = qxl_drawable->u.copy;
fill_bits(display_channel, &copy->data.src_bitmap, item->drawable);
@@ -7046,9 +7054,8 @@ static void red_display_send_stream_clip(DisplayChannel *display_channel,
} else {
ASSERT(stream_clip->clip.type == SPICE_CLIP_TYPE_RECTS);
stream_clip->clip.data = channel->send_data.header.size;
- add_buf(channel, BUF_TYPE_RAW, &item->region.num_rects, sizeof(uint32_t), 0, 0);
- add_buf(channel, BUF_TYPE_RAW, item->region.rects,
- item->region.num_rects * sizeof(SpiceRect), 0, 0);
+ add_buf(channel, BUF_TYPE_RAW, &item->n_rects, sizeof(uint32_t), 0, 0);
+ add_buf(channel, BUF_TYPE_RAW, item->rects, item->n_rects * sizeof(SpiceRect), 0, 0);
}
display_begin_send_massage(display_channel, item);
}