diff options
author | Steve Chaplin <> | 2011-06-19 14:18:41 +0800 |
---|---|---|
committer | Steve Chaplin <> | 2011-06-19 14:18:41 +0800 |
commit | 4bdcaf76248fc18253e4130fd1304b6f3b0ac3ab (patch) | |
tree | 9bef881b53fab366d86c7facdcfcc12ef8a90cfd | |
parent | 4323d440e99deb91ee2e98b6b845ab17cf9b6bd8 (diff) | |
download | pycairo-4bdcaf76248fc18253e4130fd1304b6f3b0ac3ab.tar.gz |
Add support for RecordingSurface.
Add docs and tests for RecordingSurface.
Adding the RecordingSurface to the pycairo API breaks ABI compatibility with
previous pycairo versions.
-rw-r--r-- | RELEASING | 17 | ||||
-rw-r--r-- | doc/.gitignore | 3 | ||||
-rw-r--r-- | doc/pycairo_c_api.rst | 2 | ||||
-rw-r--r-- | doc/reference/constants.rst | 1 | ||||
-rw-r--r-- | doc/reference/surfaces.rst | 61 | ||||
-rw-r--r-- | src/cairomodule.c | 23 | ||||
-rw-r--r-- | src/private.h | 7 | ||||
-rw-r--r-- | src/py3cairo.h | 24 | ||||
-rw-r--r-- | src/surface.c | 118 | ||||
-rw-r--r-- | test/api_test.py | 4 | ||||
-rw-r--r-- | wscript | 2 |
11 files changed, 221 insertions, 41 deletions
@@ -16,15 +16,18 @@ major changes briefly in a style similar to other entries in NEWS. $ cd doc $ make clean; make html # view docs and ensure version number is correct +$ cd .. $ ./waf distcheck # ensure there are no errors - rm ./pycairo-X.X.X +$ rm -rf py2cairo-X.X.X* + $ ./waf clean distclean $ ./waf dist # to create pycairo-x.x.x.tar.bz2 # create sha1 sum $ sha1sum pycairo-x.x.x.tar.bz2 > pycairo-x.x.x.tar.bz2.sha1 + # ensure html docs are present in the archive -cp pycairo* /tmp -# install from the archive, run tests and examples. +$ mv pycairo-X.X.X* /tmp + # install from the archive, run tests and examples. 4) git commit # the changes to NEWS, etc. @@ -39,7 +42,6 @@ $ git push origin master 5) Copy the archive to the cairo download server $ chmod a+r /tmp/pycairo* - $ scp pycairo-x.x.x.tar.bz2 pycairo-x.x.x.tar.bz2.sha1 cairographics.org:/srv/cairo.freedesktop.org/www/releases @@ -55,12 +57,12 @@ $ scp pycairo-x.x.x.tar.bz2 pycairo-x.x.x.tar.bz2.sha1 cairographics.org:/srv/ca Subject: ANN: pycairo release X.X.X now available -Pycairo is a set of Python bindings for the multi-platform 2D graphics -library cairo. +Pycairo is a set of Python 3.x bindings for the multi-platform 2D +graphics library cairo. http://cairographics.org http://cairographics.org/pycairo -A pycairo release X.X.X is available from: +Pycairo release X.X.X is available from: http://cairographics.org/releases/pycairo-X.X.X.tar.bz2 http://cairographics.org/releases/pycairo-X.X.X.tar.bz2.sha1 @@ -79,7 +81,6 @@ $ ssh cairographics.org 9) Increment pycairo version number, to next odd number in: doc/conf.py - README wscript $ git commit $ git push origin master diff --git a/doc/.gitignore b/doc/.gitignore index 7ae2974..fd39b78 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -1,6 +1,3 @@ _build _static _templates -html_docs_create.sh -html_docs_upload.sh - diff --git a/doc/pycairo_c_api.rst b/doc/pycairo_c_api.rst index 9e0b58f..5f2becd 100644 --- a/doc/pycairo_c_api.rst +++ b/doc/pycairo_c_api.rst @@ -56,6 +56,7 @@ Objects:: PycairoImageSurface PycairoPDFSurface PycairoPSSurface + PycairoRecordingSurface PycairoSVGSurface PycairoWin32Surface PycairoXCBSurface @@ -83,6 +84,7 @@ Types:: PyTypeObject *ImageSurface_Type; PyTypeObject *PDFSurface_Type; PyTypeObject *PSSurface_Type; + PyTypeObject *RecordingSurface_Type; PyTypeObject *SVGSurface_Type; PyTypeObject *Win32Surface_Type; PyTypeObject *XCBSurface_Type; diff --git a/doc/reference/constants.rst b/doc/reference/constants.rst index 9487059..19c0993 100644 --- a/doc/reference/constants.rst +++ b/doc/reference/constants.rst @@ -50,6 +50,7 @@ cairo.HAS HAS_PDF_SURFACE HAS_PNG_FUNCTIONS HAS_PS_SURFACE + HAS_RECORDING_SURFACE HAS_SVG_SURFACE HAS_USER_FONT HAS_QUARTZ_SURFACE diff --git a/doc/reference/surfaces.rst b/doc/reference/surfaces.rst index 4b092e7..2058a2a 100644 --- a/doc/reference/surfaces.rst +++ b/doc/reference/surfaces.rst @@ -584,6 +584,67 @@ is a multi-page vector surface backend. .. versionadded:: 1.2 +class RecordingSurface(:class:`Surface`) +======================================== + +A *RecordingSurface* is a surface that records all drawing operations at the +highest level of the surface backend interface, (that is, the level of paint, +mask, stroke, fill, and show_text_glyphs). The recording surface can then be +"replayed" against any target surface by using it as a source surface. + +If you want to replay a surface so that the results in target will be +identical to the results that would have been obtained if the original +operations applied to the recording surface had instead been applied to the +target surface, you can use code like this:: + + cr = cairo.Context(target) + cr.set_source_surface(recording_surface, 0.0, 0.0) + cr.paint() + +A *RecordingSurface* is logically unbounded, i.e. it has no implicit +constraint on the size of the drawing surface. However, in practice this is +rarely useful as you wish to replay against a particular target surface with +known bounds. For this case, it is more efficient to specify the target +extents to the recording surface upon creation. + +The recording phase of the recording surface is careful to snapshot all +necessary objects (paths, patterns, etc.), in order to achieve accurate +replay. + +.. class:: RecordingSurface(content, rectangle) + + :param content: the :ref:`CONTENT <constants_CONTENT>` for the new surface + :param rectangle: a 4-tuple of float, or None to record unbounded operations. + :returns: a new *RecordingSurface* + + Creates a *RecordingSurface* which can be used to record all drawing + operations at the highest level (that is, the level of paint, mask, stroke, + fill and show_text_glyphs). The *RecordingSurface* can then be "replayed" + against any target surface by using it as a source to drawing operations. + + The recording phase of the *RecordingSurface* is careful to snapshot all + necessary objects (paths, patterns, etc.), in order to achieve accurate + replay. + + .. versionadded:: 1.10.2 + + .. method:: ink_extents() + + :returns: (x0,y0,width,height) a 4-tuple of float + + * x0: the x-coordinate of the top-left of the ink bounding box + * y0: the y-coordinate of the top-left of the ink bounding box + * width: the width of the ink bounding box + * height: the height of the ink bounding box + + Measures the extents of the operations stored within the + *RecordingSurface*. This is useful to compute the required size of an + *ImageSurface* (or equivalent) into which to replay the full sequence of + drawing operations. + + .. versionadded:: 1.10.2 + + class SVGSurface(:class:`Surface`) ================================== diff --git a/src/cairomodule.c b/src/cairomodule.c index cbe6605..675676d 100644 --- a/src/cairomodule.c +++ b/src/cairomodule.c @@ -1,6 +1,7 @@ /* -*- mode: C; c-basic-offset: 2 -*- * - * Copyright © 2003,2010 James Henstridge, Steven Chaplin + * Copyright © 2003 James Henstridge + * Copyright © 2004-2011 Steven Chaplin * * This file is part of pycairo. * @@ -116,6 +117,11 @@ static Pycairo_CAPI_t CAPI = { #else 0, #endif +#ifdef CAIRO_HAS_RECORDING_SURFACE + &PycairoRecordingSurface_Type, +#else + 0, +#endif #ifdef CAIRO_HAS_SVG_SURFACE &PycairoSVGSurface_Type, #else @@ -247,6 +253,10 @@ PyInit__cairo(void) if (PyType_Ready(&PycairoPSSurface_Type) < 0) return NULL; #endif +#ifdef CAIRO_HAS_RECORDING_SURFACE + if (PyType_Ready(&PycairoRecordingSurface_Type) < 0) + return; +#endif #ifdef CAIRO_HAS_SVG_SURFACE if (PyType_Ready(&PycairoSVGSurface_Type) < 0) return NULL; @@ -337,6 +347,12 @@ PyInit__cairo(void) PyModule_AddObject(m, "PSSurface", (PyObject *)&PycairoPSSurface_Type); #endif +#ifdef CAIRO_HAS_RECORDING_SURFACE + Py_INCREF(&PycairoRecordingSurface_Type); + PyModule_AddObject(m, "RecordingSurface", + (PyObject *)&PycairoRecordingSurface_Type); +#endif + #ifdef CAIRO_HAS_SVG_SURFACE Py_INCREF(&PycairoSVGSurface_Type); PyModule_AddObject(m, "SVGSurface", (PyObject *)&PycairoSVGSurface_Type); @@ -399,6 +415,11 @@ PyInit__cairo(void) #else PyModule_AddIntConstant(m, "HAS_PS_SURFACE", 0); #endif +#if CAIRO_HAS_RECORDING_SURFACE + PyModule_AddIntConstant(m, "HAS_RECORDING_SURFACE", 1); +#else + PyModule_AddIntConstant(m, "HAS_RECORDING_SURFACE", 0); +#endif #if CAIRO_HAS_SVG_SURFACE PyModule_AddIntConstant(m, "HAS_SVG_SURFACE", 1); #else diff --git a/src/private.h b/src/private.h index ba59daf..197f935 100644 --- a/src/private.h +++ b/src/private.h @@ -1,6 +1,7 @@ /* -*- mode: C; c-basic-offset: 2 -*- * - * Copyright © 2003,2010 James Henstridge, Steven Chaplin + * Copyright © 2003 James Henstridge + * Copyright © 2004-2011 Steven Chaplin * * This file is part of pycairo. * @@ -75,6 +76,10 @@ extern PyTypeObject PycairoPDFSurface_Type; extern PyTypeObject PycairoPSSurface_Type; #endif +#if CAIRO_HAS_RECORDING_SURFACE +extern PyTypeObject PycairoRecordingSurface_Type; +#endif + #if CAIRO_HAS_SVG_SURFACE extern PyTypeObject PycairoSVGSurface_Type; #endif diff --git a/src/py3cairo.h b/src/py3cairo.h index 1aaf743..324ac37 100644 --- a/src/py3cairo.h +++ b/src/py3cairo.h @@ -1,6 +1,7 @@ /* -*- mode: C; c-basic-offset: 2 -*- * - * Copyright © 2003,2010 James Henstridge, Steven Chaplin + * Copyright © 2003 James Henstridge + * Copyright © 2004-2011 Steven Chaplin * * This file is part of pycairo. * @@ -76,14 +77,15 @@ typedef struct { PyObject *base; /* base object used to create surface, or NULL */ } PycairoSurface; -#define PycairoImageSurface PycairoSurface -#define PycairoPDFSurface PycairoSurface -#define PycairoPSSurface PycairoSurface -#define PycairoSVGSurface PycairoSurface -#define PycairoWin32Surface PycairoSurface +#define PycairoImageSurface PycairoSurface +#define PycairoPDFSurface PycairoSurface +#define PycairoPSSurface PycairoSurface +#define PycairoRecordingSurface PycairoSurface +#define PycairoSVGSurface PycairoSurface +#define PycairoWin32Surface PycairoSurface #define PycairoWin32PrintingSurface PycairoSurface -#define PycairoXCBSurface PycairoSurface -#define PycairoXlibSurface PycairoSurface +#define PycairoXCBSurface PycairoSurface +#define PycairoXlibSurface PycairoSurface /* get C object out of the Python wrapper */ #define PycairoContext_GET(obj) (((PycairoContext *)(obj))->ctx) @@ -120,6 +122,7 @@ typedef struct { PyTypeObject *ImageSurface_Type; PyTypeObject *PDFSurface_Type; PyTypeObject *PSSurface_Type; + PyTypeObject *RecordingSurface_Type; PyTypeObject *SVGSurface_Type; PyTypeObject *Win32Surface_Type; PyTypeObject *Win32PrintingSurface_Type; @@ -171,6 +174,11 @@ typedef struct { #define PycairoPSSurface_Type *(Pycairo_CAPI->PSSurface_Type) #endif +#if CAIRO_HAS_RECORDING_SURFACE +#define PycairoRecordingSurface_Type \ + *(Pycairo_CAPI->RecordingSurface_Type) +#endif + #if CAIRO_HAS_SVG_SURFACE #define PycairoSVGSurface_Type *(Pycairo_CAPI->SVGSurface_Type) #endif diff --git a/src/surface.c b/src/surface.c index 5e630b5..35ca169 100644 --- a/src/surface.c +++ b/src/surface.c @@ -1,6 +1,7 @@ /* -*- mode: C; c-basic-offset: 2 -*- * - * Copyright © 2003,2010 James Henstridge, Steven Chaplin + * Copyright © 2003 James Henstridge + * Copyright © 2004-2011 Steven Chaplin * * This file is part of pycairo. * @@ -31,6 +32,7 @@ * PycairoImageSurface, * PycairoPDFSurface, * PycairoPSSurface, + * PycairoRecordingSurface, * PycairoSVGSurface, * PycairoWin32Surface, * PycairoWin32PrintingSurface, @@ -72,6 +74,11 @@ PycairoSurface_FromSurface (cairo_surface_t *surface, PyObject *base) { type = &PycairoPSSurface_Type; break; #endif +#if CAIRO_HAS_RECORDING_SURFACE + case CAIRO_SURFACE_TYPE_RECORDING: + type = &PycairoRecordingSurface_Type; + break; +#endif #if CAIRO_HAS_SVG_SURFACE case CAIRO_SURFACE_TYPE_SVG: type = &PycairoSVGSurface_Type; @@ -348,8 +355,6 @@ static PyMethodDef surface_methods[] = { PyTypeObject PycairoSurface_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - //PyObject_HEAD_INIT(NULL) - //0, /* ob_size */ "cairo.Surface", /* tp_name */ sizeof(PycairoSurface), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -647,8 +652,6 @@ static PyMethodDef image_surface_methods[] = { PyTypeObject PycairoImageSurface_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - // PyObject_HEAD_INIT(NULL) - //0, /* ob_size */ "cairo.ImageSurface", /* tp_name */ sizeof(PycairoImageSurface), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -772,8 +775,6 @@ static PyMethodDef pdf_surface_methods[] = { PyTypeObject PycairoPDFSurface_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - // PyObject_HEAD_INIT(NULL) - //0, /* ob_size */ "cairo.PDFSurface", /* tp_name */ sizeof(PycairoPDFSurface), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -975,8 +976,6 @@ static PyMethodDef ps_surface_methods[] = { PyTypeObject PycairoPSSurface_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - //PyObject_HEAD_INIT(NULL) - //0, /* ob_size */ "cairo.PSSurface", /* tp_name */ sizeof(PycairoPSSurface), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -1021,6 +1020,97 @@ PyTypeObject PycairoPSSurface_Type = { #endif /* CAIRO_HAS_PS_SURFACE */ +/* Class RecordingSurface(Surface) ---------------------------------------- */ +#ifdef CAIRO_HAS_RECORDING_SURFACE + +static PyObject * +recording_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) { + int content; + cairo_rectangle_t extents, *extents_ptr; + cairo_surface_t *sfc; + PyObject *extents_tuple; + + if (!PyArg_ParseTuple(args, "iO:RecordingSurface.__new__", + &content, &extents_tuple)) + return NULL; + + if (extents_tuple == Py_None) { + extents_ptr = NULL; + } else { + if (!PyArg_ParseTuple(extents_tuple, "dddd", &extents.x, &extents.y, + &extents.width, &extents.height)) { + PyErr_SetString(PyExc_TypeError, + "RecordingSurface() argument 2 must be a " + "4-tuple of float"); + return NULL; + } + extents_ptr = &extents; + } + + Py_BEGIN_ALLOW_THREADS; + sfc = cairo_recording_surface_create (content, extents_ptr); + Py_END_ALLOW_THREADS; + return PycairoSurface_FromSurface (sfc, NULL); +} + +static PyObject * +recording_surface_ink_extents (PycairoRecordingSurface *o) { + double x0, y0, width, height; + cairo_recording_surface_ink_extents(o->surface, &x0, &y0, &width, &height); + return Py_BuildValue("(dddd)", x0, y0, width, height); +} + +static PyMethodDef recording_surface_methods[] = { + {"ink_extents", (PyCFunction)recording_surface_ink_extents, METH_NOARGS }, + {NULL, NULL, 0, NULL}, +}; + +PyTypeObject PycairoRecordingSurface_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "cairo.RecordingSurface", /* tp_name */ + sizeof(PycairoRecordingSurface), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* 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 */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + recording_surface_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PycairoSurface_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + (newfunc)recording_surface_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ +}; +#endif /* CAIRO_HAS_RECORDING_SURFACE */ + + /* Class SVGSurface(Surface) ----------------------------------------------- */ #ifdef CAIRO_HAS_SVG_SURFACE #include <cairo-svg.h> @@ -1090,8 +1180,6 @@ static PyMethodDef svg_surface_methods[] = { PyTypeObject PycairoSVGSurface_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - //PyObject_HEAD_INIT(NULL) - //0, /* ob_size */ "cairo.SVGSurface", /* tp_name */ sizeof(PycairoSVGSurface), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -1156,8 +1244,6 @@ static PyMethodDef win32_surface_methods[] = { PyTypeObject PycairoWin32Surface_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - //PyObject_HEAD_INIT(NULL) - //0, /* ob_size */ "cairo.Win32Surface", /* tp_name */ sizeof(PycairoWin32Surface), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -1219,8 +1305,6 @@ static PyMethodDef win32_printing_surface_methods[] = { PyTypeObject PycairoWin32PrintingSurface_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - //PyObject_HEAD_INIT(NULL) - //0, /* ob_size */ "cairo.Win32PrintingSurface", /* tp_name */ sizeof(PycairoWin32PrintingSurface), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -1369,8 +1453,6 @@ static PyMethodDef xcb_surface_methods[] = { PyTypeObject PycairoXCBSurface_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - //PyObject_HEAD_INIT(NULL) - //0, /* ob_size */ "cairo.XCBSurface", /* tp_name */ sizeof(PycairoXCBSurface), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -1450,8 +1532,6 @@ static PyMethodDef xlib_surface_methods[] = { PyTypeObject PycairoXlibSurface_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - //PyObject_HEAD_INIT(NULL) - //0, /* ob_size */ "cairo.XlibSurface", /* tp_name */ sizeof(PycairoXlibSurface), /* tp_basicsize */ 0, /* tp_itemsize */ diff --git a/test/api_test.py b/test/api_test.py index c83bf99..0fe0772 100644 --- a/test/api_test.py +++ b/test/api_test.py @@ -77,6 +77,10 @@ def test_surface(): f, w, h = tfi.TemporaryFile(mode='w+b'), 100, 100 s = cairo.PSSurface(f, w, h) + if cairo.HAS_RECORDING_SURFACE: + s = cairo.RecordingSurface(cairo.CONTENT_COLOR, None) + s = cairo.RecordingSurface(cairo.CONTENT_COLOR, (1,1,10,10)) + if cairo.HAS_SVG_SURFACE: f, w, h = tfi.TemporaryFile(mode='w+b'), 100, 100 s = cairo.SVGSurface(f, w, h) @@ -8,7 +8,7 @@ d = top APPNAME='pycairo' VERSION='1.10.1' -cairo_version_required = '1.10.0' +cairo_version_required = '1.10.2' def options(ctx): |