summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Chaplin <>2011-06-19 14:18:41 +0800
committerSteve Chaplin <>2011-06-19 14:18:41 +0800
commit4bdcaf76248fc18253e4130fd1304b6f3b0ac3ab (patch)
tree9bef881b53fab366d86c7facdcfcc12ef8a90cfd
parent4323d440e99deb91ee2e98b6b845ab17cf9b6bd8 (diff)
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--RELEASING17
-rw-r--r--doc/.gitignore3
-rw-r--r--doc/pycairo_c_api.rst2
-rw-r--r--doc/reference/constants.rst1
-rw-r--r--doc/reference/surfaces.rst61
-rw-r--r--src/cairomodule.c23
-rw-r--r--src/private.h7
-rw-r--r--src/py3cairo.h24
-rw-r--r--src/surface.c118
-rw-r--r--test/api_test.py4
-rw-r--r--wscript2
11 files changed, 221 insertions, 41 deletions
diff --git a/RELEASING b/RELEASING
index 358b683..e25473c 100644
--- a/RELEASING
+++ b/RELEASING
@@ -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)
diff --git a/wscript b/wscript
index c7299ef..7a8c75f 100644
--- a/wscript
+++ b/wscript
@@ -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):