[cairo] Meta surface proposal
Bill Spitzak
spitzak at d2.com
Mon Feb 7 18:14:06 PST 2005
This sounds like a good idea, though the proposed result sounds wrong to me.
If I understand it right, any primitive that intersects an area that
cannot be done by the backend will result in a "fallback" version. This
could easily mean that the whole page will be a fallback image even if
just a tiny part in the middle requires fallback. This is unlikely to
produce the best version. Instead I would like to see each fallback
operation printed as it's own image, with no effect on subsequent
non-fallback operations. This is especially important if text is drawn
atop a background, the user will be quite happy to see full-resolution
text atop a bitmapped background, certainly better than having the text
turn to bitmaps as well!
As I see it, the meta-surface implements all the back-end functions, and
calls yet another backend for the actual device. This real backend is
very similar except all the backend functions have the ability to say "I
can do this" or "I can't do this".
The meta-surface records *everything* that is sent to it. I agree with
several other posters that PDF is irrelevant here, just store it in an
internal format in memory. If you really think memory use is a problem
my idea allows an image to be used instead with no difference in result.
Or you could switch to an image when the meta stream gets too big.
The meta-surface calls the real backend which will have to decide if it
can draw the operation. On return the new operation is added to the
stored meta data, whether or not it was drawn.
The backend then does something like this:
draw_something(args) {
if (!i_can_do_this(args)) return false;
Rectangle rectangle = area_this_covers(args);
meta_backend->draw_pending_image(rectangle);
do_whatever_to_draw_this();
return true;
}
The meta backend will keep track of a "fallback region" indicating what
area on the output is wrong. When the real backend returns false, the
meta backend will calculate the bounding box of the drawing and add this
to the fallback region.
draw_pending_image() will find the intersection of the passed rectangle
and the fallback region. If non-empty, it will then use the normal Cairo
image backend to draw that region by calling it with the meta stream
that exists so far. It will then call the real backend's "scale and draw
this opaque image" function (which the real backend is required to
implement). It will also remove this region from the fallback region.
When the surface is finalized an extra draw_pending_image() is done for
the entire surface to get all the trailing operators.
I am well aware that my solution can draw things more than once. However
I don't think that is a serious problem, as it will happen a minimal
amount for any real drawings where things are not totally obscured.
Also, in a metafile type output, the obscured data may very well be
useful, removing the overlapping image may reveal an incorrect, but
better-looking, result.
More information about the cairo
mailing list