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