Consider an innocent looking function to create a stipple pattern:
color = gtk.gdk.color_parse ("mediumseagreen")
stipple_data = array.array('B', [0, 0, 0, 255, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 255])
stipple_data = stipple_data = color.red >> 8
stipple_data = stipple_data = color.green >> 8
stipple_data = stipple_data = color.blue >> 8
surface = cairo.ImageSurface.create_for_data (stipple_data,
2, 2, 8)
pattern = cairo.SurfacePattern(surface)
This function is buggy because stipple_data will go out of scope and leave the ImageSurface pointing at garbage. Worrying about reference counting is not Pythonic, therefore cairo.ImageSurface.create_for_data should INCREF the data parameter and schedule it to be DECREFed when the surface is destroyed.
I'm aware of the problems of data used by pycairo going out of scope and causing problems. Pycairo already deals correctly with these situations, AFAIK.
Have a look at pycairo-surface.c
image_surface_create_for_data() reads stipple_data into 'obj'
PycairoSurface_FromSurface(surface, obj) is called and 'obj' is received as the 'base' argument
Py_XINCREF(base); is called to keep the object alive.
At the end of the ImageSurface's life, in surface_dealloc(), Py_CLEAR(o->base); is called to release the object.
Have a read through the code to see if you agree that its already working OK. Or see if you can write a test case that demonstrates pycairo reading corrupted data.
Created attachment 20951 [details]
With this program I get:
gjc@dark-tower:gnome$ python /tmp/test_goocairo.py
[113, 179, 60, 255, 0, 0, 0, 0, 0, 0, 0, 0, 113, 179, 60, 255]
data is no more <weakref at 0x2a49720; dead>
Which clearly demonstrates that data is being freed too soon.
I'm using pycairo 1.4.12.
Created attachment 20954 [details]
simpler test case
OK, it turns out that the problem is that, although the surface references the data, the pattern does not reference the surface, at least in pycairo 1.4.12.
That is a problem.
I've updated PycairoPattern to be like PycairoContext and PycairoSurface - it has a 'base' field which can be used to keep the base object alive. This fixes the problem shown in your test case, and changes the pycairo C API.
Changing the API of an existing public function is causing several types of breakage and upgrade problems. See http://bugzilla.gnome.org/show_bug.cgi?id=581895