diff options
author | Steve Chaplin <> | 2011-06-19 13:29:21 +0800 |
---|---|---|
committer | Steve Chaplin <> | 2011-06-19 13:29:21 +0800 |
commit | f3435910d8f5365b45ebd4216f4043383c9e3e19 (patch) | |
tree | a7c9d55601880f74272a7988dbdb223b961828da | |
parent | 7d268c982bf5d756b6c6eedc86cf108e53cf3a40 (diff) | |
download | py2cairo-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.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/pycairo.h | 27 | ||||
-rw-r--r-- | src/surface.c | 100 | ||||
-rw-r--r-- | test/api_test.py | 6 |
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) |