1 /* -*- mode: C; c-basic-offset: 2 -*-
2 *
3 * Pycairo - Python bindings for cairo
4 *
5 * Copyright © 2005 Steve Chaplin
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it either under the terms of the GNU Lesser General Public
9 * License version 2.1 as published by the Free Software Foundation
10 * (the "LGPL") or, at your option, under the terms of the Mozilla
11 * Public License Version 1.1 (the "MPL"). If you do not alter this
12 * notice, a recipient may use your version of this file under either
13 * the MPL or the LGPL.
14 *
15 * You should have received a copy of the LGPL along with this library
16 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
20 *
21 * The contents of this file are subject to the Mozilla Public License
22 * Version 1.1 (the "License"); you may not use this file except in
23 * compliance with the License. You may obtain a copy of the License at
24 * http://www.mozilla.org/MPL/
25 *
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 * the specific language governing rights and limitations.
29 */
30
31 #define PY_SSIZE_T_CLEAN
32 #include <Python.h>
33
34 #include "private.h"
35
36
37 /* PycairoPath iterator object
38 * modelled on Python-2.4/Objects/rangeobject.c and tupleobject.c
39 */
40
41 PyObject *
PycairoPath_FromPath(cairo_path_t * path)42 PycairoPath_FromPath (cairo_path_t *path) {
43 PyObject *o;
44
45 assert (path != NULL);
46
47 if (Pycairo_Check_Status (path->status)) {
48 cairo_path_destroy (path);
49 return NULL;
50 }
51
52 o = PycairoPath_Type.tp_alloc (&PycairoPath_Type, 0);
53 if (o)
54 ((PycairoPath *)o)->path = path;
55 else
56 cairo_path_destroy (path);
57 return o;
58 }
59
60 static void
path_dealloc(PycairoPath * p)61 path_dealloc(PycairoPath *p) {
62 if (p->path) {
63 cairo_path_destroy(p->path);
64 p->path = NULL;
65 }
66 Py_TYPE(p)->tp_free(p);
67 }
68
69 static PyObject *
path_new(PyTypeObject * type,PyObject * args,PyObject * kwds)70 path_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
71 return type->tp_alloc(type, 0);
72 /* initializes memory to zeros */
73 }
74
75 static int
path_init(PycairoPath * p,PyObject * args,PyObject * kwds)76 path_init(PycairoPath *p, PyObject *args, PyObject *kwds) {
77 PyErr_SetString(PyExc_TypeError, "The Path type cannot be instantiated, "
78 "use Context.copy_path()");
79 return -1;
80 }
81
82 static PyObject *
path_str(PycairoPath * p)83 path_str(PycairoPath *p) {
84 PyObject *s, *pieces = NULL, *result = NULL;
85 cairo_path_t *path = p->path;
86 cairo_path_data_t *data;
87 int i, ret;
88 char buf[80];
89
90 pieces = PyList_New(0);
91 if (pieces == NULL)
92 goto Done;
93
94 /* loop reading elements */
95 for (i=0; i < path->num_data; i += path->data[i].header.length) {
96 data = &path->data[i];
97 switch (data->header.type) {
98
99 case CAIRO_PATH_MOVE_TO:
100 PyOS_snprintf(buf, sizeof(buf), "move_to %f %f",
101 data[1].point.x, data[1].point.y);
102 s = PYCAIRO_PyUnicode_FromString(buf);
103 if (!s)
104 goto Done;
105 ret = PyList_Append(pieces, s);
106 Py_DECREF(s);
107 if (ret < 0)
108 goto Done;
109 break;
110
111 case CAIRO_PATH_LINE_TO:
112 PyOS_snprintf(buf, sizeof(buf), "line_to %f %f",
113 data[1].point.x, data[1].point.y);
114 s = PYCAIRO_PyUnicode_FromString(buf);
115 if (!s)
116 goto Done;
117 ret = PyList_Append(pieces, s);
118 Py_DECREF(s);
119 if (ret < 0)
120 goto Done;
121 break;
122
123 case CAIRO_PATH_CURVE_TO:
124 PyOS_snprintf(buf, sizeof(buf), "curve_to %f %f %f %f %f %f",
125 data[1].point.x, data[1].point.y,
126 data[2].point.x, data[2].point.y,
127 data[3].point.x, data[3].point.y);
128 s = PYCAIRO_PyUnicode_FromString(buf);
129 if (!s)
130 goto Done;
131 ret = PyList_Append(pieces, s);
132 Py_DECREF(s);
133 if (ret < 0)
134 goto Done;
135 break;
136
137 case CAIRO_PATH_CLOSE_PATH:
138 s = PYCAIRO_PyUnicode_FromString("close path");
139 if (!s)
140 goto Done;
141 ret = PyList_Append(pieces, s);
142 Py_DECREF(s);
143 if (ret < 0)
144 goto Done;
145 break;
146 default:
147 PyErr_SetString(PyExc_RuntimeError, "unknown CAIRO_PATH type");
148 goto Done;
149 break;
150 }
151 }
152 /* result = "\n".join(pieces) */
153 s = PYCAIRO_PyUnicode_FromString("\n");
154 if (s == NULL)
155 goto Done;
156 result = PYCAIRO_PyUnicode_Join(s, pieces);
157 Py_DECREF(s);
158
159 Done:
160 Py_XDECREF(pieces);
161 return result;
162 }
163
164 static PyObject * path_iter(PyObject *seq); /* forward declaration */
165
166
167 static PyObject*
path_richcompare(PyObject * self,PyObject * other,int op)168 path_richcompare (PyObject *self, PyObject *other, int op)
169 {
170 if (Py_TYPE(self) == Py_TYPE(other))
171 return Pycairo_richcompare (
172 ((PycairoPath *)self)->path,
173 ((PycairoPath *)other)->path,
174 op);
175 else {
176 Py_INCREF(Py_NotImplemented);
177 return Py_NotImplemented;
178 }
179 }
180
181 static PYCAIRO_Py_hash_t
path_hash(PyObject * self)182 path_hash (PyObject *self)
183 {
184 return PYCAIRO_Py_hash_t_FromVoidPtr (((PycairoPath *)self)->path);
185 }
186
187 PyTypeObject PycairoPath_Type = {
188 PyVarObject_HEAD_INIT(NULL, 0)
189 "cairo.Path", /* tp_name */
190 sizeof(PycairoPath), /* tp_basicsize */
191 0, /* tp_itemsize */
192 (destructor)path_dealloc, /* tp_dealloc */
193 0, /* tp_print */
194 0, /* tp_getattr */
195 0, /* tp_setattr */
196 0, /* tp_compare */
197 0, /* tp_repr */
198 0, /* tp_as_number */
199 0, /* tp_as_sequence */
200 0, /* tp_as_mapping */
201 path_hash, /* tp_hash */
202 0, /* tp_call */
203 (reprfunc)path_str, /* tp_str */
204 0, /* tp_getattro */
205 0, /* tp_setattro */
206 0, /* tp_as_buffer */
207 Py_TPFLAGS_DEFAULT, /* tp_flags */
208 0, /* tp_doc */
209 0, /* tp_traverse */
210 0, /* tp_clear */
211 path_richcompare, /* tp_richcompare */
212 0, /* tp_weaklistoffset */
213 (getiterfunc)path_iter, /* tp_iter */
214 0, /* tp_iternext */
215 0, /* tp_methods */
216 0, /* tp_members */
217 0, /* tp_getset */
218 0, /* tp_base */
219 0, /* tp_dict */
220 0, /* tp_descr_get */
221 0, /* tp_descr_set */
222 0, /* tp_dictoffset */
223 (initproc)path_init, /* tp_init */
224 0, /* tp_alloc */
225 (newfunc)path_new, /* tp_new */
226 };
227
228 /*********************** PycairoPath Iterator **************************/
229
230 typedef struct {
231 PyObject_HEAD
232 int index; /* position within PycairoPath */
233 PycairoPath *pypath; /* Set to NULL when iterator is exhausted */
234 } PycairoPathiter;
235
236 PyTypeObject PycairoPathiter_Type;
237
238
239 static void
pathiter_dealloc(PycairoPathiter * it)240 pathiter_dealloc(PycairoPathiter *it) {
241 Py_XDECREF(it->pypath);
242 PyObject_Del(it);
243 }
244
245 static PyObject *
path_iter(PyObject * pypath)246 path_iter(PyObject *pypath) {
247 PycairoPathiter *it;
248
249 if (!PyObject_TypeCheck (pypath, &PycairoPath_Type)) {
250 PyErr_BadInternalCall();
251 return NULL;
252 }
253 it = PyObject_New(PycairoPathiter, &PycairoPathiter_Type);
254 if (it == NULL)
255 return NULL;
256
257 it->index = 0;
258 Py_INCREF(pypath);
259 it->pypath = (PycairoPath *)pypath;
260 return (PyObject *) it;
261 }
262
263 static PyObject *
pathiter_next(PycairoPathiter * it)264 pathiter_next(PycairoPathiter *it) {
265 PycairoPath *pypath;
266 cairo_path_t *path;
267
268 assert(it != NULL);
269 pypath = it->pypath;
270 if (pypath == NULL)
271 return NULL;
272 assert (PyObject_TypeCheck (pypath, &PycairoPath_Type));
273 path = pypath->path;
274
275 /* return the next path element, advance index */
276 if (it->index < path->num_data) {
277 cairo_path_data_t *data = &path->data[it->index];
278 int type = data->header.type;
279
280 it->index += data[0].header.length;
281
282 switch (type) {
283 case CAIRO_PATH_MOVE_TO:
284 case CAIRO_PATH_LINE_TO:
285 return Py_BuildValue("(i(dd))", type,
286 data[1].point.x, data[1].point.y);
287 case CAIRO_PATH_CURVE_TO:
288 return Py_BuildValue("(i(dddddd))", type,
289 data[1].point.x, data[1].point.y,
290 data[2].point.x, data[2].point.y,
291 data[3].point.x, data[3].point.y);
292 case CAIRO_PATH_CLOSE_PATH:
293 return Py_BuildValue("i()", type);
294 default:
295 PyErr_SetString(PyExc_RuntimeError, "unknown CAIRO_PATH type");
296 return NULL;
297 }
298 }
299
300 /* iterator has no remaining items */
301 Py_DECREF(pypath);
302 it->pypath = NULL;
303 return NULL;
304 }
305
306 PyTypeObject PycairoPathiter_Type = {
307 PyVarObject_HEAD_INIT(NULL, 0)
308 "cairo.Pathiter", /* tp_name */
309 sizeof(PycairoPathiter), /* tp_basicsize */
310 0, /* tp_itemsize */
311 (destructor)pathiter_dealloc, /* tp_dealloc */
312 0, /* tp_print */
313 0, /* tp_getattr */
314 0, /* tp_setattr */
315 0, /* tp_compare */
316 0, /* tp_repr */
317 0, /* tp_as_number */
318 0, /* tp_as_sequence */
319 0, /* tp_as_mapping */
320 0, /* tp_hash */
321 0, /* tp_call */
322 0, /* tp_str */
323 0, /* tp_getattro */
324 0, /* tp_setattro */
325 0, /* tp_as_buffer */
326 Py_TPFLAGS_DEFAULT, /* tp_flags */
327 0, /* tp_doc */
328 0, /* tp_traverse */
329 0, /* tp_clear */
330 0, /* tp_richcompare */
331 0, /* tp_weaklistoffset */
332 0, /* PyObject_SelfIter, */ /* tp_iter */
333 (iternextfunc)pathiter_next, /* tp_iternext */
334 0, /* tp_methods */
335 };
336