[cairo] Redoing SOURCE and CLEAR
Behdad Esfahbod
behdad at cs.toronto.edu
Wed Aug 17 08:55:13 PDT 2005
Hi Owen,
I like your general reasoning, but after thinking a bit more I
don't like your proposal. I've made a mental model like this:
- Any area out of clip wouldn't be touched,
- mask is tayloring the source,
- taylored source is applied to dest according to the operator
And so I can easily reason that if I use the SOURCE operator,
no evidence of dest would remain. And that matches the old
behavior.
If we change according to your proposal, I don't see any easy way
to achieve the old behavior other than first clearing and then
doing source.
Moreover, it reduces SOURCE to IN somehow, but a broken one. The
fact that it's differentiating between a alpha of 0 in the
source, and a point ouside the mask is confusing. So for example
these two are not the same:
cr = cairo_create (scratch);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_rectangle (cr, x, y, width, height);
cairo_set_source_rgba (cr, 0, 0, 0);
cairo_fill (cr);
cairo_destroy (cr);
cr = cairo_create (canvas);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_surface (cr, scratch);
cairo_paint (cr);
cairo_destory (cr);
and:
cr = cairo_create (canvas);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle (cr, x, y, width, height);
cairo_set_source_rgba (cr, 0, 0, 0);
cairo_fill (cr);
cairo_destroy (cr);
What's happening is that in the first case, I have a transparent
surface with a black rectangle inside. I paint my surface with
that and expect to get a transparent surface with a black
rectangle inside, that I get. In the second case, I don't have
such a surface, but try to get the same effect by defining a path
and color that represent the rectangle, and I *do the same
operation*, but what I will get is garbage outside, not
transparency.
My 2 cents though,
behdad
On Wed, 17 Aug 2005, Owen Taylor wrote:
> So, what would you expect:
>
> cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
> cairo_set_source_surface (cr, image, x, y);
> cairo_rectangle (cr, x, y, width, height);
> cairo_fill();
>
> and:
>
> cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
> cairo_rectangle (cr, x, y, width, height);
> cairo_fill();
>
> to do? If you guessed:
>
> Copy the rectangle x,y,width,height from the image
> to the target surface and clear the rest of the
> target surface.
>
> And:
>
> Clear the entire target surface
>
> Then you have a good understanding of the current definition of the
> cairo operators. But most likely, you didn't. The fact that
> SOURCE and CLEAR affect areas beyond the mask is quite unexpected
> and if we leave it this way will likely be a VFAQ for cairo.
>
> Is there a reasonable alternate definition? First, some useful
> notation that Carl came up with yesterday.
>
> define:
>
> C ? A : B
>
> as:
>
> (A IN C) ADD (B OUT C)
>
> In my unbounded operators mail, I showed, that
>
> (src IN mask IN clip) OP dest
>
> Is equivalent to:
>
> clip ? (src IN mask) OP dest : dest
>
> For a large set of the Cairo operators: OVER, ATOP, DEST,
> DEST_OVER, DEST_OUT, XOR, ADD, and we used that as a inspiration
> to make the second form the *definition* of the rendering equation
> for the unbounded operators SOURCE, CLEAR, IN, OUT, DEST_IN,
> DEST_ATOP. And I think it's the right definition for the latter
> 4. But for SOURCE and CLEAR, it isn't working out so great.
>
> Using basically the same process, we can pull out the
> MASK the same way we pulled out the clip and get:
>
> (mask IN clip) ? src OP dest : dest
>
> Again, this is the same for the 7 "normal" operators, but it
> gives something different for unbounded operators. This equation
> gives what we intuitively expect for CLEAR and SOURCE.
>
> So, the proposal here is to logically divide the operators into
> 4 groups by what definition we use:
>
> OVER, ATOP, DEST, DEST_OVER, DEST_OUT, XOR, ADD
>
> All definitions equivalent
>
> SOURCE, CLEAR
>
> (mask IN clip) ? src OP dest : dest
>
> IN, OUT, DEST_IN, DEST_ATOP
>
> clip ? (src IN mask) OP dest : dest
>
> SATURATE
>
> (src IN mask IN clip) OP dest
>
> I've attached images that show the old and new versions of CLEAR and
> SOURCE compared with two similar operators - DEST_OUT and OVER.
>
> I've also attached a patch implementing the change including some
> new test cases.
>
> Comments on the patch:
>
> - In my earlier unbounded-operators patch, I was very careful
> so that the surface backends worked correctly with our
> definitions for all operators.
>
> That's not preserved here. composite() works right for SOURCE
> and CLEAR only when there is no mask, and show_text() and
> composite_trapezoids() don't work right at all with these
> operators.
>
> This is covered up in the cairo-gstate.c code and I've added
> assertions to the wrapper functions to trap these cases.
>
> Implementing CLEAR in the backends wouldn't be hard other than
> duplication - it's just DEST_OUT with a solid source.
> Implementing SOURCE is a little more of a pain - you have
> to do two passes - first a pass with the mask, then
> an ADD pass with src IN mask.
>
> It might still be worth it to keep the concepts clean, but
> what I have now is workable.
>
> - The implementation of SOURCE in cairo-gstate.c results in
> an extra intermediate mask being created for glyphs, since
> we create one in show_glyphs() (either on the server or
> in the cairo-ft-font.c code) and then draw it onto another
> mask. The image case could easily be fixed by special-casing
> ADD in _cairo_ft_scaled_font_show_glyphs(). The xlib case
> could almost equally easily be fixed by not passing a mask
> format to the server for ADD.
>
> (A danger of this change is that people will start using
> SOURCE rather than OVER, and SOURCE is inherently less
> efficient)
>
> Comments on compatibility:
>
> - In general, there hasn't been much time for people to get
> used to the new behavior of SOURCE and CLEAR. There probably
> is more code still broken by it than code that expects it.
>
> - If you are using SOURCE and CLEAR with paint() - and that's
> really the only sensible usage with the current definitions,
> then there is no change.
>
> (It's not quite as useless to use SOURCE with a shape as
> it is to use CLEAR with a shape - SOURCE with a shape could
> be used to skip clearing a surface. But it's not useful
> enough to expect anybody to have found it in two weeks.)
>
> My guess is that nobody will notice the change except for the
> good, so it's compatible enough to go in at this point.
> I'm not *happy* about suggesting it at this point, but the
> only real alternative would be to document the strangeness
> then later introduce a new operator - COPY, say, that behaves
> as I'm suggesting that SOURCE should do here.
>
> Regards,
> Owen
>
>
--behdad
http://behdad.org/
More information about the cairo
mailing list