[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