[cairo] Meta surface proposal

Owen Taylor otaylor at redhat.com
Sun Feb 6 13:22:59 PST 2005


Here's some more details about what I was thinking about for doing 
printer fallbacks.

cairo_meta_surface_t is a helper surface type that is used for surface
types where:

 - There are some operations we want to implement natively,
   but for other operations we need to use fallbacks.
 - We can't read back from the surface

API
===

 void cairo_meta_surface_create (cairo_format_t format,
                                 int            width,
                                 int            height);

The width/height here are the width/height we would use if drawing
the entire page as an image fallback. The coordinate system used
when drawing primitives is determined by this width/height as well.

 void cairo_meta_surface_set_background_color (cairo_surface_t *surface,
                                               double           red,
                                               double           green,
                                               double           blue);

Tells the meta surface what background color it should composite
against for image fallbacks.

 typedef enum {
   CAIRO_META_MODE_NATIVE,   /* Replay primitives directly */
   CAIRO_META_MODE_FALLBACK  /* Replay primitives as images */
 } cairo_meta_mode_t;

 void cairo_meta_surface_set_mode (cairo_surface_t  *surface,
                                   cairo_meta_mode_t fallback);

Informs the meta surface how subsequently drawn primitives should
be replayed. If a NATIVE primitive overlaps with a FALLBACK primitive,
the NATIVE primitive will be coerced to FALLBACK as necessary.

 void cairo_meta_surface_replay (cairo_surface_t *surface,
                                 cairo_surface_t *target);

Replays the meta surface to a target native surface using a mix of
native drawing and images.

Usage example
==============

When a cairo_win32_surface_t was created targeting, say, a printer, it
would immediately create a meta surface. Then
cairo_win32_composite_trapezoids() would schematically
look like:

 /* Determine whether we need to draw the trapezoids as a fallback */

 if (surface->meta_surface && !surface->replaying) {
     if (need_fallback)
         cairo_meta_surface_set_mode (surface, CAIRO_META_MODE_FALLBACK); 
     else
         cairo_meta_surface_set_mode (surface, CAIRO_META_MODE_NATIVE); 

     _cairo_surface_composite_trapezoids (surface->meta_surface, ...)
 } else {
     if (need_fallback)
        return CAIRO_INT_STATUS_UNSUPPORTED:

     /* Draw trapezoids natively */
 }

The meta surface would be replayed when show_page() was called on
the win32 surface, or when the win32 surface was otherwise "flushed".

Implementation 
==============

The interface above could be implemented at many different levels of
sophistication. Here's a basic idea:

 1. When a primitive is drawn to the meta surface, we add it to 
    an internal stream of primitives. We also compute a bounding region
    for the primitive and store that along with the primitive. 
    The bounding region doesn't have to be exact, but just using
    a bounding rectangle will produce suboptimal results.

 2. Before replaying the surface, we compute the transitive closure
    of each fallback primitive with other primitives under intersection
    and mark all native primitives in that set as fallback.
    
    Possible implementation algorithm:

     - Create a queue containing all the fallback primitives
     - For each item in the queue, intersect it with all native
       primitives (data structures such as quadtrees could be
       used to make this < O(n) in the normal case), if any
       items intersect, mark them as fallback and add them to
       the end of the queue.

 3. Determine a set of rectangles that bounds the all fallback
    primitives. The exactness of the bound won't affect rendered
    quality, but it will affect efficiency of the output stream.
    The rectangles could overlap.

 4. For each rectangle in the set, create an image of that size,
    clear it to the background color,
    draw the intersecting fallback primitives onto it in their
    original order, then draw the image to the target surface.

 5. Then draw all remaining native primitives onto the destination
    surface in their original order.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
Url : http://lists.freedesktop.org/archives/cairo/attachments/20050206/e26882bf/attachment.pgp


More information about the cairo mailing list