[cairo] group/pattern API

Carl Worth cworth at cworth.org
Fri Dec 2 14:48:22 PST 2005


On Sat, 12 Nov 2005 20:48:42 -0800, Vladimir Vukicevic wrote:
> > 1) Intermediate compositing. ...
> >
> > 2) Repeating pattern construction. ...
> >
> > 3) Mask construction. ...
> 
> The expected usage for (1) and (2) is pretty different -- (3) could go
> either way, but I think it leans mostly towards (2).  For (1),
> returning a pattern, especially one with a surface that's resizing
> based on the content, doesn't make sense to me

For (1), the pattern returned no longer has a surface that's
resizing. All of the surface resizing happens begin begin_group and
end_group and no surface resizing happens after the caller receives a
handle to the pattern.

>                                                -- at what origin do I
> paint that pattern if I want to just use an intermediate compositing
> surface?  If we say (0,0) always, then it becomes useless for case
> (2).

I think the key concept here is that if the user paints the resulting
pattern without applying any additional transformation matrix to it,
then all the elements drawn within the group will appear at the same
location as if they were drawn without any group.

Of course, we assume we'll be using an efficiently-sized surface to
implement this group pattern, so there will need to be an offset in
that pattern to get things in the right place.

And I think we'll want that offset to be "hidden" from the pattern's
matrix. That is, given:

	cairo_pattern_t *pattern;
	cairo_matrix_t matrix;

	cairo_matrix_init_translate (&matrix, 5.0, 5.0);
	pattern = cairo_end_group (cr);

then the difference between:

	cairo_set_source (cr, pattern);
	cairo_paint (cr);

and:

	cairo_pattern_set_matrix (pattern, &matrix);
	cairo_set_source (cr, pattern);
	cairo_paint (cr);

Should be a difference of a (5,5) offset of the pattern, rather than
the pattern jumping up to a position that's offset from the target
surface origin by (5,5).

For pattern construction, it would certainly be easier to just avoid
it as a use case for now in this API, (that is, the resulting pattern
could be logically the same size and position as the target
surface). 

> I suggest that we add distinct support for groups and patterns, with a
> group being composited into the parent surface with the current
> compositing operator and an alpha parameter to end_group (much like
> cairo_paint_with_alpha()):
> 
> void cairo_begin_group (cairo_t *cr);
> void cairo_end_group (cairo_t *cr, double alpha);

A _long_ time ago we had an API very much like this in cairo, (see the
long commented-out cairo_push_group and cairo_pop_group in cairo.h).
The reason this got pulled out was that the entanglement of the "end
group" operation along with the "paint the group" operation caused
confusion with regard to what graphics state is in place at the time
of the implicit paint. (This was particularly confusing as
cairo_pop_group also had an implicit cairo_restore in it).

My latest proposal to return a cairo_pattern_t* from cairo_end_group
is precisely intended to resolve this problem by separating the
painting operation from the "end group" operation.

> groups should nest; you should be able to begin_group as many times as
> you'd like.

Absolutely. Does returning a cairo_pattern_t* rather than implicitly
painting cause any problem here?

> For patterns, I'd like to suggest a different interface -- I don't
> think use cases (2) and (3) have much to do with the current cairo_t,
> other than determining the surface type to use.  So, I suggest
> something like this:
> 
> cairo_t *cairo_pattern_begin (cairo_surface_t *reference_surface);
> cairo_pattern_t *cairo_pattern_end (cairo_t *pattern_cairo);

I don't like this. So far, we've been talking about creating a new
kind of magic pattern named a "group", (which happens to have its
create function split into begin/end_group rather than "group_create",
but that's the best we've come up with).

But also adding a magic cairo_t, with no name, and its create
functionality in "pattern_begin" seems very wrong.

If this functionality were really important, I think I'd much rather
see it use cairo_create and some means of setting a surface as
"growable". But then again, the pattern use case we're talking about
here is distinct in that the use case _requires_ a size anyway. So
we don't get any benefit from not using the existing size-based
surface create functions anyway.

(We could still imagine doing some lazy allocation and growing
surfaces to back explicitly-sized surfaces, but that's a potential
optimization that would not have any API impact).

Phew. Hopefully that made some sense, but if not, I can take another
whack at explaining it.

If nothing else, it's been fun to be back doing some API design
again. I haven't been able to do that for quite some time with cairo.

-Carl
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.freedesktop.org/archives/cairo/attachments/20051202/553dd03e/attachment.pgp


More information about the cairo mailing list