[cairo] API Shakeup: cairo_output_stream_t and
cairo_surface_finish()
Kristian Høgsberg
krh at bitplanet.net
Tue Feb 15 20:42:14 PST 2005
Hi,
Here is a proposal for an output stream abstraction to be used for
cairo's output stream needs. We add a new object,
cairo_output_stream_t, to the user API:
typedef cairo_status_t (*cairo_output_stream_write_func_t)
(const void *data,
size_t length,
void *closure);
cairo_output_stream_t *
cairo_output_stream_create
(cairo_output_stream_write_func_t write_func,
cairo_destroy_func_t destroy_func,
void *closure);
void
cairo_output_stream_destroy
(cairo_output_stream_t *stream);
A cairo_output_stream_t object is passed to the
cairo_pdf_surface_create() constructor:
s = cairo_pdf_surface_create (stream, width_inches, height_inches);
and the image surface helper function to write PNG files will take a stream:
cairo_image_surface_write_png (surface, stream);
We still provide stdio convenience functions:
FILE *fp;
fp = fopen (...);
cairo_pdf_surface_create_for_file (fp, width_inches, height_inches);
This just wraps the stdio functions in a cairo_output_stream_object_t
and calls cairo_pdf_surface_create (). Owen suggests we use filenames
with the convenience functions instead, but that has encoding problems
on Windows and using stdio makes it easy to use in a web graphics
application.
Finally, there is cairo_surface_finish(), which we discussed Monday and
which has been discussed on the list earlier. The proposal at this
point is:
cairo_status_t
cairo_surface_finish (cairo_surface_t *surface);
This function will write out the file trailer, or in general, complete
the surface and drop all references to external resources. For the PDF
backend it means that the FILE will not be used anymore and can be
closed, for the Xlib backend it means the drawable can be freed.
Further drawing the the surface will not affect the surface but set the
surface status to an error. When cairo_surface_finish() is called,
cairo will destroy the output stream at which point the output stream
destroy_func will be called to release resources associated with the
output stream. After this, cairo is guaranteed to no longer call the
write_func.
When the reference count for a surface reaches zero, cairo will call
cairo_surface_finish() if it hasn't been called already, before
destroying the surface.
For internal backend use the following functions will be available:
cairo_private cairo_status_t
cairo_output_stream_write (cairo_output_stream_t *stream,
const void *data, size_t length);
cairo_private cairo_status_t
cairo_output_stream_printf (cairo_output_stream_t *stream,
const char *fmt, ...);
cairo_private cairo_status_t
cairo_output_stream_status (cairo_output_stream_t *stream);
The reason for having cairo_output_stream_status() is that in case of
failure the output functions become inert, so you can do:
cairo_output_stream_write (stream, data1, data1_size);
cairo_output_stream_write (stream, data2, data2_size);
return cairo_output_stream_status (stream);
and get the right behavior even if the first write fails.
Issues:
- cairo takes ownership of the cairo_output_stream_t when you create a
surface for the output stream, and frees it after calling the
destroy_func. Maybe the solution is to just not do this, rename
destroy_func to finish_func, and let the user call
cairo_stream_destroy() either after calling cairo_surface_finish() or in
a user data destroy callback.
- the write_func is a user provided callback that will be called from
deep inside cairo internals... keithp, is this something you object to?
- should we keep the cairo_output_stream_t object out of the public API
entirely and make the user pass in write_func, destroy_func, and closure
as extra arguments to the surface create functions?
cheers,
Kristian
More information about the cairo
mailing list