summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Chaplin <>2011-06-19 13:29:21 +0800
committerSteve Chaplin <>2011-06-19 13:29:21 +0800
commitf3435910d8f5365b45ebd4216f4043383c9e3e19 (patch)
treea7c9d55601880f74272a7988dbdb223b961828da
parent7d268c982bf5d756b6c6eedc86cf108e53cf3a40 (diff)
downloadpy2cairo-f3435910d8f5365b45ebd4216f4043383c9e3e19.tar.gz
Add support for RecordingSurface, using patch (modified) from bug #36854.
Add docs and tests for RecordingSurface. Adding the RecordingSurface to the pycairo API breaks ABI compatibility with previous pycairo versions.
-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/pycairo.h27
-rw-r--r--src/surface.c100
-rw-r--r--test/api_test.py6
8 files changed, 214 insertions, 13 deletions
diff --git a/doc/pycairo_c_api.rst b/doc/pycairo_c_api.rst
index 5e2a175..c228d3e 100644
--- a/doc/pycairo_c_api.rst
+++ b/doc/pycairo_c_api.rst
@@ -50,6 +50,7 @@ Objects::
PycairoImageSurface
PycairoPDFSurface
PycairoPSSurface
+ PycairoRecordingSurface
PycairoSVGSurface
PycairoWin32Surface
PycairoXCBSurface
@@ -77,6 +78,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 0249ea4..63ba990 100644
--- a/doc/reference/surfaces.rst
+++ b/doc/reference/surfaces.rst
@@ -577,6 +577,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 f0d39f8..67d8091 100644
--- a/src/cairomodule.c
+++ b/src/cairomodule.c
@@ -2,7 +2,8 @@
*
* Pycairo - Python bindings for cairo
*
- * Copyright © 2003 James Henstridge, Steven Chaplin
+ * Copyright © 2003 James Henstridge
+ * Copyright © 2004-2011 Steven Chaplin
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -127,6 +128,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
@@ -223,6 +229,10 @@ init_cairo(void)
if (PyType_Ready(&PycairoPSSurface_Type) < 0)
return;
#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;
@@ -305,6 +315,12 @@ init_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);
@@ -379,6 +395,11 @@ init_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 4e09922..bf6ffa5 100644
--- a/src/private.h
+++ b/src/private.h
@@ -2,7 +2,8 @@
*
* Pycairo - Python bindings for cairo
*
- * Copyright © 2003 James Henstridge, Steven Chaplin
+ * Copyright © 2003 James Henstridge
+ * Copyright © 2004-2011 Steven Chaplin
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -86,6 +87,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/pycairo.h b/src/pycairo.h
index c886de8..a5015f0 100644
--- a/src/pycairo.h
+++ b/src/pycairo.h
@@ -2,7 +2,8 @@
*
* Pycairo - Python bindings for cairo
*
- * Copyright © 2003 James Henstridge, Steven Chaplin
+ * Copyright © 2003 James Henstridge
+ * Copyright © 2004-2011 Steven Chaplin
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -87,14 +88,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)
@@ -131,6 +133,7 @@ typedef struct {
PyTypeObject *ImageSurface_Type;
PyTypeObject *PDFSurface_Type;
PyTypeObject *PSSurface_Type;
+ PyTypeObject *RecordingSurface_Type;
PyTypeObject *SVGSurface_Type;
PyTypeObject *Win32Surface_Type;
PyTypeObject *Win32PrintingSurface_Type;
@@ -182,13 +185,19 @@ 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
#if CAIRO_HAS_WIN32_SURFACE
#define PycairoWin32Surface_Type *(Pycairo_CAPI->Win32Surface_Type)
-#define PycairoWin32PrintingSurface_Type *(Pycairo_CAPI->Win32PrintingSurface_Type)
+#define PycairoWin32PrintingSurface_Type \
+ *(Pycairo_CAPI->Win32PrintingSurface_Type)
#endif
#if CAIRO_HAS_XCB_SURFACE
diff --git a/src/surface.c b/src/surface.c
index 2888e9c..d46a77c 100644
--- a/src/surface.c
+++ b/src/surface.c
@@ -2,7 +2,8 @@
*
* Pycairo - Python bindings for cairo
*
- * Copyright © 2003 James Henstridge, Steven Chaplin
+ * Copyright © 2003 James Henstridge
+ * Copyright © 2004-2011 Steven Chaplin
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -83,6 +84,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;
@@ -1014,6 +1020,98 @@ 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 = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "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>
diff --git a/test/api_test.py b/test/api_test.py
index 47d3520..38c6979 100644
--- a/test/api_test.py
+++ b/test/api_test.py
@@ -70,7 +70,7 @@ def test_surface():
f, w, h = cairo.FORMAT_ARGB32, 100, 100
s = cairo.ImageSurface(f, w, h)
assert s.get_format() == f
- assert s.get_width() == w
+ assert s.get_width() == w
assert s.get_height() == h
if cairo.HAS_PDF_SURFACE:
@@ -81,6 +81,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)