[cairo] Proposal: cairo_document_t

Kristian Høgsberg krh at bitplanet.net
Thu Dec 2 21:56:27 PST 2004


Hi,

I've been having some trouble trying to shoe-horn the multi page
nature of PDF documents into the cairo API.  Consider drawing to a
surface, calling show page, drawing some more.  What would it mean to
use that surface as a pattern fill?

I was planning to break some of the state in cairo_pdf_surface_t out
into a cairo_pdf_document_t.  I wanted to do this internally in the
PDF backend, but the more I think about it, the more I think it makes
sense to expose this in the user API.

So, what I propose is that we add a new object to the public API:

     cairo_document_t

A cairo document is a separate object from a cairo surface.  A cairo
document consists of a number of pages, each of which is just a cairo
surface.  A cairo surface doesn't necessarily correspond to a page in
the file, it can be an auxiliary surface used for e.g. a watermark or
pattern fill.

This simplifies the concepts: a surface isn't implicitly also a PDF
document or a collection of pages, a surface is just a canvas that you
paint on.  All surfaces are equal, instead of now where one of them
magically is the PDF file.  A page is just another surface and could
be used as a fill pattern on a later page if that is what you want.

This change implicitly divides the backends into two groups: paginated
backends (PDF, Postscript, SVG?) and simple backends (image, png, X).
Paginated backends should implement the corresponding document type, 
while simple backends do not have a corresponding document type.

At a glance this seems to complicate the API: more objects, more
functions, but I'd argue that it actually simplifies it.  For simple
backends, the API is the same, except we remove cairo_show_page() and
cairo_copy_page().  Thus, the API is smaller and we keep pagination
out of the backends where it doesn't make sense.  On the other hand,
if you are using a paginated backend, the document object is an
intuitive and explicit representation of the document you are
generating, and makes a good home for the pagination functionality.

The API I would like to propose has a function for creating documents
for each paginated backend.  For PDF it would be:

     cairo_document_t *
     cairo_pdf_document_create (FILE	*file,
			       double	width_inches,
			       double	height_inches,
			       double	x_pixels_per_inch,
			       double	y_pixels_per_inch);

Creating a PDF surface takes a reference to the document it is part
of:

     cairo_surface_t *
     cairo_pdf_surface_create (cairo_document_t 	*document,
			      double		width,
			      double		height);

This is in line with the other surface creating functions, but the
document should work as a surface factory so drawing code can add a
new page without knowledge of the backend in use:

     cairo_surface_t *
     cairo_document_create_page (cairo_document_t	*document);

A page is just a regular surface and can be used as the target surface
using cairo_set_target_surface ().  To actually add the page to the
document page sequence use

     cairo_status_t
     cairo_document_add_page (cairo_document_t	*document,
			     cairo_surface_t	*page);

Just like we have cairo_set_target_png() and similar convenience
functions there could be:

     cairo_status_t
     cairo_set_target_new_page (cairo_t		*cr,
			       cairo_document_t	*doc);

which does:

     page = cairo_document_create_page (doc);
     cairo_set_target_surface (cr, page);
     cairo_document_add_page (doc, page);
     cairo_surface_destroy (page);

I think this makes pretty good sense, and I have a good idea of how to
implement it in the PDF backend.  Except for removing the show_page()
and copy_page() functions, there would be no changes to existing
backends.

Comments?

cheers,
Kristian



More information about the cairo mailing list