[cairo] cairo_meta_surface_t and postscript output

Kristian Høgsberg krh at bitplanet.net
Tue May 10 22:53:18 PDT 2005


I've been investigating how we can produce better postscript output in
cairo, and here's a writeup of my thoughts about the meta surface idea.
We will need some sort of meta surface mechanism as Owen describes here:


The meta surface is a feature internal to cairo, to be used in
implementing fallbacks in the PS backend and the PDF backend.  It's not
a retained mode canvas, an OpenGL display list, or an on-disk file
format.  We need the meta surface in order to be able to do a global
analysis on an entire page, so we can identify which areas can be
rendered natively with postscript operators and which areas must be
rendered using image fallbacks.  The meta surface itself is a fairly
simple construction that just records the backend calls it receives -
I've attached a scratch implementation to flesh out the idea a bit.

The way I imagine this working is that we do a number of passes through
the meta surface: first we render the contents that can be rendered
using postscript operators, then do a pass to identify the areas that
must be rendered using images, and then a pass to actually render them.
Then we composite them on top of the existing postscript output.

Using this approach we'll be replaying the meta surface against an image
surface and we'll be generating postscript output from it.  This raises
some questions in what to record, since an image surface normally only
expects mainly surface->composite_trapezoids() and surface->composite()
call, whereas the postscript output requires surface->show_glyphs() and
surface->fill_path() to be recorded.  One solution could be to use two
meta surfaces with different fallback behaviors, one for the image
fallbacks and one for the postscript output.  However, since we'll most
likely need to queue up all pages before writing the document[1] this
approach is probably too expensive (the meta surface for the image
backend would store all glyphs as images to be composited).

Instead, we could record the highest level primitive in the meta surface
and then do the required fallbacks as necessary when replaying against a
target surface.  For example, we would record surface->show_glyphs() and
when replaying against a target surface the replay code would perform
the same fallbacks as cairo-gstate.c does when a function returns
CAIRO_INT_STATUS_UNSUPPORTED.  With the current set of backend
functions, the only fallbacks we need are for surface->show_glyphs() and
surface->fill_path().  surface->show_glyphs() isn't too bad, in case the
surface doesn't support it, we just ask the font to do it.
surface->fill_path() is worse though, since we need to do the equivalent
of _cairo_gstate_clip_and_composite_trapezoids(), but without a gstate.
What we'll need is something similar to this:

        cairo_surface_fill_path (cairo_operator_t    operator,
                                 cairo_pattern_t    *source,
                                 cairo_surface_t    *surface,
                                 cairo_path_fixed_t *path,
                                 cairo_clip_rec_t   *clip,  [2]
                                 double              tolerance,
                                 cairo_fill_rule_t   fill_rule);

which will try to call surface->fill_path() and if that's not supported,
do the usual fallbacks with the given arguments calling
surface->composite_trapezoids() and surface->composite() as necessary.
This will require some rewriting of cairo-gstate.c, but it's not as bad
as it looks, most of the time we pass the gstate around we're actually
only using the cairo_clip_rec_t part.

We'll also need to fix clipping for postscript and pdf output, but I'll
describe that in another mail, this one is long enough as it is.


[1] We need to output the embedded fonts in the beginning of the
postscript file, but we don't know what subset to output before we've
gone through all the pages.

[2] Now that the struct tag is _cairo_clip_rec, could we rename it to
struct _cairo_clip and cairo_clip_t since that doesn't conflict with the
cairo_clip() function any more?

-------------- next part --------------
A non-text attachment was scrubbed...
Name: cairo-meta-surface.c
Type: text/x-csrc
Size: 15985 bytes
Desc: not available
Url : http://lists.freedesktop.org/archives/cairo/attachments/20050511/790f0a92/cairo-meta-surface.c
-------------- next part --------------
A non-text attachment was scrubbed...
Name: cairo-meta-surface.h
Type: text/x-chdr
Size: 4761 bytes
Desc: not available
Url : http://lists.freedesktop.org/archives/cairo/attachments/20050511/790f0a92/cairo-meta-surface.h

More information about the cairo mailing list