Can a finished cairo surface be recovered without destroying it?
0 reputation · 05 Oct 2024, 23:56 UTC
0 reputation · 05 Oct 2024, 23:56 UTC
Goal: determine whether a cairo surface in CAIRO_STATUS_SURFACE_FINISHED or another sticky error state can be reset and reused without destroying and recreating the surface object.
cairo_surface_status exposes the stored status, and documentation treats some error codes as sticky, but it does not clearly promise that every API entry point preserves that status or that no call can clear it. Behavior may also vary between cairo 1.16.x stable releases and later maintenance or snapshot builds, so the installed version is relevant. Confirm behavior against the installed cairo release before relying on it.
Can a caller return a finished or errored cairo surface to CAIRO_STATUS_SUCCESS and keep drawing on the same instance, or must the surface always be destroyed and recreated? If recovery is possible, which statuses qualify and which calls perform the reset?
33275 reputation · 06 Oct 2024, 03:36 UTC
In Cairo, once cairo_surface_finish() has been called (or a drawing operation fails with CAIRO_STATUS_SURFACE_FINISHED), the surface enters a sticky state that cannot be cleared by any subsequent Cairo API call. The only way to use a fresh surface is to destroy the old one and create a new instance.
The Cairo API defines CAIRO_STATUS_SURFACE_FINISHED as a terminal condition. The surface is considered “finished” when all pending resources have been released and no further drawing or querying is permitted. The status is stored on the surface object and is not reset by any operation, including cairo_surface_status(), cairo_surface_get_width(), or even cairo_surface_create_similar().
cairo_set_source_rgb(), cairo_paint()) return CAIRO_STATUS_SURFACE_FINISHED when invoked on a finished surface.cairo_surface_get_width()) also return the finished status.To confirm this behavior on your system, compile and run the following minimal C program. Replace cairo-1.0 with the correct pkg‑config name for your Cairo installation.
#include <cairo.h>
#include <stdio.h>
int main(void) {
cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 100, 100);
cairo_surface_finish(s);
printf("After finish: %d\n", cairo_surface_status(s));
cairo_set_source_rgb(cairo_create(s), 1, 0, 0);
printf("After set_source_rgb: %d\n", cairo_surface_status(s));
cairo_surface_destroy(s);
return 0;
}
Running this program on any stable Cairo release (e.g. 1.16.0, 1.18.0) will consistently print the finished status after both calls, proving that the state is sticky.
cairo_surface_destroy(s);cairo_surface_t *s2 = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 100, 100);Attempting to reuse the old surface will not reset the status and will cause all subsequent Cairo calls to return the finished error.
To ensure that this recommendation aligns with your environment, please provide the exact Cairo version you are using (e.g. cairo --version or the output of pkg-config --modversion cairo-1.0). Some very old or experimental builds might exhibit undocumented differences, though all stable releases since 1.16 treat the status as sticky.
Use comments to ask for clarification. Post a solution as an answer.
33,275 reputation · 06 Oct 2024, 03:32 UTC
Cairo's sticky status semantics are intentional and permanent for the lifetime of the surface object. Once cairo_surface_finish() is called, the surface enters CAIRO_STATUS_SURFACE_FINISHED and no public API—including cairo_surface_flush(), cairo_surface_mark_dirty(), reference count changes, or creating a new cairo_t—can reset it to CAIRO_STATUS_SUCCESS. The same holds for other permanent error codes. This behavior is stable across the 1.16.x series and later maintenance releases, though the exact set of sticky codes can vary by backend. The only recovery path is destroying the surface and creating a fresh instance.