Skip to content
This repository has been archived by the owner on Nov 17, 2020. It is now read-only.

Commit

Permalink
Add support for RecordingSurface, using patch (modified) from bug #36…
Browse files Browse the repository at this point in the history
…854.

Add docs and tests for RecordingSurface.
Adding the RecordingSurface to the pycairo API breaks ABI compatibility with
previous pycairo versions.
  • Loading branch information
Steve Chaplin committed Jun 19, 2011
1 parent 7d268c9 commit f343591
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 13 deletions.
2 changes: 2 additions & 0 deletions doc/pycairo_c_api.rst
Expand Up @@ -50,6 +50,7 @@ Objects::
PycairoImageSurface
PycairoPDFSurface
PycairoPSSurface
PycairoRecordingSurface
PycairoSVGSurface
PycairoWin32Surface
PycairoXCBSurface
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions doc/reference/constants.rst
Expand Up @@ -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
Expand Down
61 changes: 61 additions & 0 deletions doc/reference/surfaces.rst
Expand Up @@ -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`)
==================================

Expand Down
23 changes: 22 additions & 1 deletion src/cairomodule.c
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion src/private.h
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
27 changes: 18 additions & 9 deletions src/pycairo.h
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
100 changes: 99 additions & 1 deletion src/surface.c
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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>
Expand Down
6 changes: 5 additions & 1 deletion test/api_test.py
Expand Up @@ -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:
Expand All @@ -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)
Expand Down

0 comments on commit f343591

Please sign in to comment.