Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cairo.ScriptSurface. Fixes #17 #47

Merged
merged 1 commit into from
Jul 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions cairo/cairomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,13 @@ PYCAIRO_MOD_INIT(_cairo)

if (PyType_Ready(&PycairoDevice_Type) < 0)
return PYCAIRO_MOD_ERROR_VAL;

#ifdef CAIRO_HAS_SCRIPT_SURFACE
if (PyType_Ready(&PycairoScriptDevice_Type) < 0)
return PYCAIRO_MOD_ERROR_VAL;
if (PyType_Ready(&PycairoScriptSurface_Type) < 0)
return PYCAIRO_MOD_ERROR_VAL;
#endif

if (PyType_Ready(&PycairoRegion_Type) < 0)
return PYCAIRO_MOD_ERROR_VAL;
Expand Down Expand Up @@ -380,8 +385,12 @@ PYCAIRO_MOD_INIT(_cairo)
Py_INCREF(&PycairoDevice_Type);
PyModule_AddObject(m, "Device", (PyObject *)&PycairoDevice_Type);

#ifdef CAIRO_HAS_SCRIPT_SURFACE
Py_INCREF(&PycairoScriptDevice_Type);
PyModule_AddObject(m, "ScriptDevice", (PyObject *)&PycairoScriptDevice_Type);
Py_INCREF(&PycairoScriptSurface_Type);
PyModule_AddObject(m, "ScriptSurface", (PyObject *)&PycairoScriptSurface_Type);
#endif

#ifdef CAIRO_HAS_IMAGE_SURFACE
Py_INCREF(&PycairoImageSurface_Type);
Expand Down
10 changes: 0 additions & 10 deletions cairo/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,6 @@
#include "config.h"
#include "private.h"


typedef struct {
PyObject_HEAD
cairo_device_t *device;
} PycairoDevice;

static void
device_dealloc(PycairoDevice *obj) {
if (obj->device) {
Expand Down Expand Up @@ -139,10 +133,6 @@ PyTypeObject PycairoDevice_Type = {
#if CAIRO_HAS_SCRIPT_SURFACE
#include <cairo-script.h>

typedef struct {
PycairoDevice base;
} PycairoScriptDevice;

static const cairo_user_data_key_t device_base_object_key;

static void
Expand Down
10 changes: 10 additions & 0 deletions cairo/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ PyObject *PycairoScaledFont_FromScaledFont (cairo_scaled_font_t *scaled_font);
extern PyTypeObject PycairoSurface_Type;
extern PyTypeObject PycairoImageSurface_Type;

typedef struct {
PyObject_HEAD
cairo_device_t *device;
} PycairoDevice;

#if CAIRO_HAS_SCRIPT_SURFACE
typedef PycairoDevice PycairoScriptDevice;
extern PyTypeObject PycairoScriptSurface_Type;
#endif

#if CAIRO_HAS_PDF_SURFACE
extern PyTypeObject PycairoPDFSurface_Type;
#endif
Expand Down
92 changes: 92 additions & 0 deletions cairo/surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ PycairoSurface_FromSurface (cairo_surface_t *surface, PyObject *base) {
case CAIRO_SURFACE_TYPE_XLIB:
type = &PycairoXlibSurface_Type;
break;
#endif
#if CAIRO_HAS_SCRIPT_SURFACE
case CAIRO_SURFACE_TYPE_SCRIPT:
type = &PycairoScriptSurface_Type;
break;
#endif
default:
type = &PycairoSurface_Type;
Expand Down Expand Up @@ -1169,6 +1174,93 @@ PyTypeObject PycairoPDFSurface_Type = {
};
#endif /* CAIRO_HAS_PDF_SURFACE */

#ifdef CAIRO_HAS_SCRIPT_SURFACE
#include <cairo-script.h>

typedef PycairoSurface PycairoScriptSurface;

static PyObject *
script_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
cairo_content_t content;
double width, height;
PyObject *pydevice;

if (!PyArg_ParseTuple (args, "O!idd:ScriptSurface.__new__",
&PycairoScriptDevice_Type, &pydevice, &content, &width, &height))
return NULL;

return PycairoSurface_FromSurface (
cairo_script_surface_create (
((PycairoDevice*)pydevice)->device, content, width, height),
NULL);
}

static PyObject *
script_surface_create_for_target (PyTypeObject *type, PyObject *args) {
PyObject *pydevice, *target;

if (!PyArg_ParseTuple (args, "O!O!:ScriptSurface.create_for_target",
&PycairoScriptDevice_Type, &pydevice, &PycairoSurface_Type, &target))
return NULL;

return PycairoSurface_FromSurface (
cairo_script_surface_create_for_target (
((PycairoDevice*)pydevice)->device, ((PycairoSurface*)target)->surface),
NULL);
}

static PyMethodDef script_surface_methods[] = {
{"create_for_target",
(PyCFunction)script_surface_create_for_target, METH_VARARGS | METH_CLASS},
{NULL, NULL, 0, NULL},
};

PyTypeObject PycairoScriptSurface_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"cairo.ScriptSurface", /* tp_name */
sizeof(PycairoScriptSurface), /* 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 */
script_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)script_surface_new, /* tp_new */
0, /* tp_free */
0, /* tp_is_gc */
0, /* tp_bases */
};

#endif /* CAIRO_HAS_SCRIPT_SURFACE */


/* Class PSSurface(Surface) ----------------------------------------------- */
#ifdef CAIRO_HAS_PS_SURFACE
Expand Down
34 changes: 34 additions & 0 deletions docs/reference/surfaces.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1022,3 +1022,37 @@ if it is available.
:returns: the width of the X Drawable underlying the surface in pixels.

.. versionadded:: 1.2


class ScriptSurface(:class:`Surface`)
=====================================

The script surface provides the ability to render to a native script that
matches the cairo drawing model. The scripts can be replayed using tools under
the util/cairo-script directory, or with cairo-perf-trace.


.. class:: ScriptSurface(script, content, width, height)

:param cairo.ScriptDevice script: the script (output device)
:param cairo.Content content: the content of the surface
:param float width: width in pixels
:param float height: height in pixels
:rtype: cairo.ScriptSurface
:raises cairo.Error:

Create a new surface that will emit its rendering through ``script``.

.. versionadded:: 1.14

.. classmethod:: create_for_target(script, target)

:param cairo.ScriptDevice script: the script (output device)
:param cairo.Surface target: a target surface to wrap
:rtype: cairo.ScriptSurface
:raises cairo.Error:

Create a proxy surface that will render to ``target`` and record the
operations to ``device``.

.. versionadded:: 1.14
34 changes: 34 additions & 0 deletions tests/test_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,37 @@ def test_surface_from_stream_closed_before_finished():
fileobj.close()
with pytest.raises(IOError):
surface.finish()


def test_script_surface():
f = io.BytesIO()
dev = cairo.ScriptDevice(f)
surface = cairo.ScriptSurface(dev, cairo.Content.COLOR_ALPHA, 42, 10)
assert isinstance(surface, cairo.ScriptSurface)
cairo.Context(surface).paint()
dev.flush()
assert b"42" in f.getvalue()
assert b"paint" in f.getvalue()


def test_script_surface_create_for_target():
# paint the script proxy
f = io.BytesIO()
dev = cairo.ScriptDevice(f)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
script = cairo.ScriptSurface.create_for_target(dev, surface)
assert isinstance(script, cairo.ScriptSurface)
ctx = cairo.Context(script)
ctx.set_source_rgb(0.25, 0.5, 1.0)
ctx.paint()
assert b"paint" in f.getvalue()
surface.flush()
image_data = bytes(surface.get_data())

# check if the result is the same
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
ctx = cairo.Context(surface)
ctx.set_source_rgb(0.25, 0.5, 1.0)
ctx.paint()
surface.flush()
assert bytes(surface.get_data()) == image_data