[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