summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Chaplin <>2012-08-19 13:35:36 +0800
committerSteve Chaplin <>2012-08-19 13:35:36 +0800
commit75e82a1b3f495a3abbc78e50a5c66356d320fb15 (patch)
tree1201ed13bb3f3a69d4316b50f9b9aa63e3867511
parentcd463341de185094455cf5869a442aa02b8b812e (diff)
downloadpycairo-75e82a1b3f495a3abbc78e50a5c66356d320fb15.tar.gz
Add support for cairo_region_t, using patch in bug #44336.
-rw-r--r--doc/pycairo_c_api.rst10
-rw-r--r--doc/reference/index.rst1
-rw-r--r--doc/reference/region.rst52
-rwxr-xr-xsetup.py4
-rw-r--r--src/cairomodule.c22
-rw-r--r--src/matrix.c2
-rw-r--r--src/private.h18
-rw-r--r--src/py3cairo.h25
-rw-r--r--src/region.c598
-rw-r--r--src/wscript1
-rw-r--r--test/api_test.py62
11 files changed, 791 insertions, 4 deletions
diff --git a/doc/pycairo_c_api.rst b/doc/pycairo_c_api.rst
index 5f2becd..acce2eb 100644
--- a/doc/pycairo_c_api.rst
+++ b/doc/pycairo_c_api.rst
@@ -51,6 +51,8 @@ Objects::
PycairoGradient
PycairoLinearGradient
PycairoRadialGradient
+ PycairoRectangleInt
+ PycairoRegion
PycairoScaledFont
PycairoSurface
PycairoImageSurface
@@ -79,6 +81,8 @@ Types::
PyTypeObject *Gradient_Type;
PyTypeObject *LinearGradient_Type;
PyTypeObject *RadialGradient_Type;
+ PyTypeObject *RectangleInt_Type;
+ PyTypeObject *Region_Type;
PyTypeObject *ScaledFont_Type;
PyTypeObject *Surface_Type;
PyTypeObject *ImageSurface_Type;
@@ -117,6 +121,12 @@ Functions
.. c:function:: PyObject * PycairoPattern_FromPattern(cairo_pattern_t *pattern, PyObject *base)
+.. c:function:: PyObject * PycairoRectangleInt_FromRectangleInt(const cairo_rectangle_int_t *rectangle_int)
+
+
+.. c:function:: PyObject * PycairoRegion_FromRegion(const cairo_region_t *region)
+
+
.. c:function:: PyObject * PycairoScaledFont_FromScaledFont(cairo_scaled_font_t *scaled_font)
diff --git a/doc/reference/index.rst b/doc/reference/index.rst
index 2b1b9ac..81787cc 100644
--- a/doc/reference/index.rst
+++ b/doc/reference/index.rst
@@ -15,5 +15,6 @@ Reference
matrix
paths
patterns
+ region
surfaces
text
diff --git a/doc/reference/region.rst b/doc/reference/region.rst
new file mode 100644
index 0000000..06124a3
--- /dev/null
+++ b/doc/reference/region.rst
@@ -0,0 +1,52 @@
+.. _region:
+
+******
+Region
+******
+Region — Representing a pixel-aligned area
+
+.. currentmodule:: cairo
+
+
+class Region()
+==============
+*Region* is a simple graphical data type representing an area of
+integer-aligned rectangles. They are often used on raster surfaces to track
+areas of interest, such as change or clip areas.
+
+
+.. class:: Region([rectangle_int|rectangle_ints])
+
+ :param rectangle_int: a rectangle or a list of rectangle
+ :type rectangle_int: :class:`RectangleInt` or [:class:`RectangleInt`]
+
+ Allocates a new empty region object or a region object with the containing
+ rectangle(s).
+
+
+ .. method:: copy()
+
+ :returns: A newly allocated :class:`Region`.
+ :raises: :exc:`NoMemory` if memory cannot be allocated.
+
+ Allocates a new *Region* object copying the area from original.
+
+
+class RectangleInt()
+====================
+*RectangleInt* is a data structure for holding a rectangle with integer
+coordinates.
+
+
+.. class:: RectangleInt(x=0, y=0, width=0, height=0)
+
+ :param x: X coordinate of the left side of the rectangle
+ :type x: int
+ :param y: Y coordinate of the the top side of the rectangle
+ :type y: int
+ :param width: width of the rectangle
+ :type width: int
+ :param height: height of the rectangle
+ :type height: int
+
+ Allocates a new *RectangleInt* object.
diff --git a/setup.py b/setup.py
index a93a650..bde4ce2 100755
--- a/setup.py
+++ b/setup.py
@@ -81,7 +81,8 @@ def createConfigFile(ConfigFile):
if sys.version_info < python_version_required:
- raise SystemExit('Error: Python >= %s is required' %s (python_version_required,))
+ raise SystemExit('Error: Python >= %s is required' %
+ (python_version_required,))
pkg_config_version_check ('cairo', cairo_version_required)
if sys.platform == 'win32':
@@ -101,6 +102,7 @@ cairo = dic.Extension(
'src/matrix.c',
'src/path.c',
'src/pattern.c',
+ 'src/region.c',
'src/surface.c',
],
include_dirs = pkg_config_parse('--cflags-only-I', 'cairo'),
diff --git a/src/cairomodule.c b/src/cairomodule.c
index 08d823a..b1f2caa 100644
--- a/src/cairomodule.c
+++ b/src/cairomodule.c
@@ -157,6 +157,12 @@ static Pycairo_CAPI_t CAPI = {
PycairoSurface_FromSurface,
Pycairo_Check_Status,
+
+ &PycairoRectangleInt_Type,
+ PycairoRectangleInt_FromRectangleInt,
+
+ &PycairoRegion_Type,
+ PycairoRegion_FromRegion,
};
static PyObject *
@@ -246,6 +252,12 @@ PyInit__cairo(void)
if (PyType_Ready(&PycairoRadialGradient_Type) < 0)
return NULL;
+ if (PyType_Ready(&PycairoRectangleInt_Type) < 0)
+ return NULL;
+
+ if (PyType_Ready(&PycairoRegion_Type) < 0)
+ return NULL;
+
if (PyType_Ready(&PycairoScaledFont_Type) < 0)
return NULL;
@@ -335,6 +347,12 @@ PyInit__cairo(void)
PyModule_AddObject(m, "RadialGradient",
(PyObject *)&PycairoRadialGradient_Type);
+ Py_INCREF(&PycairoRectangleInt_Type);
+ PyModule_AddObject(m, "RectangleInt", (PyObject *)&PycairoRectangleInt_Type);
+
+ Py_INCREF(&PycairoRegion_Type);
+ PyModule_AddObject(m, "Region", (PyObject *)&PycairoRegion_Type);
+
Py_INCREF(&PycairoScaledFont_Type);
PyModule_AddObject(m, "ScaledFont", (PyObject *)&PycairoScaledFont_Type);
@@ -571,6 +589,10 @@ PyInit__cairo(void)
CONSTANT(PS_LEVEL_3);
#endif
+ CONSTANT(REGION_OVERLAP_IN);
+ CONSTANT(REGION_OVERLAP_OUT);
+ CONSTANT(REGION_OVERLAP_PART);
+
#ifdef CAIRO_HAS_SVG_SURFACE
CONSTANT(SVG_VERSION_1_1);
CONSTANT(SVG_VERSION_1_2);
diff --git a/src/matrix.c b/src/matrix.c
index 122e700..24f6e4a 100644
--- a/src/matrix.c
+++ b/src/matrix.c
@@ -285,8 +285,6 @@ static PyMethodDef matrix_methods[] = {
PyTypeObject PycairoMatrix_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
- //PyObject_HEAD_INIT(NULL)
- //0, /* ob_size */
"cairo.Matrix", /* tp_name */
sizeof(PycairoMatrix), /* tp_basicsize */
0, /* tp_itemsize */
diff --git a/src/private.h b/src/private.h
index 197f935..4a6b6ad 100644
--- a/src/private.h
+++ b/src/private.h
@@ -22,7 +22,7 @@
#define _PYCAIRO_PRIVATE_H_
#ifdef _PYCAIRO_H_
-# error "don't include pycairo.h and pycairo-private.h together"
+# error "don't include py3cairo.h and private.h together"
#endif
#define _INSIDE_PYCAIRO_
@@ -62,6 +62,13 @@ extern PyTypeObject PycairoRadialGradient_Type;
PyObject *PycairoPattern_FromPattern (cairo_pattern_t *pattern,
PyObject *base);
+extern PyTypeObject PycairoRectangleInt_Type;
+PyObject *PycairoRectangleInt_FromRectangleInt (
+ cairo_rectangle_int_t *rectangle_int);
+
+extern PyTypeObject PycairoRegion_Type;
+PyObject *PycairoRegion_FromRegion (cairo_region_t *region);
+
extern PyTypeObject PycairoScaledFont_Type;
PyObject *PycairoScaledFont_FromScaledFont (cairo_scaled_font_t *scaled_font);
@@ -161,5 +168,14 @@ int Pycairo_Check_Status (cairo_status_t status);
} \
} while (0)
+#define RETURN_NULL_IF_CAIRO_REGION_ERROR(region) \
+ do { \
+ cairo_status_t status = cairo_region_status (region); \
+ if (status != CAIRO_STATUS_SUCCESS) { \
+ Pycairo_Check_Status (status); \
+ return NULL; \
+ } \
+ } while (0)
+
#endif /* _PYCAIRO_PRIVATE_H_ */
diff --git a/src/py3cairo.h b/src/py3cairo.h
index 853c1d8..590582b 100644
--- a/src/py3cairo.h
+++ b/src/py3cairo.h
@@ -68,6 +68,16 @@ typedef struct {
typedef struct {
PyObject_HEAD
+ cairo_rectangle_int_t rectangle_int;
+} PycairoRectangleInt;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_region_t *region;
+} PycairoRegion;
+
+typedef struct {
+ PyObject_HEAD
cairo_scaled_font_t *scaled_font;
} PycairoScaledFont;
@@ -133,6 +143,14 @@ typedef struct {
/* misc functions */
int (*Check_Status)(cairo_status_t status);
+
+ PyTypeObject *RectangleInt_Type;
+ PyObject *(*RectangleInt_FromRectangleInt)(
+ const cairo_rectangle_int_t *rectangle_int);
+
+ PyTypeObject *Region_Type;
+ PyObject *(*Region_FromRegion)(const cairo_region_t *region);
+
} Pycairo_CAPI_t;
@@ -160,6 +178,13 @@ typedef struct {
#define PycairoRadialGradient_Type *(Pycairo_CAPI->RadialGradient_Type)
#define PycairoPattern_FromPattern (Pycairo_CAPI->Pattern_FromPattern)
+#define PycairoRectangleInt_Type *(Pycairo_CAPI->RectangleInt_Type)
+#define PycairoRectangleInt_FromRectangleInt \
+ (Pycairo_CAPI->RectangleInt_FromRectangleInt)
+
+#define PycairoRegion_Type *(Pycairo_CAPI->Region_Type)
+#define PycairoRegion_FromRegion (Pycairo_CAPI->Region_FromRegion)
+
#define PycairoScaledFont_Type *(Pycairo_CAPI->ScaledFont_Type)
#define PycairoScaledFont_FromScaledFont \
(Pycairo_CAPI->ScaledFont_FromScaledFont)
diff --git a/src/region.c b/src/region.c
new file mode 100644
index 0000000..2198ccd
--- /dev/null
+++ b/src/region.c
@@ -0,0 +1,598 @@
+/* -*- mode: C; c-basic-offset: 2 -*-
+ *
+ * Copyright © 2005,2010 Steve Chaplin
+ *
+ * This file is part of pycairo.
+ *
+ * Pycairo is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * Pycairo is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with pycairo. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include "structmember.h"
+
+#include "config.h"
+#include "private.h"
+
+/* PycairoRectangleInt_FromRectangleInt
+ * Create a new PycairoRectangleInt from a cairo_rectangle_int_t
+ * rectangle_int - a cairo_rectangle_int_t to 'wrap' into a Python object.
+ * rectangle_int is unreferenced if the PycairoRectangleInt creation
+ * fails.
+ * Return value: New reference or NULL on failure
+ */
+PyObject *
+PycairoRectangleInt_FromRectangleInt (cairo_rectangle_int_t *rectangle_int) {
+ PyObject *o;
+
+ assert (rectangle_int != NULL);
+
+ o = PycairoRectangleInt_Type.tp_alloc (&PycairoRectangleInt_Type, 0);
+ if (o)
+ ((PycairoRectangleInt *)o)->rectangle_int = *rectangle_int;
+ return o;
+}
+
+static void
+rectangle_int_dealloc(PycairoRectangleInt *o) {
+#ifdef DEBUG
+ printf("rectangle_int_dealloc start\n");
+#endif
+ //o->ob_type->tp_free((PyObject *)o);
+ Py_TYPE(o)->tp_free(o);
+#ifdef DEBUG
+ printf("rectangle_int_dealloc end\n");
+#endif
+}
+
+static PyObject *
+rectangle_int_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ static char *kwlist[] = { "x", "y", "width", "height", NULL };
+ int x, y, w, h;
+ x = y = w = h = 0;
+ cairo_rectangle_int_t rect;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ "|iiii:RectangleInt.__new__", kwlist,
+ &x, &y, &w, &h))
+ return NULL;
+
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+
+ return PycairoRectangleInt_FromRectangleInt(&rect);
+}
+
+static PyObject *
+rectangle_int_str(PycairoRectangleInt *rect_o) {
+ PyObject *s;
+ cairo_rectangle_int_t *rect = &(rect_o->rectangle_int);
+ char buf[80];
+ PyOS_snprintf(buf, sizeof(buf), "cairo.RectangleInt(%d, %d, %d, %d)",
+ rect->x, rect->y, rect->width, rect->height);
+ s = PyUnicode_FromString(buf);
+ return s;
+}
+
+static PyObject *
+rectangle_int_richcompare(PycairoRectangleInt *self,
+ PycairoRectangleInt *other, int op) {
+ int res = 0;
+ PyObject *b;
+
+ if (op != Py_EQ && op != Py_NE) {
+ PyErr_SetString(PyExc_TypeError, "Only support testing for == or !=");
+ return NULL;
+ }
+ if (!PyObject_IsInstance((PyObject*)other,
+ (PyObject*)&PycairoRectangleInt_Type)) {
+ res = 0;
+ }
+ else if (
+ self->rectangle_int.x == other->rectangle_int.x &&
+ self->rectangle_int.y == other->rectangle_int.y &&
+ self->rectangle_int.width == other->rectangle_int.width &&
+ self->rectangle_int.height == other->rectangle_int.height
+ )
+ res = 1;
+ res = op == Py_NE ? !res : res;
+ b = res ? Py_True : Py_False;
+ Py_INCREF(b);
+
+ return b;
+}
+
+static PyMemberDef RectangleInt_members[] = {
+ {"x", T_INT, sizeof(PyObject), 0,
+ "X coordinate of the left side of the rectangle"},
+ {"y", T_INT, sizeof(PyObject)+sizeof(int), 0,
+ "Y coordinate of the the top side of the rectangle"},
+ {"width", T_INT, sizeof(PyObject)+sizeof(int)*2, 0,
+ "width of the rectangle"},
+ {"height", T_INT, sizeof(PyObject)+sizeof(int)*3, 0,
+ "height of the rectangle"},
+ {NULL}
+};
+
+PyTypeObject PycairoRectangleInt_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "cairo.RectangleInt", /* tp_name */
+ sizeof(PycairoRectangleInt), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)rectangle_int_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ (reprfunc)rectangle_int_str, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ (richcmpfunc)rectangle_int_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ RectangleInt_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)rectangle_int_new, /* tp_new */
+};
+
+/* PycairoRegion_FromRegion
+ * Create a new PycairoRegion from a cairo_region_t
+ * region - a cairo_region_t to 'wrap' into a Python object.
+ * region is unreferenced if the PycairoRegion creation fails, or if
+ * region is in an error status.
+ * Return value: New reference or NULL on failure
+ */
+PyObject *
+PycairoRegion_FromRegion (cairo_region_t *region) {
+ PyObject *o;
+
+ assert (region != NULL);
+
+ if (Pycairo_Check_Status (cairo_region_status(region))) {
+ cairo_region_destroy (region);
+ return NULL;
+ }
+
+ o = PycairoRegion_Type.tp_alloc (&PycairoRegion_Type, 0);
+ if (o)
+ ((PycairoRegion *)o)->region = region;
+ else
+ cairo_region_destroy (region);
+ return o;
+}
+
+static void
+region_dealloc(PycairoRegion *o) {
+#ifdef DEBUG
+ printf("region_dealloc start\n");
+#endif
+ if (o->region) {
+ cairo_region_destroy(o->region);
+ o->region = NULL;
+ }
+ //o->ob_type->tp_free((PyObject *)o);
+ Py_TYPE(o)->tp_free(o);
+#ifdef DEBUG
+ printf("region_dealloc end\n");
+#endif
+}
+
+static PyObject *
+region_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ PyObject *s = NULL;
+ PycairoRectangleInt *rect_obj = NULL;
+ cairo_region_t *region = NULL;
+ cairo_rectangle_int_t *rect = NULL;
+
+ if (PyArg_ParseTuple(args, "|O!:Region.__new__",
+ &PycairoRectangleInt_Type, &rect_obj)) {
+ if (rect_obj != NULL) {
+ region = cairo_region_create_rectangle(&(rect_obj->rectangle_int));
+ }
+ } else if (!PyArg_ParseTuple(args, "|O:Region.__new__", &s)) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be a RectangleInt or a sequence of RectangleInt.");
+ return NULL;
+ }
+ PyErr_Clear(); /* Clear possible err in the 1st arg parser. */
+
+ /* list of rectangle_int or no args */
+ if (s != NULL) {
+ int i;
+ int rect_size;
+ PyObject *seq = NULL;
+ seq = PySequence_Fast (s,
+ "argument must be a RectangleInt or a sequence of RectangleInt.");
+ if (seq == NULL) {
+ return NULL;
+ }
+ rect_size = PySequence_Fast_GET_SIZE(seq);
+ rect = PyMem_Malloc (rect_size * sizeof(cairo_rectangle_int_t));
+ if (rect == NULL) {
+ Py_DECREF(seq);
+ return PyErr_NoMemory();
+ }
+
+ for(i=0; i<rect_size; i++) {
+ PyObject *obj_tmp = PySequence_Fast_GET_ITEM(seq, i);
+ if (PyObject_IsInstance(obj_tmp,
+ (PyObject*)&PycairoRectangleInt_Type) != 1) {
+ Py_DECREF(seq);
+ PyMem_Free(rect);
+ return NULL;
+ }
+ rect_obj = (PycairoRectangleInt*) obj_tmp;
+ rect[i] = rect_obj->rectangle_int;
+ }
+
+ region = cairo_region_create_rectangles(rect, rect_size);
+
+ Py_DECREF(seq);
+ PyMem_Free(rect);
+ }
+
+ if (region == NULL) {
+ region = cairo_region_create();
+ }
+
+ RETURN_NULL_IF_CAIRO_REGION_ERROR(region);
+ return PycairoRegion_FromRegion(region);
+}
+
+PyObject *
+region_copy (PycairoRegion *o) {
+ cairo_region_t *res;
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_copy (o->region);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_REGION_ERROR(res);
+ return PycairoRegion_FromRegion(res);
+}
+
+
+PyObject *
+region_get_extents (PycairoRegion *o) {
+ cairo_rectangle_int_t rect;
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_region_get_extents(o->region, &rect);
+ Py_END_ALLOW_THREADS;
+
+ return PycairoRectangleInt_FromRectangleInt(&rect);
+}
+
+
+PyObject *
+region_num_rectangles (PycairoRegion *o) {
+ int res;
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_num_rectangles(o->region);
+ Py_END_ALLOW_THREADS;
+ return Py_BuildValue("i", res);
+}
+
+
+PyObject *
+region_get_rectangle (PycairoRegion *o, PyObject *args) {
+ cairo_rectangle_int_t rect;
+ int i;
+ int total;
+ if (!PyArg_ParseTuple (args, "i:Region.get_rectangle", &i))
+ return NULL;
+ total = cairo_region_num_rectangles(o->region);
+ if (i >= total || i < 0) {
+ if ( i < 0)
+ PyErr_SetString(PyExc_ValueError, "index must be a positive number");
+ else
+ PyErr_SetString(PyExc_ValueError, "index is to big for the region");
+ return NULL;
+ }
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_region_get_rectangle(o->region, i, &rect);
+ Py_END_ALLOW_THREADS;
+ return PycairoRectangleInt_FromRectangleInt(&rect);
+}
+
+
+PyObject *
+region_is_empty (PycairoRegion *o) {
+ cairo_bool_t res;
+ PyObject *b;
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_is_empty(o->region);
+ Py_END_ALLOW_THREADS;
+ b = res ? Py_True : Py_False;
+ Py_INCREF(b);
+ return b;
+}
+
+
+PyObject *
+region_contains_point (PycairoRegion *o, PyObject *args) {
+ int x, y;
+ cairo_bool_t res;
+ PyObject *b;
+ if (!PyArg_ParseTuple (args, "ii:Region.contains_point", &x, &y))
+ return NULL;
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_contains_point(o->region, x, y);
+ Py_END_ALLOW_THREADS;
+ b = res ? Py_True : Py_False;
+ Py_INCREF(b);
+ return b;
+}
+
+
+PyObject *
+region_contains_rectangle (PycairoRegion *o, PyObject *args) {
+ cairo_region_overlap_t res;
+ PycairoRectangleInt *rect_int;
+ if (!PyArg_ParseTuple (args, "O!:Region.contains_rectangle",
+ &PycairoRectangleInt_Type, &rect_int))
+ return NULL;
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_contains_rectangle(o->region, &(rect_int->rectangle_int));
+ Py_END_ALLOW_THREADS;
+ return Py_BuildValue("i", res);
+}
+
+
+PyObject *
+region_equal (PycairoRegion *o, PyObject *args) {
+ cairo_bool_t res;
+ PyObject *b;
+ PycairoRegion *region_obj;
+ if (!PyArg_ParseTuple (args, "O!:Region.equal",
+ &PycairoRegion_Type, &region_obj))
+ return NULL;
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_equal (o->region, region_obj->region);
+ Py_END_ALLOW_THREADS;
+ b = res ? Py_True : Py_False;
+ Py_INCREF(b);
+ return b;
+}
+
+static PyObject *
+region_richcompare(PycairoRegion *self, PycairoRegion *other, int op) {
+ int res = 0;
+ PyObject *b;
+
+ if (op != Py_EQ && op != Py_NE) {
+ PyErr_SetString(PyExc_TypeError, "Only support testing for == or !=");
+ return NULL;
+ }
+ if (!PyObject_IsInstance((PyObject*)other, (PyObject*)&PycairoRegion_Type)) {
+ res = 0;
+ } else {
+ res = cairo_region_equal (self->region, other->region);
+ }
+
+ res = op == Py_NE ? !res : res;
+ b = res ? Py_True : Py_False;
+ Py_INCREF(b);
+
+ return b;
+}
+
+PyObject *
+region_translate (PycairoRegion *o, PyObject *args) {
+ int x, y;
+ if (!PyArg_ParseTuple (args, "ii:Region.translate", &x, &y))
+ return NULL;
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_region_translate (o->region, x, y);
+ Py_END_ALLOW_THREADS;
+ Py_RETURN_NONE;
+}
+
+
+PyObject *
+region_intersect (PycairoRegion *o, PyObject *args) {
+ cairo_status_t res;
+ PyObject *other;
+ if (!PyArg_ParseTuple (args, "O:Region.intersect", &other))
+ return NULL;
+
+ if (PyObject_IsInstance(other, (PyObject*)&PycairoRegion_Type) == 1) {
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_intersect(o->region,
+ ((PycairoRegion *)other)->region);
+ Py_END_ALLOW_THREADS;
+ } else if (PyObject_IsInstance(other,
+ (PyObject*)&PycairoRectangleInt_Type) == 1) {
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_intersect_rectangle(o->region,
+ &(((PycairoRectangleInt *)other)->rectangle_int));
+ Py_END_ALLOW_THREADS;
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be a Region or a RectangleInt.");
+ return NULL;
+ }
+
+ RETURN_NULL_IF_CAIRO_ERROR(res);
+ Py_RETURN_NONE;
+}
+
+PyObject *
+region_subtract (PycairoRegion *o, PyObject *args) {
+ cairo_status_t res;
+ PyObject *other;
+ if (!PyArg_ParseTuple (args, "O:Region.subtract", &other))
+ return NULL;
+
+ if (PyObject_IsInstance(other, (PyObject*)&PycairoRegion_Type) == 1) {
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_subtract(o->region,
+ ((PycairoRegion *)other)->region);
+ Py_END_ALLOW_THREADS;
+ } else if (PyObject_IsInstance(other,
+ (PyObject*)&PycairoRectangleInt_Type) == 1) {
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_subtract_rectangle(o->region,
+ &(((PycairoRectangleInt *)other)->rectangle_int));
+ Py_END_ALLOW_THREADS;
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be a Region or a RectangleInt.");
+ return NULL;
+ }
+ RETURN_NULL_IF_CAIRO_ERROR(res);
+ Py_RETURN_NONE;
+}
+
+PyObject *
+region_union (PycairoRegion *o, PyObject *args) {
+ cairo_status_t res;
+ PyObject *other;
+ if (!PyArg_ParseTuple (args, "O:Region.union", &other))
+ return NULL;
+
+ if (PyObject_IsInstance(other, (PyObject*)&PycairoRegion_Type) == 1) {
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_union(o->region,
+ ((PycairoRegion *)other)->region);
+ Py_END_ALLOW_THREADS;
+ } else if (PyObject_IsInstance(other,
+ (PyObject*)&PycairoRectangleInt_Type) == 1) {
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_union_rectangle(o->region,
+ &(((PycairoRectangleInt *)other)->rectangle_int));
+ Py_END_ALLOW_THREADS;
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be a Region or a RectangleInt.");
+ return NULL;
+ }
+ RETURN_NULL_IF_CAIRO_ERROR(res);
+ Py_RETURN_NONE;
+}
+
+PyObject *
+region_xor (PycairoRegion *o, PyObject *args) {
+ cairo_status_t res;
+ PyObject *other;
+ if (!PyArg_ParseTuple (args, "O:Region.xorg", &other))
+ return NULL;
+
+ if (PyObject_IsInstance(other, (PyObject*)&PycairoRegion_Type) == 1) {
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_xor(o->region,
+ ((PycairoRegion *)other)->region);
+ Py_END_ALLOW_THREADS;
+ } else if (PyObject_IsInstance(other,
+ (PyObject*)&PycairoRectangleInt_Type) == 1) {
+ Py_BEGIN_ALLOW_THREADS;
+ res = cairo_region_xor_rectangle(o->region,
+ &(((PycairoRectangleInt *)other)->rectangle_int));
+ Py_END_ALLOW_THREADS;
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be a Region or a RectangleInt.");
+ return NULL;
+ }
+ RETURN_NULL_IF_CAIRO_ERROR(res);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef region_methods[] = {
+ /* methods never exposed in a language binding:
+ * cairo_region_destroy()
+ * cairo_region_get_type()
+ * cairo_region_reference()
+ *
+ * cairo_region_status()
+ * - not needed since Pycairo handles status checking
+ *
+ * _(intersect/subtract/union/xor)_rectangle are merged with the region
+ * ones.
+ */
+ {"copy", (PyCFunction)region_copy, METH_NOARGS },
+ {"get_extents", (PyCFunction)region_get_extents, METH_NOARGS },
+ {"num_rectangles", (PyCFunction)region_num_rectangles, METH_NOARGS },
+ {"get_rectangle", (PyCFunction)region_get_rectangle, METH_VARARGS },
+ {"is_empty", (PyCFunction)region_is_empty, METH_NOARGS },
+ {"contains_point", (PyCFunction)region_contains_point, METH_VARARGS },
+ {"contains_rectangle", (PyCFunction)region_contains_rectangle,
+ METH_VARARGS },
+ {"equal", (PyCFunction)region_equal, METH_VARARGS },
+ {"translate", (PyCFunction)region_translate, METH_VARARGS },
+ {"intersect", (PyCFunction)region_intersect, METH_VARARGS },
+ {"subtract", (PyCFunction)region_subtract, METH_VARARGS },
+ {"union", (PyCFunction)region_union, METH_VARARGS },
+ {"xor", (PyCFunction)region_xor, METH_VARARGS },
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoRegion_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "cairo.Region", /* tp_name */
+ sizeof(PycairoRegion), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)region_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ (richcmpfunc)region_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ region_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)region_new, /* tp_new */
+};
diff --git a/src/wscript b/src/wscript
index 0ece7db..d6af709 100644
--- a/src/wscript
+++ b/src/wscript
@@ -25,6 +25,7 @@ def build(ctx):
'font.c',
'path.c',
'pattern.c',
+ 'region.c',
'matrix.c',
'surface.c',
],
diff --git a/test/api_test.py b/test/api_test.py
index 0fe0772..86317b2 100644
--- a/test/api_test.py
+++ b/test/api_test.py
@@ -88,3 +88,65 @@ def test_surface():
def test_text():
pass
+
+
+def test_region():
+ a = cairo.Region()
+ assert a.is_empty() == True
+ assert a.num_rectangles() == 0
+
+ b = cairo.RectangleInt(1, 2, 10, 12)
+ d = cairo.RectangleInt(1, 1, 10, 12)
+ e = cairo.RectangleInt(1, 3, 8, 12)
+ assert (b.x, b.y, b.width, b.height) == (1, 2, 10, 12)
+ c = cairo.Region((b, e))
+ assert not c.is_empty()
+ assert c.num_rectangles() == 2
+ assert c.get_rectangle(1).y == 14
+
+ ex = c.get_extents()
+ assert ex == cairo.RectangleInt(1, 2, 10, 13)
+ assert c.contains_rectangle(d) == cairo.REGION_OVERLAP_PART
+
+ c.translate(10, 20)
+ assert c.contains_rectangle(d) == cairo.REGION_OVERLAP_OUT
+ assert c.get_rectangle(1) == cairo.RectangleInt(11, 34, 8, 1)
+
+ cp = c.copy()
+ assert c.num_rectangles() == cp.num_rectangles()
+ assert c.get_rectangle(0) == cp.get_rectangle(0)
+ assert c == cp
+ assert 3 != c
+ assert c != "test"
+
+ c = cairo.Region((b, e))
+ c.intersect(d)
+ assert c.num_rectangles() == 1
+ assert c.get_rectangle(0) == cairo.RectangleInt(1, 2, 10, 11)
+
+ c = cairo.Region((b, e))
+ c.subtract(d)
+ assert c.num_rectangles() == 2
+ assert c == cairo.Region([
+ cairo.RectangleInt(1, 13, 10, 1), cairo.RectangleInt(1, 14, 8, 1) ])
+
+ d = cairo.Region(d)
+ c = cairo.Region((b, e))
+ c.subtract(d)
+ assert c.num_rectangles() == 2
+ assert c.get_rectangle(0) == cairo.RectangleInt(1, 13, 10, 1)
+
+ c = cairo.Region((b, e))
+ c.union(d)
+ assert c.num_rectangles() == 2
+ assert c == cairo.Region([
+ cairo.RectangleInt(1, 1, 10, 13), cairo.RectangleInt(1, 14, 8, 1) ])
+
+ c = cairo.Region((b, e))
+ c.xor(d)
+ assert c.num_rectangles() == 3
+ assert c == cairo.Region([
+ cairo.RectangleInt(1, 1, 10, 1),
+ cairo.RectangleInt(1, 14, 8, 1),
+ cairo.RectangleInt(1, 13, 10, 1),
+ ])