Skip to content
Draft
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
5 changes: 4 additions & 1 deletion cairo/cairomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <Python.h>

#include "private.h"
#include "dynamic.h"

#ifdef CAIRO_HAS_PDF_SURFACE
#include <cairo-pdf.h>
Expand Down Expand Up @@ -124,7 +125,9 @@ static Pycairo_CAPI_t CAPI = {

static PyObject *
pycairo_cairo_version (PyObject *self, PyObject *ignored) {
return PyLong_FromLong (cairo_version());
RETURN_NULL_IF_NOT_HAS_CAIRO_FUNC(cairo_version);

return PyLong_FromLong (PYCAIRO_GET_CAIRO_FUNC(cairo_version)());
}

static PyObject *
Expand Down
49 changes: 49 additions & 0 deletions cairo/dynamic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <stddef.h>
#ifdef _WIN32
#include <windows.h>
#else
#define _GNU_SOURCE
#include <dlfcn.h>
#endif

#include "dynamic.h"

#define INIT_CAIRO_FUNC(field, symbol_name) \
.field = {symbol_name, NULL, 0}

_Pycairo_cairo_funcs_t _Pycairo_cairo_funcs = {
INIT_CAIRO_FUNC(cairo_version, "cairo_version"),
};

void* _Pycairo_get_cairo_symbol(const char* symbol_name) {
static void* cairo_handle = NULL;
static int handle_initialized = 0;

if (!handle_initialized) {
handle_initialized = 1;
#ifdef _WIN32
HMODULE handle;
if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCSTR)cairo_create, &handle)) {
cairo_handle = handle;
}
#else
Dl_info info;
if (dladdr((void*)cairo_create, &info) != 0) {
cairo_handle = dlopen(info.dli_fname, RTLD_LAZY | RTLD_NOLOAD);
}
#endif
}

if (!cairo_handle)
return NULL;

#ifdef _WIN32
return (void*)GetProcAddress((HMODULE)cairo_handle, symbol_name);
#else
dlerror();
void* symbol = dlsym(cairo_handle, symbol_name);
return (dlerror() == NULL) ? symbol : NULL;
#endif
}
50 changes: 50 additions & 0 deletions cairo/dynamic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef _PYCAIRO_DYNAMIC_H_
#define _PYCAIRO_DYNAMIC_H_

#include <cairo.h>

void* _Pycairo_get_cairo_symbol(const char* symbol_name);

#define _PYCAIRO_DECLARE_CAIRO_FUNC(name, ret_type, params) \
struct { \
const char* symbol_name; \
ret_type (*ptr)params; \
int checked; \
} name

typedef struct {
_PYCAIRO_DECLARE_CAIRO_FUNC(cairo_version, int, (void));
} _Pycairo_cairo_funcs_t;

extern _Pycairo_cairo_funcs_t _Pycairo_cairo_funcs;

#ifdef CAIRO_WIN32_STATIC_BUILD

#define PYCAIRO_GET_CAIRO_FUNC(field) (field)

#define RETURN_NULL_IF_NOT_HAS_CAIRO_FUNC(field)

#define PYCAIRO_HAS_CAIRO_FUNC(field) (1)

#else

#define PYCAIRO_GET_CAIRO_FUNC(field) \
(_Pycairo_cairo_funcs.field.checked ? _Pycairo_cairo_funcs.field.ptr : \
(_Pycairo_cairo_funcs.field.checked = 1, \
_Pycairo_cairo_funcs.field.ptr = _Pycairo_get_cairo_symbol(_Pycairo_cairo_funcs.field.symbol_name)))

#define PYCAIRO_HAS_CAIRO_FUNC(field) \
(PYCAIRO_GET_CAIRO_FUNC(field) != NULL)

#define RETURN_NULL_IF_NOT_HAS_CAIRO_FUNC(field) \
do { \
if (!PYCAIRO_GET_CAIRO_FUNC(field)) { \
PyErr_Format(PyExc_RuntimeError, "%s not available in this cairo build", \
_Pycairo_cairo_funcs.field.symbol_name); \
return NULL; \
} \
} while(0)

#endif

#endif // _PYCAIRO_DYNAMIC_H_
1 change: 1 addition & 0 deletions cairo/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ sources = [
'surface.c',
'textcluster.c',
'textextents.c',
'dynamic.c',
]

foreach python_file : python_sources
Expand Down
Loading