Add HAS_ constants
pycairo has a bunch of constants (see http://cairographics.org/documentation/pycairo/2/reference/constants.html#cairo-has) which define if a given feature is available. It'd be awesome if cairocffi supported these as well.
It’d be nice, but it’s not obvious how to do it.
These constants are given by cairo as #define C preprocessor macros. pycairo is itself written in C, includes cairo.h, and can just use these macros.
cairocffi, on the other hand, uses dlopen to load a shared library at runtime. All we get are the "symbols" exported by the library, which do not include macros. The best we could do is find a cairo.h file on the system and parse it, but there’s no telling whether it matches the cairo version we’ve loaded as a library.
Or, perhaps we can convince the cairo developers to add a function (not a macro) for getting these constants (perhaps as a bitfield).
I've asked the cairo developers to add this in https://bugs.freedesktop.org/show_bug.cgi?id=83050
I’ve just thought of a work-around: just try to use a cairo function, and catch whatever exception CFFI raises for not finding the corresponding symbol.
… which is pretty much what Behdad Esfahbod suggests:
https://bugs.freedesktop.org/show_bug.cgi?id=83050#c1
Well, it would be more convenient for something like cairocffi to try to load a symbol and see if it fails...
Now, if we want to do this with an API compatible with pycairo, we either need to:
- Test for all the HAS_* flags and set them at import time, which has some performance cost. (It’d be useful to profile it and see how it compares with the existing import-time performance cost of parsing a bunch of C headers.)
- Make them magic objects that implements all sorts of magic methods to behave kinda like booleans, but only evaluate themselves when first used.
- To make them be actual booleans but determined lazily, we’d need to replace the cairocffi module with a custom class with properties (descriptors) on it. The latter might be fragile, too much magic.
Or, if pycairo compat can be dropped, this could be more simply a function or a set of functions.
In any case, we’d first need to map each HAS_* constant to a symbol that only exists in the shared library if that feature is enabled. (E.g. HAS_IMAGE_SURFACE to cairo_image_surface_create.)