From 5e235e53ef38df9fb75b4d15c372d8be2b0ae05b Mon Sep 17 00:00:00 2001 From: P. J. McDermott Date: Tue, 29 Oct 2013 20:41:39 -0400 Subject: Initial commit. --- (limited to 'debian/patches/add-missing-utils.patch') diff --git a/debian/patches/add-missing-utils.patch b/debian/patches/add-missing-utils.patch new file mode 100644 index 0000000..5772bd7 --- /dev/null +++ b/debian/patches/add-missing-utils.patch @@ -0,0 +1,209 @@ +From: "P. J. McDermott" +Origin: upstream, https://github.com/SimonSapin/cairocffi/tree/master/utils +Subject: Add missing utils/ directory + +--- a/utils/cairocffi_to_pycairo.py ++++ b/utils/cairocffi_to_pycairo.py +@@ -0,0 +1,32 @@ ++import ctypes ++import cairo # pycairo ++import cairocffi ++ ++pycairo = ctypes.PyDLL(cairo._cairo.__file__) ++pycairo.PycairoContext_FromContext.restype = ctypes.c_void_p ++pycairo.PycairoContext_FromContext.argtypes = 3 * [ctypes.c_void_p] ++ctypes.pythonapi.PyList_Append.argtypes = 2 * [ctypes.c_void_p] ++ ++ ++def _UNSAFE_cairocffi_context_to_pycairo(cairocffi_context): ++ # Sanity check. Continuing with another type would probably segfault. ++ if not isinstance(cairocffi_context, cairocffi.Context): ++ raise TypeError('Expected a cairocffi.Context, got %r' ++ % cairocffi_context) ++ ++ # Create a reference for PycairoContext_FromContext to take ownership of. ++ cairocffi.cairo.cairo_reference(cairocffi_context._pointer) ++ # Casting the pointer to uintptr_t (the integer type as wide as a pointer) ++ # gets the context’s integer address. ++ # On CPython id(cairo.Context) gives the address to the Context type, ++ # as expected by PycairoContext_FromContext. ++ address = pycairo.PycairoContext_FromContext( ++ int(cairocffi.ffi.cast('uintptr_t', cairocffi_context._pointer)), ++ id(cairo.Context), ++ None) ++ assert address ++ # This trick uses Python’s C API ++ # to get a reference to a Python object from its address. ++ temp_list = [] ++ assert ctypes.pythonapi.PyList_Append(id(temp_list), address) == 0 ++ return temp_list[0] +--- a/utils/cairo_coverage.py ++++ b/utils/cairo_coverage.py +@@ -0,0 +1,23 @@ ++import inspect ++import pycparser ++import cairocffi ++ ++ALL_THE_CODE = ''.join( ++ line ++ for module in [ ++ cairocffi, cairocffi.surfaces, cairocffi.patterns, ++ cairocffi.fonts, cairocffi.context, cairocffi.matrix] ++ for line in inspect.getsourcelines(module)[0]) ++ ++ ++class Visitor(pycparser.c_ast.NodeVisitor): ++ def visit_Decl(self, node): ++ for _, child in node.children(): ++ if isinstance(child, pycparser.c_ast.FuncDecl): ++ if ('cairo.' + node.name) not in ALL_THE_CODE and not ( ++ node.name.endswith('user_data')): ++ print(node.name) ++ break ++ ++print('cairo functions never used in cairocffi:\n') ++Visitor().visit(pycparser.CParser().parse(cairocffi.constants._CAIRO_HEADERS)) +--- a/utils/compare_pycairo.py ++++ b/utils/compare_pycairo.py +@@ -0,0 +1,24 @@ ++import cairo as pycairo ++import cairocffi ++ ++# We want the real pycairo ++assert pycairo is not cairocffi ++ ++ ++print('Missing pycairo API:\n') ++ ++for name in dir(pycairo): ++ pycairo_obj = getattr(pycairo, name) ++ cairocffi_obj = getattr(cairocffi, name, None) ++ if name.startswith(('_', 'version', 'CAPI')): ++ continue ++ if cairocffi_obj is None: ++ print(name) ++ elif isinstance(pycairo_obj, type): ++ for method_name in dir(pycairo_obj): ++ if method_name.startswith('__'): ++ continue ++ pycairo_method = getattr(pycairo_obj, method_name) ++ cairocffi_method = getattr(cairocffi_obj, method_name, None) ++ if cairocffi_method is None: ++ print('%s.%s' % (name, method_name)) +--- a/utils/pango_example.py ++++ b/utils/pango_example.py +@@ -0,0 +1,56 @@ ++# coding: utf8 ++import cairocffi ++import cffi ++ ++ ++ffi = cffi.FFI() ++ffi.include(cairocffi.ffi) ++ffi.cdef(''' ++ /* GLib */ ++ typedef void* gpointer; ++ void g_object_unref (gpointer object); ++ ++ /* Pango and PangoCairo */ ++ typedef ... PangoLayout; ++ typedef enum { ++ PANGO_ALIGN_LEFT, ++ PANGO_ALIGN_CENTER, ++ PANGO_ALIGN_RIGHT ++ } PangoAlignment; ++ int pango_units_from_double (double d); ++ PangoLayout * pango_cairo_create_layout (cairo_t *cr); ++ void pango_cairo_show_layout (cairo_t *cr, PangoLayout *layout); ++ void pango_layout_set_width (PangoLayout *layout, int width); ++ void pango_layout_set_alignment ( ++ PangoLayout *layout, PangoAlignment alignment); ++ void pango_layout_set_markup ( ++ PangoLayout *layout, const char *text, int length); ++''') ++gobject = ffi.dlopen('gobject-2.0') ++pango = ffi.dlopen('pango-1.0') ++pangocairo = ffi.dlopen('pangocairo-1.0') ++ ++gobject_ref = lambda pointer: ffi.gc(pointer, gobject.g_object_unref) ++units_from_double = pango.pango_units_from_double ++ ++ ++def write_example_pdf(target): ++ pt_per_mm = 72 / 25.4 ++ width, height = 210 * pt_per_mm, 297 * pt_per_mm # A4 portrait ++ surface = cairocffi.PDFSurface(target, width, height) ++ context = cairocffi.Context(surface) ++ context.translate(0, 300) ++ context.rotate(-0.2) ++ ++ layout = gobject_ref( ++ pangocairo.pango_cairo_create_layout(context._pointer)) ++ pango.pango_layout_set_width(layout, units_from_double(width)) ++ pango.pango_layout_set_alignment(layout, pango.PANGO_ALIGN_CENTER) ++ markup = u'Hi from Παν語!' ++ markup = ffi.new('char[]', markup.encode('utf8')) ++ pango.pango_layout_set_markup(layout, markup, -1) ++ pangocairo.pango_cairo_show_layout(context._pointer, layout) ++ ++ ++if __name__ == '__main__': ++ write_example_pdf(target='pango_example.pdf') +--- a/utils/pycairo_to_cairocffi.py ++++ b/utils/pycairo_to_cairocffi.py +@@ -0,0 +1,25 @@ ++import cairo # pycairo ++import cairocffi ++ ++ ++def _UNSAFE_pycairo_context_to_cairocffi(pycairo_context): ++ # Sanity check. Continuing with another type would probably segfault. ++ if not isinstance(pycairo_context, cairo.Context): ++ raise TypeError('Expected a cairo.Context, got %r' % pycairo_context) ++ ++ # On CPython, id() gives the memory address of a Python object. ++ # pycairo implements Context as a C struct: ++ # typedef struct { ++ # PyObject_HEAD ++ # cairo_t *ctx; ++ # PyObject *base; ++ # } PycairoContext; ++ # Still on CPython, object.__basicsize__ is the size of PyObject_HEAD, ++ # ie. the offset to the ctx field. ++ # ffi.cast() converts the integer address to a cairo_t** pointer. ++ # [0] dereferences that pointer, ie. read the ctx field. ++ # The result is a cairo_t* pointer that cairocffi can use. ++ return cairocffi.Context._from_pointer( ++ cairocffi.ffi.cast('cairo_t **', ++ id(pycairo_context) + object.__basicsize__)[0], ++ incref=True) +--- a/utils/tests.py ++++ b/utils/tests.py +@@ -0,0 +1,27 @@ ++import io ++import cairo # pycairo ++import cairocffi ++ ++from pycairo_to_cairocffi import _UNSAFE_pycairo_context_to_cairocffi ++from cairocffi_to_pycairo import _UNSAFE_cairocffi_context_to_pycairo ++import pango_example ++ ++ ++def test(): ++ cairocffi_context = cairocffi.Context(cairocffi.PDFSurface(None, 10, 20)) ++ cairocffi_context.scale(2, 3) ++ pycairo_context = _UNSAFE_cairocffi_context_to_pycairo(cairocffi_context) ++ cairocffi_context2 = _UNSAFE_pycairo_context_to_cairocffi(pycairo_context) ++ assert tuple(cairocffi_context.get_matrix()) == (2, 0, 0, 3, 0, 0) ++ assert tuple(cairocffi_context2.get_matrix()) == (2, 0, 0, 3, 0, 0) ++ assert tuple(pycairo_context.get_matrix()) == (2, 0, 0, 3, 0, 0) ++ assert cairocffi_context2._pointer == cairocffi_context._pointer ++ ++ file_obj = io.BytesIO() ++ # Mostly test that this runs without raising. ++ pango_example.write_example_pdf(file_obj) ++ assert file_obj.getvalue().startswith(b'%PDF') ++ ++ ++if __name__ == '__main__': ++ test() -- cgit v0.9.1