[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