[cairo] New PDF backend snapshot
Carl Worth
cworth at cworth.org
Wed Dec 22 09:34:04 PST 2004
On Tue, 21 Dec 2004 17:51:26 -0500, Kristian Høgsberg wrote:
> backend specific "meta data" for the underlying resource. The only
> difference with the PDF backend is that it doesn't rely on an external
> library.
That's the key difference there. I'd like to reduce the amount of
setup-work needed before a user can begin using cairo as much as
possible. When an external library is involved, there's not much I can
do about that in cairo of course, (though higher-level libraries could
still help out).
> It is certainly possible to remove cairo_pdf_document_t from
> the public API and manipulate document properties through the surface
> object. An alternative route would be to split part of the backend into
> it's own library and namespace like glitz.
I would suggest the former. A separate library could make sense if it
were designed to be a general-purpose PDF creation library. I can
think of a lot of things that would belong there that don't fit well
in cairo. But I don't know of any such PDF library that already
exists, and I didn't get the idea that you were interested in creating
one.
And without cairo_pdf_document_t, we could still switch to some
external PDF library later if something does appear.
> >>+void
> >>+cairo_set_target_pdf (cairo_t *cr,
> >>+ cairo_pdf_document_t *document);
>
> I understand that I'm breaking the rule here, I'm just not sure how you
> would do it otherwise.
The convention I want is that the following template should work for
all backend:
cairo_surface_t *surface;
surface = cairo_foo_surface_create (/* foo-specific args*/);
cairo_set_target_surface (cr, surface);
cairo_surface_destroy (surface);
And, for all backends, there is a convenience function that achieves
the same, but without making the user manage a surface object:
cairo_set_target_foo (/* foo-specific args */);
> Of course, dropping cairo_pdf_document_t from
> the API would require both to take the same arguments as
> cairo_pdf_document_create(), which would solve the problem.
Yes.
> But if you
> did that, cairo_pdf_surface_create() could only be used for creating a
> surface to be used with cairo_set_target_surface() - you couldn't
> composite it into another PDF surface since it would belong to a
> different document.
That would be broken. Perhaps what you are calling
cairo_pdf_document_t should just be renamed cairo_pdf_surface_t?
Perhaps not the ideal name, but that's the name imposed by the API
convention. Then it could (internally) contain an cairo_pdf_page_t?
Or perhaps the two structures should be merged? That would certainly
prevent their separation inadvertently breaking the behavior of
cairo_pdf_surface in user-visible ways.
> less). The downside is that it's one of the more advanced features of
> PDF 1.4 so it will be interesting to see what level of support the
> various viewers implement.
It seems rather convenient that a cairo-based PDF viewer is beginning
to come together... But portability of the output is something to keep
in mind.
> I think there is also value in separating out boring container code from
> the interesting cairo code.
Agreed.
> The code is easier to follow when you don't
> have to parse array growing logic intertwined with e.g. bounding box
> computations.
I think the implementation does this fairly well already. All
"grow_by" functions are called only from their corresponding "add"
functions. For example:
_cairo_polygon_add_edge
_cairo_spline_add_point
_cairo_traps_add_trap
There are a few cases of realloc in the code without these layers of
functions and datatypes. But I don't think any of them constitute
confusing or intertwined logic. And that approach is likely the best
where there is only local manipulation of a local array,
(eg. _utf8_to_ucs4).
> The cairo_array_index() was meant to give direct array access, for example:
>
> num_elements = cairo_array_num_elements (array);
Why not just array->num_elements here?
> traps = cairo_array_index (array, index, num_elements);
I don't follow. Why pass num_elements in here? array already contains
that.
>
> for (i = 0; i < num_elements; i++)
> traps[i].top = 100;
I see. If that's the intended usage, then the index argument to
cairo_array_index would always be zero. So the above could be
simplified to:
traps = cairo_array_pointer (array); /* or similar? */
for (i = 0; i < array->num_elements; i++)
traps[i].top = 100;
That's basically just using a function call in place of a cast, but
maybe that would be worthwhile.
>
> (the num_elements argument to cairo_array_index() isn't in the patch,
> but I'm thinking it should be there so the function can assert() that
> the elements the caller wants to access are within bounds).
> As for type
> safety, that's a classic tradeoff with containers
Yes, and it's a tradeoff that I consider carefully.
> and we're already
> passing void pointers to surfaces to the backends.
Certainly one case of void pointers in the code doesn't mean we give
up type-safety anywhere. The virtual backend functions have the
advantage of being explicitly enumerated in a table, and their
implementations immediately cast back to the appropriate type, making
it easy to verify the type-soundness of any backend implementation.
Notice that whenever a backend implementation also needs to directly
call an interface function, I've tried to always call a type-safe
function for which the interface function is just a trivial wrapper,
(eg. _cairo_image_abstract_surface_set_matrix ->
_cairo_image_surface_set_matrix).
I would even prefer to be able to restrict calls of the virtual
functions to calls through the table, but I don't know an easy
mechanism for that.
So, coming back to the array issue. It's not clear to me that we
really need a new cairo_array, but I would prefer something that
didn't use "void *" in the usage pattern. An approach with consistent
or contained structures might allow more of the ugly stuff, (void *,
casts, etc.) to be contained in cairo_array.c. The header files would
also have to be verified and kept consistent, but that seems easier to
do than for all function calls.
My, how I sometimes wish we had a decent language...
-Carl
More information about the cairo
mailing list