[Spice-devel] [PATCH 25/30] Replace custom region implementation with pixman_region32_t

Alexander Larsson alexl at redhat.com
Thu Feb 18 12:58:51 PST 2010


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.
---
 client/application.cpp      |   20 +-
 client/canvas.h             |    3 +-
 client/cursor_channel.cpp   |   14 +-
 client/gui/gui.cpp          |   26 +-
 client/red_cairo_canvas.cpp |   15 +-
 client/red_gl_canvas.cpp    |   16 +-
 client/screen.cpp           |   50 ++-
 client/screen_layer.cpp     |   21 +-
 client/x11/red_window.cpp   |    5 +-
 common/cairo_canvas.c       |   26 +-
 common/cairo_canvas.h       |    2 +-
 common/gl_canvas.c          |   35 ++-
 common/gl_canvas.h          |    2 +-
 common/region.c             |  942 ++++++-------------------------------------
 common/region.h             |   20 +-
 server/red_worker.c         |   42 ++-
 16 files changed, 328 insertions(+), 911 deletions(-)

diff --git a/client/application.cpp b/client/application.cpp
index cca7d43..0fa25b4 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 0878d2d..e3fe982 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 30c52d9..0909f5c 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 e4d69ee..0ff442e 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 80a89b7..c2496ff 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 43bf424..6598425 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 9e6b04e..40e0676 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 af25211..ef5ef95 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 49c5533..a38f7db 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 60fe2f4..9e61a4f 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -1071,11 +1071,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);
     }
@@ -1964,23 +1967,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,
+    /* Make sure we always clip to canvas size */
+    pixman_region32_init_rect (&canvas->canvas_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_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 485cf24..9bd65ff 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 b8d4843..4c3a110 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -163,6 +163,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;
@@ -705,14 +712,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);
 
@@ -732,15 +746,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 3f885a0..4339bc0 100644
--- a/common/gl_canvas.h
+++ b/common/gl_canvas.h
@@ -44,7 +44,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 f0bb614..e4d483a 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,926 +34,236 @@
     abort();                                                \
 }
 
-#ifdef REGION_DEBUG
-#define REGION_IS_VALID(region) region_is_valid(region)
-#else
-#define REGION_IS_VALID(region) TRUE
-#endif
-
-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;
-}
-
-#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;
-}
+/*  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) ) )
 
 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));
-}
-
-int region_is_valid(const QRegion *rgn)
-{
-    if (rgn->num_rects) {
-        uint32_t i;
-        SpiceRect bbox;
-
-        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;
-
-            r = &rgn->rects[i];
-            if (!rect_is_valid(r) || rect_is_empty(r)) {
-                return FALSE;
-            }
-
-            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;
-            }
-            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;
+    pixman_region32_init (dest);
+    pixman_region32_copy (dest, (pixman_region32_t *)src);
 }
 
-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;
-
-
-    printf("%sREGION: %p, size %u storage is %s, ",
-           prefix,
-           rgn,
-           rgn->rects_size,
-           (rgn->rects == rgn->buf) ? "BUF" : "MALLOC");
-
-    if (rgn->num_rects == 0) {
-        printf("EMPTY\n");
-        return;
-    }
-
-    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));
-}
-
-int region_is_empty(const QRegion *rgn)
-{
-    ASSERT(REGION_IS_VALID(rgn));
-    return !rgn->num_rects;
-}
-
-#ifdef REGION_USE_IMPROVED
-
-int region_is_equal(const QRegion *rgn1, const QRegion *rgn2)
-{
-    int test_res;
-
-    ASSERT(REGION_IS_VALID(rgn1));
-    ASSERT(REGION_IS_VALID(rgn2));
-
-    if (rgn1->num_rects == 0 || rgn2->num_rects == 0) {
-        return rgn1->num_rects == rgn2->num_rects;
-    }
-
-    if (!rect_is_equal(&rgn1->bbox, &rgn2->bbox)) {
-        return FALSE;
-    }
-
-    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)
+int region_test(const QRegion *rgn, const QRegion *other_rgn, int query)
 {
-    QRegion tmp_rgn;
-    int ret;
-
-    ASSERT(REGION_IS_VALID(rgn1));
-    ASSERT(REGION_IS_VALID(rgn2));
-
-    if (rgn1->num_rects == 0 || rgn2->num_rects == 0) {
-        return rgn1->num_rects == rgn2->num_rects;
-    }
+    pixman_region32_t intersection;
+    int res;
 
-    if (!rect_is_equal(&rgn1->bbox, &rgn2->bbox)) {
-        return FALSE;
-    }
+    pixman_region32_init (&intersection);
+    pixman_region32_intersect (&intersection,
+                               (pixman_region32_t *)rgn,
+                               (pixman_region32_t *)other_rgn);
 
-    region_clone(&tmp_rgn, rgn1);
-    region_xor(&tmp_rgn, rgn2);
-    ret = region_is_empty(&tmp_rgn);
-    region_destroy(&tmp_rgn);
-    return ret;
-}
+    res = 0;
 
-#endif
+    if (query & REGION_TEST_SHARED &&
+        pixman_region32_not_empty (&intersection))
+        res |= REGION_TEST_SHARED;
 
-typedef struct RgnOpCtx {
-    SpiceRect *now;
-    SpiceRect *end;
-    SpiceRect *scan_line;
-    SpiceRect r;
-    SpiceRect split;
-#ifdef REGION_USE_IMPROVED
-    int abort;
-#endif
-} RgnOpCtx;
+    if (query & REGION_TEST_LEFT_EXCLUSIVE &&
+        !pixman_region32_equal (&intersection, (pixman_region32_t *)rgn))
+        res |= REGION_TEST_LEFT_EXCLUSIVE;
 
-static inline int op_ctx_is_valid(RgnOpCtx *ctx)
-{
-    return ctx->now != ctx->end;
-}
+    if (query & REGION_TEST_RIGHT_EXCLUSIVE &&
+        !pixman_region32_equal (&intersection, (pixman_region32_t *)other_rgn))
+        res |= REGION_TEST_RIGHT_EXCLUSIVE;
 
-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;
-}
-
-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;
-    }
-}
-
-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);
+    return res;
 }
 
-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);
-    }
-}
-
-static inline void op_ctx_split(RgnOpCtx *ctx, int32_t h_line)
+int region_is_valid(const QRegion *rgn)
 {
-    ASSERT(ctx->now == ctx->scan_line);
-    ctx->r.bottom = h_line;
+    return pixman_region32_selfcheck((pixman_region32_t *)rgn);
 }
 
-static void region_steal_rects(QRegion *rgn, uint32_t *num_rects, SpiceRect **rects)
+int region_is_empty(const QRegion *rgn)
 {
-    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
-        }
-    } else {
-        *rects = NULL;
-    }
-    __region_init(rgn);
-    ASSERT(REGION_IS_VALID(rgn));
+    return !pixman_region32_not_empty ((pixman_region32_t *)rgn);
 }
 
-typedef struct JoinContext {
-    QRegion *rgn;
-    SpiceRect *line0;
-    SpiceRect *line1;
-    SpiceRect *end;
-} JoinContext;
-
-static inline SpiceRect *__get_line(QRegion *rgn, SpiceRect *pos)
+SpiceRect *region_dup_rects(const QRegion *rgn, int *num_rects)
 {
-    SpiceRect *end = rgn->rects + rgn->num_rects;
+    pixman_box32_t *boxes;
+    SpiceRect *rects;
+    int n, i;
 
-    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
-        }
+    boxes = pixman_region32_rectangles ((pixman_region32_t *)rgn, &n);
+    if (num_rects)
+        *num_rects = n;
+    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 pos;
+    return rects;
 }
 
-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;
-}
 
-static inline int region_join_next(JoinContext *context)
+int region_is_equal(const QRegion *rgn1, const QRegion *rgn2)
 {
-    context->line0 = context->line1;
-    context->line1 = context->end;
-    context->end = __get_line(context->rgn, context->line1);
-    return context->end != context->line1;
+    return pixman_region32_equal ((pixman_region32_t *)rgn1, (pixman_region32_t *)rgn2);
 }
 
-static inline void region_join_join(JoinContext *context)
-{
-    SpiceRect *pos_0 = context->line0;
-    SpiceRect *pos_1 = context->line1;
-    int32_t bottom;
-    QRegion *rgn;
-
-    if (pos_0->bottom != pos_1->top) {
-        return;
-    }
-
-    if (pos_1 - pos_0 != context->end - pos_1) {
-        return;
-    }
-
-    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;
-    }
-    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_intersects(const QRegion *rgn1, const QRegion *rgn2)
 {
-    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));
-}
+    int test_res;
 
-static void region_push_rect(QRegion *rgn, SpiceRect *r)
-{
-    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);
+    if (!region_bounds_intersects(rgn1, rgn2)) {
+        return FALSE;
     }
-}
-
-#ifdef REGION_USE_IMPROVED
 
-static SpiceRect *op_context_find_area_below(RgnOpCtx *ctx, int32_t val)
-{
-    SpiceRect *start = ctx->now;
-    SpiceRect *end = ctx->end;
-
-    while (start != end) {
-        int pos = (end - start) / 2;
-        if (start[pos].bottom <= val) {
-            start = &start[pos + 1];
-        } else {
-            end = &start[pos];
-        }
-    }
-    return start;
+    test_res = region_test(rgn1, rgn2, REGION_TEST_SHARED);
+    return !!test_res;
 }
 
-static int op_context_skip_v(RgnOpCtx *ctx, int32_t top)
+int region_bounds_intersects(const QRegion *rgn1, const QRegion *rgn2)
 {
-    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;
-    }
-    return FALSE;
-}
+    pixman_box32_t *extents1, *extents2;
 
-typedef void (*op_callback_t)(RgnOpCtx *context, SpiceRect *, SpiceRect *);
+    extents1 = pixman_region32_extents ((pixman_region32_t *)rgn1);
+    extents2 = pixman_region32_extents ((pixman_region32_t *)rgn1);
 
-static void op_context_skip(RgnOpCtx *self, RgnOpCtx *other, op_callback_t on_self,
-                            op_callback_t on_other)
-{
-    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 EXTENTCHECK(extents1, extents2);
 }
 
-static inline int op_context_more_overlap(RgnOpCtx *ctx, int32_t *bottom)
-{
-    if (!op_ctx_is_valid(ctx)) {
-        return FALSE;
-    }
-
-    if (ctx->scan_line->bottom > *bottom && ctx->scan_line->top < *bottom) {
-        *bottom = ctx->scan_line->bottom;
-    }
-    return ctx->scan_line->top < *bottom;
-}
-
-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)
-{
-    int32_t bottom = MAX(self->scan_line->bottom, other->scan_line->bottom);
-
-    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)));
-}
-
-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)
+int region_contains(const QRegion *rgn, const QRegion *other)
 {
-    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);
-    }
-}
-
-typedef struct SelfOpCtx {
-    RgnOpCtx ctx;
-    QRegion *rgn;
-} SelfOpCtx;
+    int test_res;
 
-static void add_rects(RgnOpCtx *ctx, SpiceRect *now, SpiceRect *end)
-{
-    SelfOpCtx *self_ctx = (SelfOpCtx *)ctx;
-    for (; now < end; now++) {
-        region_push_rect(self_ctx->rgn, now);
-    }
+    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);
-}
-
-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);
-}
-
-typedef struct TestOpCtx {
-    RgnOpCtx ctx;
-    int result;
-    int abort_on;
-} TestOpCtx;
-
+    pixman_region32_t intersection;
 
-static void region_test_on_self(RgnOpCtx *ctx, SpiceRect *now, SpiceRect *end)
-{
-    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_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);
 }
 
-static void region_test_on_other(RgnOpCtx *ctx, SpiceRect *now, SpiceRect *end)
-{
-    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;
-    }
-}
-
-static void region_test_on_both(RgnOpCtx *ctx, SpiceRect *now, SpiceRect *end)
-{
-    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;
-    }
-}
-
-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;
-}
-
-#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)
-{
-    ASSERT(REGION_IS_VALID(rgn));
-    if (op & RIGION_OP_ADD_SELF) {
-        region_push_rect(rgn, r);
-    }
-}
-
-static inline void region_on_other(QRegion *rgn, SpiceRect *r, uint32_t op)
+void region_exclude(QRegion *rgn, const QRegion *other_rgn)
 {
-    ASSERT(REGION_IS_VALID(rgn));
-    if (op & RIGION_OP_ADD_OTHER) {
-        region_push_rect(rgn, r);
-    }
+    pixman_region32_subtract (rgn, rgn, (pixman_region32_t *)other_rgn);
 }
 
-static inline void region_on_both(QRegion *rgn, SpiceRect *r, uint32_t op)
+void region_add(QRegion *rgn, const SpiceRect *r)
 {
-    ASSERT(REGION_IS_VALID(rgn));
-    if (op & RIGION_OP_ADD_COMMON) {
-        region_push_rect(rgn, r);
-    }
+    pixman_region32_union_rect (rgn, rgn, r->left, r->top,
+                                r->right - r->left,
+                                r->bottom - r->top);
 }
 
-static void region_op(QRegion *rgn, const QRegion *other_rgn, uint32_t op)
+void region_remove(QRegion *rgn, const SpiceRect *r)
 {
-    RgnOpCtx self;
-    RgnOpCtx other;
-    uint32_t num_rects;
-    SpiceRect *rects;
-
-    ASSERT(REGION_IS_VALID(rgn));
-    ASSERT(REGION_IS_VALID(other_rgn));
-    region_steal_rects(rgn, &num_rects, &rects);
-
-    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);
-            }
-        }
-    }
-    free(rects);
-    region_join(rgn);
-}
+    pixman_region32_t rg;
 
-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);
+    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);
 }
 
-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)
+void region_offset(QRegion *rgn, int32_t dx, int32_t dy)
 {
-    region_op(rgn, other_rgn, RIGION_OP_ADD_SELF | RIGION_OP_ADD_OTHER);
+    pixman_region32_translate (rgn, dx, dy);
 }
 
-void region_exclude(QRegion *rgn, const QRegion *other_rgn)
+void region_dump(const QRegion *rgn, const char *prefix)
 {
-    region_op(rgn, other_rgn, RIGION_OP_ADD_SELF);
-}
-
-#endif
+    pixman_box32_t *rects, *extents;
+    int n_rects, i;
 
+    printf("%sREGION: %p, ", prefix, rgn);
 
-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)) {
+    if (!pixman_region32_not_empty ((pixman_region32_t *)rgn)) {
+        printf("EMPTY\n");
         return;
     }
-    rect_offset(&rgn->bbox, dx, dy);
-    now = rgn->rects;
-    end = now + rgn->num_rects;
-    for (; now < end; now++) {
-        rect_offset(now, dx, dy);
-    }
-}
-
-void region_add(QRegion *rgn, const SpiceRect *r)
-{
-    ASSERT(REGION_IS_VALID(rgn));
-    ASSERT(rect_is_valid(r));
 
-    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);
-    }
-}
+    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);
 
-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;
 
-        region_init(&rect_rgn);
-        region_add(&rect_rgn, r);
-        region_exclude(rgn, &rect_rgn);
+    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);
     }
 }
 
-#ifdef REGION_USE_IMPROVED
+#ifdef REGION_TEST
 
-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;
-}
-
-#else
-
-int region_contains(const QRegion *rgn, const QRegion *other)
-{
-    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;
+    return TRUE;
 }
 
-#endif
-
-int region_contains_point(const QRegion *rgn, int32_t x, int32_t y)
+static void rect_set(SpiceRect *r, int32_t top, int32_t left, int32_t bottom, int32_t right)
 {
-    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;
-    }
-
-    SpiceRect* now = rgn->rects;
-    SpiceRect* end = now + rgn->num_rects;
-
-    for (; now < end; now++) {
-        if (rect_intersects(now, &point)) {
-            return TRUE;
-        }
-    }
-    return FALSE;
+    r->top = top;
+    r->left = left;
+    r->bottom = bottom;
+    r->right = right;
+    ASSERT(rect_is_valid(r));
 }
 
-#ifdef REGION_TEST
 
 static void test(const QRegion *r1, const QRegion *r2, int *expected)
 {
diff --git a/common/region.h b/common/region.h
index e685bfb..ce21498 100644
--- a/common/region.h
+++ b/common/region.h
@@ -20,20 +20,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)
@@ -41,16 +30,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, int *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 b2cb1f6..e875bd2 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -843,7 +843,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 +1306,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)
@@ -1904,13 +1904,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)) {
@@ -4304,8 +4304,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
@@ -6965,6 +6964,9 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
     RedChannel *channel;
     QXLDrawable *qxl_drawable;
     SpiceMsgDisplayDrawCopy *copy = &display_channel->send_data.u.copy;
+    SpiceRect *rects;
+    int num_rects;
+    uint32_t num_rects32;
 
     ASSERT(display_channel && item && item->drawable);
     channel = &display_channel->base;
@@ -6980,8 +6982,11 @@ 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);
+    rects = region_dup_rects(&item->region, &num_rects);
+    num_rects32 = num_rects;
+    add_buf(channel, BUF_TYPE_RAW, &num_rects32, sizeof(uint32_t), 0, 0);
+    add_buf(channel, BUF_TYPE_RAW, rects, sizeof(SpiceRect) * num_rects, 0, 0);
+    free(rects);
     copy->data = qxl_drawable->u.copy;
     fill_bits(display_channel, &copy->data.src_bitmap, item->drawable);
 
@@ -7034,6 +7039,9 @@ static void red_display_send_stream_clip(DisplayChannel *display_channel,
 
     StreamAgent *agent = item->stream_agent;
     Stream *stream = agent->stream;
+    SpiceRect *rects;
+    int num_rects;
+    uint32_t num_rects32;
 
     ASSERT(stream);
 
@@ -7046,9 +7054,11 @@ 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);
+	rects = region_dup_rects(&item->region, &num_rects);
+	num_rects32 = num_rects;
+        add_buf(channel, BUF_TYPE_RAW, &num_rects32, sizeof(uint32_t), 0, 0);
+        add_buf(channel, BUF_TYPE_RAW, rects, num_rects * sizeof(SpiceRect), 0, 0);
+	free(rects);
     }
     display_begin_send_massage(display_channel, item);
 }
-- 
1.6.6



More information about the Spice-devel mailing list