1 #include "mplutils.h"
2 #include "py_converters.h"
3 #include "_backend_agg.h"
4 
5 typedef struct
6 {
7     PyObject_HEAD
8     RendererAgg *x;
9     Py_ssize_t shape[3];
10     Py_ssize_t strides[3];
11     Py_ssize_t suboffsets[3];
12 } PyRendererAgg;
13 
14 typedef struct
15 {
16     PyObject_HEAD
17     BufferRegion *x;
18     Py_ssize_t shape[3];
19     Py_ssize_t strides[3];
20     Py_ssize_t suboffsets[3];
21 } PyBufferRegion;
22 
23 
24 /**********************************************************************
25  * BufferRegion
26  * */
27 
PyBufferRegion_new(PyTypeObject * type,PyObject * args,PyObject * kwds)28 static PyObject *PyBufferRegion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
29 {
30     PyBufferRegion *self;
31     self = (PyBufferRegion *)type->tp_alloc(type, 0);
32     self->x = NULL;
33     return (PyObject *)self;
34 }
35 
PyBufferRegion_dealloc(PyBufferRegion * self)36 static void PyBufferRegion_dealloc(PyBufferRegion *self)
37 {
38     delete self->x;
39     Py_TYPE(self)->tp_free((PyObject *)self);
40 }
41 
PyBufferRegion_to_string(PyBufferRegion * self,PyObject * args,PyObject * kwds)42 static PyObject *PyBufferRegion_to_string(PyBufferRegion *self, PyObject *args, PyObject *kwds)
43 {
44     return PyBytes_FromStringAndSize((const char *)self->x->get_data(),
45                                      self->x->get_height() * self->x->get_stride());
46 }
47 
48 /* TODO: This doesn't seem to be used internally.  Remove? */
49 
PyBufferRegion_set_x(PyBufferRegion * self,PyObject * args,PyObject * kwds)50 static PyObject *PyBufferRegion_set_x(PyBufferRegion *self, PyObject *args, PyObject *kwds)
51 {
52     int x;
53     if (!PyArg_ParseTuple(args, "i:set_x", &x)) {
54         return NULL;
55     }
56     self->x->get_rect().x1 = x;
57 
58     Py_RETURN_NONE;
59 }
60 
PyBufferRegion_set_y(PyBufferRegion * self,PyObject * args,PyObject * kwds)61 static PyObject *PyBufferRegion_set_y(PyBufferRegion *self, PyObject *args, PyObject *kwds)
62 {
63     int y;
64     if (!PyArg_ParseTuple(args, "i:set_y", &y)) {
65         return NULL;
66     }
67     self->x->get_rect().y1 = y;
68 
69     Py_RETURN_NONE;
70 }
71 
PyBufferRegion_get_extents(PyBufferRegion * self,PyObject * args,PyObject * kwds)72 static PyObject *PyBufferRegion_get_extents(PyBufferRegion *self, PyObject *args, PyObject *kwds)
73 {
74     agg::rect_i rect = self->x->get_rect();
75 
76     return Py_BuildValue("IIII", rect.x1, rect.y1, rect.x2, rect.y2);
77 }
78 
PyBufferRegion_to_string_argb(PyBufferRegion * self,PyObject * args,PyObject * kwds)79 static PyObject *PyBufferRegion_to_string_argb(PyBufferRegion *self, PyObject *args, PyObject *kwds)
80 {
81     PyObject *bufobj;
82     uint8_t *buf;
83 
84     bufobj = PyBytes_FromStringAndSize(NULL, self->x->get_height() * self->x->get_stride());
85     buf = (uint8_t *)PyBytes_AS_STRING(bufobj);
86 
87     CALL_CPP_CLEANUP("to_string_argb", (self->x->to_string_argb(buf)), Py_DECREF(bufobj));
88 
89     return bufobj;
90 }
91 
PyBufferRegion_get_buffer(PyBufferRegion * self,Py_buffer * buf,int flags)92 int PyBufferRegion_get_buffer(PyBufferRegion *self, Py_buffer *buf, int flags)
93 {
94     Py_INCREF(self);
95     buf->obj = (PyObject *)self;
96     buf->buf = self->x->get_data();
97     buf->len = self->x->get_width() * self->x->get_height() * 4;
98     buf->readonly = 0;
99     buf->format = (char *)"B";
100     buf->ndim = 3;
101     self->shape[0] = self->x->get_height();
102     self->shape[1] = self->x->get_width();
103     self->shape[2] = 4;
104     buf->shape = self->shape;
105     self->strides[0] = self->x->get_width() * 4;
106     self->strides[1] = 4;
107     self->strides[2] = 1;
108     buf->strides = self->strides;
109     buf->suboffsets = NULL;
110     buf->itemsize = 1;
111     buf->internal = NULL;
112 
113     return 1;
114 }
115 
116 static PyTypeObject PyBufferRegionType;
117 
PyBufferRegion_init_type(PyObject * m,PyTypeObject * type)118 static PyTypeObject *PyBufferRegion_init_type(PyObject *m, PyTypeObject *type)
119 {
120     static PyMethodDef methods[] = {
121         { "to_string", (PyCFunction)PyBufferRegion_to_string, METH_NOARGS, NULL },
122         { "to_string_argb", (PyCFunction)PyBufferRegion_to_string_argb, METH_NOARGS, NULL },
123         { "set_x", (PyCFunction)PyBufferRegion_set_x, METH_VARARGS, NULL },
124         { "set_y", (PyCFunction)PyBufferRegion_set_y, METH_VARARGS, NULL },
125         { "get_extents", (PyCFunction)PyBufferRegion_get_extents, METH_NOARGS, NULL },
126         { NULL }
127     };
128 
129     static PyBufferProcs buffer_procs;
130     memset(&buffer_procs, 0, sizeof(PyBufferProcs));
131     buffer_procs.bf_getbuffer = (getbufferproc)PyBufferRegion_get_buffer;
132 
133     memset(type, 0, sizeof(PyTypeObject));
134     type->tp_name = "matplotlib.backends._backend_agg.BufferRegion";
135     type->tp_basicsize = sizeof(PyBufferRegion);
136     type->tp_dealloc = (destructor)PyBufferRegion_dealloc;
137     type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_NEWBUFFER;
138     type->tp_methods = methods;
139     type->tp_new = PyBufferRegion_new;
140     type->tp_as_buffer = &buffer_procs;
141 
142     if (PyType_Ready(type) < 0) {
143         return NULL;
144     }
145 
146     /* Don't need to add to module, since you can't create buffer
147        regions directly from Python */
148 
149     return type;
150 }
151 
152 /**********************************************************************
153  * RendererAgg
154  * */
155 
PyRendererAgg_new(PyTypeObject * type,PyObject * args,PyObject * kwds)156 static PyObject *PyRendererAgg_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
157 {
158     PyRendererAgg *self;
159     self = (PyRendererAgg *)type->tp_alloc(type, 0);
160     self->x = NULL;
161     return (PyObject *)self;
162 }
163 
PyRendererAgg_init(PyRendererAgg * self,PyObject * args,PyObject * kwds)164 static int PyRendererAgg_init(PyRendererAgg *self, PyObject *args, PyObject *kwds)
165 {
166     unsigned int width;
167     unsigned int height;
168     double dpi;
169     int debug = 0;
170 
171     if (!PyArg_ParseTuple(args, "IId|i:RendererAgg", &width, &height, &dpi, &debug)) {
172         return -1;
173     }
174 
175     if (dpi <= 0.0) {
176         PyErr_SetString(PyExc_ValueError, "dpi must be positive");
177         return -1;
178     }
179 
180     if (width >= 1 << 16 || height >= 1 << 16) {
181         PyErr_Format(
182             PyExc_ValueError,
183             "Image size of %dx%d pixels is too large. "
184             "It must be less than 2^16 in each direction.",
185             width, height);
186         return -1;
187     }
188 
189     CALL_CPP_INIT("RendererAgg", self->x = new RendererAgg(width, height, dpi))
190 
191     return 0;
192 }
193 
PyRendererAgg_dealloc(PyRendererAgg * self)194 static void PyRendererAgg_dealloc(PyRendererAgg *self)
195 {
196     delete self->x;
197     Py_TYPE(self)->tp_free((PyObject *)self);
198 }
199 
PyRendererAgg_draw_path(PyRendererAgg * self,PyObject * args,PyObject * kwds)200 static PyObject *PyRendererAgg_draw_path(PyRendererAgg *self, PyObject *args, PyObject *kwds)
201 {
202     GCAgg gc;
203     py::PathIterator path;
204     agg::trans_affine trans;
205     PyObject *faceobj = NULL;
206     agg::rgba face;
207 
208     if (!PyArg_ParseTuple(args,
209                           "O&O&O&|O:draw_path",
210                           &convert_gcagg,
211                           &gc,
212                           &convert_path,
213                           &path,
214                           &convert_trans_affine,
215                           &trans,
216                           &faceobj)) {
217         return NULL;
218     }
219 
220     if (!convert_face(faceobj, gc, &face)) {
221         return NULL;
222     }
223 
224     CALL_CPP("draw_path", (self->x->draw_path(gc, path, trans, face)));
225 
226     Py_RETURN_NONE;
227 }
228 
PyRendererAgg_draw_text_image(PyRendererAgg * self,PyObject * args,PyObject * kwds)229 static PyObject *PyRendererAgg_draw_text_image(PyRendererAgg *self, PyObject *args, PyObject *kwds)
230 {
231     numpy::array_view<agg::int8u, 2> image;
232     double x;
233     double y;
234     double angle;
235     GCAgg gc;
236 
237     if (!PyArg_ParseTuple(args,
238                           "O&dddO&:draw_text_image",
239                           &image.converter_contiguous,
240                           &image,
241                           &x,
242                           &y,
243                           &angle,
244                           &convert_gcagg,
245                           &gc)) {
246         return NULL;
247     }
248 
249     CALL_CPP("draw_text_image", (self->x->draw_text_image(gc, image, x, y, angle)));
250 
251     Py_RETURN_NONE;
252 }
253 
PyRendererAgg_draw_markers(PyRendererAgg * self,PyObject * args,PyObject * kwds)254 PyObject *PyRendererAgg_draw_markers(PyRendererAgg *self, PyObject *args, PyObject *kwds)
255 {
256     GCAgg gc;
257     py::PathIterator marker_path;
258     agg::trans_affine marker_path_trans;
259     py::PathIterator path;
260     agg::trans_affine trans;
261     PyObject *faceobj = NULL;
262     agg::rgba face;
263 
264     if (!PyArg_ParseTuple(args,
265                           "O&O&O&O&O&|O:draw_markers",
266                           &convert_gcagg,
267                           &gc,
268                           &convert_path,
269                           &marker_path,
270                           &convert_trans_affine,
271                           &marker_path_trans,
272                           &convert_path,
273                           &path,
274                           &convert_trans_affine,
275                           &trans,
276                           &faceobj)) {
277         return NULL;
278     }
279 
280     if (!convert_face(faceobj, gc, &face)) {
281         return NULL;
282     }
283 
284     CALL_CPP("draw_markers",
285              (self->x->draw_markers(gc, marker_path, marker_path_trans, path, trans, face)));
286 
287     Py_RETURN_NONE;
288 }
289 
PyRendererAgg_draw_image(PyRendererAgg * self,PyObject * args,PyObject * kwds)290 static PyObject *PyRendererAgg_draw_image(PyRendererAgg *self, PyObject *args, PyObject *kwds)
291 {
292     GCAgg gc;
293     double x;
294     double y;
295     numpy::array_view<agg::int8u, 3> image;
296 
297     if (!PyArg_ParseTuple(args,
298                           "O&ddO&:draw_image",
299                           &convert_gcagg,
300                           &gc,
301                           &x,
302                           &y,
303                           &image.converter_contiguous,
304                           &image)) {
305         return NULL;
306     }
307 
308     x = mpl_round(x);
309     y = mpl_round(y);
310 
311     gc.alpha = 1.0;
312     CALL_CPP("draw_image", (self->x->draw_image(gc, x, y, image)));
313 
314     Py_RETURN_NONE;
315 }
316 
317 static PyObject *
PyRendererAgg_draw_path_collection(PyRendererAgg * self,PyObject * args,PyObject * kwds)318 PyRendererAgg_draw_path_collection(PyRendererAgg *self, PyObject *args, PyObject *kwds)
319 {
320     GCAgg gc;
321     agg::trans_affine master_transform;
322     PyObject *pathobj;
323     numpy::array_view<const double, 3> transforms;
324     numpy::array_view<const double, 2> offsets;
325     agg::trans_affine offset_trans;
326     numpy::array_view<const double, 2> facecolors;
327     numpy::array_view<const double, 2> edgecolors;
328     numpy::array_view<const double, 1> linewidths;
329     DashesVector dashes;
330     numpy::array_view<const uint8_t, 1> antialiaseds;
331     PyObject *ignored;
332     e_offset_position offset_position;
333 
334     if (!PyArg_ParseTuple(args,
335                           "O&O&OO&O&O&O&O&O&O&O&OO&:draw_path_collection",
336                           &convert_gcagg,
337                           &gc,
338                           &convert_trans_affine,
339                           &master_transform,
340                           &pathobj,
341                           &convert_transforms,
342                           &transforms,
343                           &convert_points,
344                           &offsets,
345                           &convert_trans_affine,
346                           &offset_trans,
347                           &convert_colors,
348                           &facecolors,
349                           &convert_colors,
350                           &edgecolors,
351                           &linewidths.converter,
352                           &linewidths,
353                           &convert_dashes_vector,
354                           &dashes,
355                           &antialiaseds.converter,
356                           &antialiaseds,
357                           &ignored,
358                           &convert_offset_position,
359                           &offset_position)) {
360         return NULL;
361     }
362 
363     try
364     {
365         py::PathGenerator path(pathobj);
366 
367         CALL_CPP("draw_path_collection",
368                  (self->x->draw_path_collection(gc,
369                                                 master_transform,
370                                                 path,
371                                                 transforms,
372                                                 offsets,
373                                                 offset_trans,
374                                                 facecolors,
375                                                 edgecolors,
376                                                 linewidths,
377                                                 dashes,
378                                                 antialiaseds,
379                                                 offset_position)));
380     }
381     catch (const py::exception &)
382     {
383         return NULL;
384     }
385 
386     Py_RETURN_NONE;
387 }
388 
PyRendererAgg_draw_quad_mesh(PyRendererAgg * self,PyObject * args,PyObject * kwds)389 static PyObject *PyRendererAgg_draw_quad_mesh(PyRendererAgg *self, PyObject *args, PyObject *kwds)
390 {
391     GCAgg gc;
392     agg::trans_affine master_transform;
393     unsigned int mesh_width;
394     unsigned int mesh_height;
395     numpy::array_view<const double, 3> coordinates;
396     numpy::array_view<const double, 2> offsets;
397     agg::trans_affine offset_trans;
398     numpy::array_view<const double, 2> facecolors;
399     int antialiased;
400     numpy::array_view<const double, 2> edgecolors;
401 
402     if (!PyArg_ParseTuple(args,
403                           "O&O&IIO&O&O&O&iO&:draw_quad_mesh",
404                           &convert_gcagg,
405                           &gc,
406                           &convert_trans_affine,
407                           &master_transform,
408                           &mesh_width,
409                           &mesh_height,
410                           &coordinates.converter,
411                           &coordinates,
412                           &convert_points,
413                           &offsets,
414                           &convert_trans_affine,
415                           &offset_trans,
416                           &convert_colors,
417                           &facecolors,
418                           &antialiased,
419                           &convert_colors,
420                           &edgecolors)) {
421         return NULL;
422     }
423 
424     CALL_CPP("draw_quad_mesh",
425              (self->x->draw_quad_mesh(gc,
426                                       master_transform,
427                                       mesh_width,
428                                       mesh_height,
429                                       coordinates,
430                                       offsets,
431                                       offset_trans,
432                                       facecolors,
433                                       antialiased,
434                                       edgecolors)));
435 
436     Py_RETURN_NONE;
437 }
438 
439 static PyObject *
PyRendererAgg_draw_gouraud_triangle(PyRendererAgg * self,PyObject * args,PyObject * kwds)440 PyRendererAgg_draw_gouraud_triangle(PyRendererAgg *self, PyObject *args, PyObject *kwds)
441 {
442     GCAgg gc;
443     numpy::array_view<const double, 2> points;
444     numpy::array_view<const double, 2> colors;
445     agg::trans_affine trans;
446 
447     if (!PyArg_ParseTuple(args,
448                           "O&O&O&O&|O:draw_gouraud_triangle",
449                           &convert_gcagg,
450                           &gc,
451                           &points.converter,
452                           &points,
453                           &colors.converter,
454                           &colors,
455                           &convert_trans_affine,
456                           &trans)) {
457         return NULL;
458     }
459 
460     if (points.dim(0) != 3 || points.dim(1) != 2) {
461         PyErr_Format(PyExc_ValueError,
462                      "points must be a 3x2 array, got %" NPY_INTP_FMT "x%" NPY_INTP_FMT,
463                      points.dim(0), points.dim(1));
464         return NULL;
465     }
466 
467     if (colors.dim(0) != 3 || colors.dim(1) != 4) {
468         PyErr_Format(PyExc_ValueError,
469                      "colors must be a 3x4 array, got %" NPY_INTP_FMT "x%" NPY_INTP_FMT,
470                      colors.dim(0), colors.dim(1));
471         return NULL;
472     }
473 
474 
475     CALL_CPP("draw_gouraud_triangle", (self->x->draw_gouraud_triangle(gc, points, colors, trans)));
476 
477     Py_RETURN_NONE;
478 }
479 
480 static PyObject *
PyRendererAgg_draw_gouraud_triangles(PyRendererAgg * self,PyObject * args,PyObject * kwds)481 PyRendererAgg_draw_gouraud_triangles(PyRendererAgg *self, PyObject *args, PyObject *kwds)
482 {
483     GCAgg gc;
484     numpy::array_view<const double, 3> points;
485     numpy::array_view<const double, 3> colors;
486     agg::trans_affine trans;
487 
488     if (!PyArg_ParseTuple(args,
489                           "O&O&O&O&|O:draw_gouraud_triangles",
490                           &convert_gcagg,
491                           &gc,
492                           &points.converter,
493                           &points,
494                           &colors.converter,
495                           &colors,
496                           &convert_trans_affine,
497                           &trans)) {
498         return NULL;
499     }
500 
501     if (points.size() != 0 && (points.dim(1) != 3 || points.dim(2) != 2)) {
502         PyErr_Format(PyExc_ValueError,
503                      "points must be a Nx3x2 array, got %" NPY_INTP_FMT "x%" NPY_INTP_FMT "x%" NPY_INTP_FMT,
504                      points.dim(0), points.dim(1), points.dim(2));
505         return NULL;
506     }
507 
508     if (colors.size() != 0 && (colors.dim(1) != 3 || colors.dim(2) != 4)) {
509         PyErr_Format(PyExc_ValueError,
510                      "colors must be a Nx3x4 array, got %" NPY_INTP_FMT "x%" NPY_INTP_FMT "x%" NPY_INTP_FMT,
511                      colors.dim(0), colors.dim(1), colors.dim(2));
512         return NULL;
513     }
514 
515     if (points.size() != colors.size()) {
516         PyErr_Format(PyExc_ValueError,
517                      "points and colors arrays must be the same length, got %" NPY_INTP_FMT " and %" NPY_INTP_FMT,
518                      points.dim(0), colors.dim(0));
519         return NULL;
520     }
521 
522     CALL_CPP("draw_gouraud_triangles", self->x->draw_gouraud_triangles(gc, points, colors, trans));
523 
524     Py_RETURN_NONE;
525 }
526 
PyRendererAgg_tostring_rgb(PyRendererAgg * self,PyObject * args,PyObject * kwds)527 static PyObject *PyRendererAgg_tostring_rgb(PyRendererAgg *self, PyObject *args, PyObject *kwds)
528 {
529     PyObject *buffobj = NULL;
530 
531     buffobj = PyBytes_FromStringAndSize(NULL, self->x->get_width() * self->x->get_height() * 3);
532     if (buffobj == NULL) {
533         return NULL;
534     }
535 
536     CALL_CPP_CLEANUP("tostring_rgb",
537                      (self->x->tostring_rgb((uint8_t *)PyBytes_AS_STRING(buffobj))),
538                      Py_DECREF(buffobj));
539 
540     return buffobj;
541 }
542 
PyRendererAgg_tostring_argb(PyRendererAgg * self,PyObject * args,PyObject * kwds)543 static PyObject *PyRendererAgg_tostring_argb(PyRendererAgg *self, PyObject *args, PyObject *kwds)
544 {
545     PyObject *buffobj = NULL;
546 
547     buffobj = PyBytes_FromStringAndSize(NULL, self->x->get_width() * self->x->get_height() * 4);
548     if (buffobj == NULL) {
549         return NULL;
550     }
551 
552     CALL_CPP_CLEANUP("tostring_argb",
553                      (self->x->tostring_argb((uint8_t *)PyBytes_AS_STRING(buffobj))),
554                      Py_DECREF(buffobj));
555 
556     return buffobj;
557 }
558 
PyRendererAgg_tostring_bgra(PyRendererAgg * self,PyObject * args,PyObject * kwds)559 static PyObject *PyRendererAgg_tostring_bgra(PyRendererAgg *self, PyObject *args, PyObject *kwds)
560 {
561     PyObject *buffobj = NULL;
562 
563     buffobj = PyBytes_FromStringAndSize(NULL, self->x->get_width() * self->x->get_height() * 4);
564     if (buffobj == NULL) {
565         return NULL;
566     }
567 
568     CALL_CPP_CLEANUP("to_string_bgra",
569                      (self->x->tostring_bgra((uint8_t *)PyBytes_AS_STRING(buffobj))),
570                      Py_DECREF(buffobj));
571 
572     return buffobj;
573 }
574 
575 static PyObject *
PyRendererAgg_get_content_extents(PyRendererAgg * self,PyObject * args,PyObject * kwds)576 PyRendererAgg_get_content_extents(PyRendererAgg *self, PyObject *args, PyObject *kwds)
577 {
578     agg::rect_i extents;
579 
580     CALL_CPP("get_content_extents", (extents = self->x->get_content_extents()));
581 
582     return Py_BuildValue(
583         "iiii", extents.x1, extents.y1, extents.x2 - extents.x1, extents.y2 - extents.y1);
584 }
585 
PyRendererAgg_buffer_rgba(PyRendererAgg * self,PyObject * args,PyObject * kwds)586 static PyObject *PyRendererAgg_buffer_rgba(PyRendererAgg *self, PyObject *args, PyObject *kwds)
587 {
588 #if PY3K
589     return PyBytes_FromStringAndSize((const char *)self->x->pixBuffer,
590                                      self->x->get_width() * self->x->get_height() * 4);
591 #else
592     return PyBuffer_FromReadWriteMemory(self->x->pixBuffer,
593                                         self->x->get_width() * self->x->get_height() * 4);
594 #endif
595 }
596 
PyRendererAgg_get_buffer(PyRendererAgg * self,Py_buffer * buf,int flags)597 int PyRendererAgg_get_buffer(PyRendererAgg *self, Py_buffer *buf, int flags)
598 {
599     Py_INCREF(self);
600     buf->obj = (PyObject *)self;
601     buf->buf = self->x->pixBuffer;
602     buf->len = self->x->get_width() * self->x->get_height() * 4;
603     buf->readonly = 0;
604     buf->format = (char *)"B";
605     buf->ndim = 3;
606     self->shape[0] = self->x->get_height();
607     self->shape[1] = self->x->get_width();
608     self->shape[2] = 4;
609     buf->shape = self->shape;
610     self->strides[0] = self->x->get_width() * 4;
611     self->strides[1] = 4;
612     self->strides[2] = 1;
613     buf->strides = self->strides;
614     buf->suboffsets = NULL;
615     buf->itemsize = 1;
616     buf->internal = NULL;
617 
618     return 1;
619 }
620 
PyRendererAgg_clear(PyRendererAgg * self,PyObject * args,PyObject * kwds)621 static PyObject *PyRendererAgg_clear(PyRendererAgg *self, PyObject *args, PyObject *kwds)
622 {
623     CALL_CPP("clear", self->x->clear());
624 
625     Py_RETURN_NONE;
626 }
627 
PyRendererAgg_copy_from_bbox(PyRendererAgg * self,PyObject * args,PyObject * kwds)628 static PyObject *PyRendererAgg_copy_from_bbox(PyRendererAgg *self, PyObject *args, PyObject *kwds)
629 {
630     agg::rect_d bbox;
631     BufferRegion *reg;
632     PyObject *regobj;
633 
634     if (!PyArg_ParseTuple(args, "O&:copy_from_bbox", &convert_rect, &bbox)) {
635         return 0;
636     }
637 
638     CALL_CPP("copy_from_bbox", (reg = self->x->copy_from_bbox(bbox)));
639 
640     regobj = PyBufferRegion_new(&PyBufferRegionType, NULL, NULL);
641     ((PyBufferRegion *)regobj)->x = reg;
642 
643     return regobj;
644 }
645 
PyRendererAgg_restore_region(PyRendererAgg * self,PyObject * args,PyObject * kwds)646 static PyObject *PyRendererAgg_restore_region(PyRendererAgg *self, PyObject *args, PyObject *kwds)
647 {
648     PyBufferRegion *regobj;
649     int xx1 = 0, yy1 = 0, xx2 = 0, yy2 = 0, x = 0, y = 0;
650 
651     if (!PyArg_ParseTuple(args,
652                           "O!|iiiiii:restore_region",
653                           &PyBufferRegionType,
654                           &regobj,
655                           &xx1,
656                           &yy1,
657                           &xx2,
658                           &yy2,
659                           &x,
660                           &y)) {
661         return 0;
662     }
663 
664     if (PySequence_Size(args) == 1) {
665         CALL_CPP("restore_region", (self->x->restore_region(*(regobj->x))));
666     } else {
667         CALL_CPP("restore_region", self->x->restore_region(*(regobj->x), xx1, yy1, xx2, yy2, x, y));
668     }
669 
670     Py_RETURN_NONE;
671 }
672 
673 PyTypeObject PyRendererAggType;
674 
PyRendererAgg_init_type(PyObject * m,PyTypeObject * type)675 static PyTypeObject *PyRendererAgg_init_type(PyObject *m, PyTypeObject *type)
676 {
677     static PyMethodDef methods[] = {
678         {"draw_path", (PyCFunction)PyRendererAgg_draw_path, METH_VARARGS, NULL},
679         {"draw_markers", (PyCFunction)PyRendererAgg_draw_markers, METH_VARARGS, NULL},
680         {"draw_text_image", (PyCFunction)PyRendererAgg_draw_text_image, METH_VARARGS, NULL},
681         {"draw_image", (PyCFunction)PyRendererAgg_draw_image, METH_VARARGS, NULL},
682         {"draw_path_collection", (PyCFunction)PyRendererAgg_draw_path_collection, METH_VARARGS, NULL},
683         {"draw_quad_mesh", (PyCFunction)PyRendererAgg_draw_quad_mesh, METH_VARARGS, NULL},
684         {"draw_gouraud_triangle", (PyCFunction)PyRendererAgg_draw_gouraud_triangle, METH_VARARGS, NULL},
685         {"draw_gouraud_triangles", (PyCFunction)PyRendererAgg_draw_gouraud_triangles, METH_VARARGS, NULL},
686 
687         {"tostring_rgb", (PyCFunction)PyRendererAgg_tostring_rgb, METH_NOARGS, NULL},
688         {"tostring_argb", (PyCFunction)PyRendererAgg_tostring_argb, METH_NOARGS, NULL},
689         {"tostring_bgra", (PyCFunction)PyRendererAgg_tostring_bgra, METH_NOARGS, NULL},
690         {"get_content_extents", (PyCFunction)PyRendererAgg_get_content_extents, METH_NOARGS, NULL},
691         {"buffer_rgba", (PyCFunction)PyRendererAgg_buffer_rgba, METH_NOARGS, NULL},
692         {"clear", (PyCFunction)PyRendererAgg_clear, METH_NOARGS, NULL},
693 
694         {"copy_from_bbox", (PyCFunction)PyRendererAgg_copy_from_bbox, METH_VARARGS, NULL},
695         {"restore_region", (PyCFunction)PyRendererAgg_restore_region, METH_VARARGS, NULL},
696         {NULL}
697     };
698 
699     static PyBufferProcs buffer_procs;
700     memset(&buffer_procs, 0, sizeof(PyBufferProcs));
701     buffer_procs.bf_getbuffer = (getbufferproc)PyRendererAgg_get_buffer;
702 
703     memset(type, 0, sizeof(PyTypeObject));
704     type->tp_name = "matplotlib.backends._backend_agg.RendererAgg";
705     type->tp_basicsize = sizeof(PyRendererAgg);
706     type->tp_dealloc = (destructor)PyRendererAgg_dealloc;
707     type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_NEWBUFFER;
708     type->tp_methods = methods;
709     type->tp_init = (initproc)PyRendererAgg_init;
710     type->tp_new = PyRendererAgg_new;
711     type->tp_as_buffer = &buffer_procs;
712 
713     if (PyType_Ready(type) < 0) {
714         return NULL;
715     }
716 
717     if (PyModule_AddObject(m, "RendererAgg", (PyObject *)type)) {
718         return NULL;
719     }
720 
721     return type;
722 }
723 
724 extern "C" {
725 
726 #if PY3K
727 static struct PyModuleDef moduledef = {
728     PyModuleDef_HEAD_INIT,
729     "_backend_agg",
730     NULL,
731     0,
732     NULL,
733     NULL,
734     NULL,
735     NULL,
736     NULL
737 };
738 
739 #define INITERROR return NULL
740 
PyInit__backend_agg(void)741 PyMODINIT_FUNC PyInit__backend_agg(void)
742 
743 #else
744 #define INITERROR return
745 
746 PyMODINIT_FUNC init_backend_agg(void)
747 #endif
748 
749 {
750     PyObject *m;
751 
752 #if PY3K
753     m = PyModule_Create(&moduledef);
754 #else
755     m = Py_InitModule3("_backend_agg", NULL, NULL);
756 #endif
757 
758     if (m == NULL) {
759         INITERROR;
760     }
761 
762     import_array();
763 
764     if (!PyRendererAgg_init_type(m, &PyRendererAggType)) {
765         INITERROR;
766     }
767 
768     if (!PyBufferRegion_init_type(m, &PyBufferRegionType)) {
769         INITERROR;
770     }
771 
772 #if PY3K
773     return m;
774 #endif
775 }
776 
777 } // extern "C"
778