[whatwg] Canvas - globalCompositeOperation
ddailey at zoominternet.net
Tue Mar 27 17:11:05 PDT 2007
I suspect you already are aware of this but in addition to the references
the SVG 1.1 reco gives examples of the Porter-Duff composites
It appears that Opera is not handling them properly in SVG either:
----- Original Message -----
From: "Philip Taylor" <excors+whatwg at gmail.com>
To: <whatwg at lists.whatwg.org>
Sent: Tuesday, March 27, 2007 7:30 PM
Subject: [whatwg] Canvas - globalCompositeOperation
> It has been mentioned before  that globalCompositeOperation is
> poorly defined - the spec has a note saying "The source-* descriptions
> below don't define what should happen with semi-transparent regions"
> and is vague about non-transparent colours too - and it is not
> implemented interoperably. I haven't seen any descriptions of what it
> ought to do, so this is an attempt to explain and describe what I
> believe should be specified.
> Most of the operations are defined in the Porter-Duff paper , which
> does say how semi-transparent regions should be handled. My summary of
> A single pixel with 25% alpha is considered to be a large number of
> subpixels of which a uniformly-random 25% are totally solid and 75%
> are totally transparent - the subpixels only have 1-bit alpha. When
> you combine that 25% alpha pixel 'A' with a 50% alpha pixel 'B', you
> expect 25%*50% of the subpixels to overlap, while (1-25%)*(1-50%) of
> subpixels are covered by neither pixel, and similar for the subpixels
> that are covered by only 'A' or only 'B'.
> The composite operators define how you choose which of the inputs (0,
> A, B) is used as the output of the subpixel, for each of the four
> possible coverage cases (!A & !B, !A & B, A & !B, A & B). Then you
> just (conceptually) average all the subpixels, to get the actual pixel
> The P-D paper assumes colours are represented with pre-multiplied
> alpha (where nonpremul[r, g, b, a] == premul[r*a, g*a, b*a, a]), e.g.
> 50%-transparent bright red is premul[0.5, 0, 0, 0.5]. The canvas
> (inheriting from CSS) and seemingly much of the rest of the world
> (e.g. Cairo, and most humans) use non-pre-multiplied alpha in their
> APIs, e.g. 50% transparent red is "rgba(255, 0, 0, 0.5)". But the
> compositing equations won't work nicely with non-pre-multiplied alpha,
> and implementations appear to use pre-multiplied alpha internally, so
> the operation should be specified in the pre-multiplied form. (I'll
> use lowercase c for pre-multiplied colour components, uppercase C for
> Taking that into account gives the following algorithm for most of the
> composite operators:
> | Operator | FA | FB
> | -----------------+------+------
> | source-over | 1 | 1-aA
> | destination-over | 1-aB | 1
> | source-in | aB | 0
> | destination-in | 0 | aA
> | source-out | 1-aB | 0
> | destination-out | 0 | 1-aA
> | source-atop | aB | 1-aA
> | destination-atop | 1-aB | aA
> | xor | 1-aB | 1-aA
> | copy | 1 | 0
> | lighter | 1 | 1
> | cO = cA*FA + cB*FB
> | aO = aA*FA + aB*FB
> | where cX is the pre-multiplied colour component of pixel X, in the
> | [0, 1]; aX is the alpha component of pixel X in the range [0, 1]; A and
> | are the source and destination pixels respectively; O is the output
> | The calculation of aO must be clamped to the range [0, 1].
> ("lighter" can result in aO > 1, hence the need to clamp it.)
> Only "darker" cannot fit in this table (given that FA is a function of
> aB, and FB is a function of aA).
> To compare the main implementations (Firefox trunk 20070326, Opera
> 9.20, Safari 2.0.4), there is a demonstration at
> and example outputs at
> "over", "in", "out" and "copy" are all correct (in that they match the
> above algorithm).
> "xor" is correct in Firefox and Safari, but incorrect in Opera; Opera
> appears to be using the pre-multiplied equations on the
> non-pre-multiplied colours (i.e. doing CO = CA*FA + CB*FB, where CX is
> the non-pre-multiplied colour component).
> "atop" and "lighter" are correct in Firefox and Safari, but incorrect
> in Opera; I don't know what Opera is doing.
> "darker" is messy:
> Firefox's "darker" is implemented as:
> Operator | FA | FB
> darker [saturate] | min(1, (1-aB)/aA) | 1
> It seems this can't easily be hardware-accelerated - the Cairo GL
> backend  doesn't support CAIRO_OPERATOR_SATURATE, and says
> case CAIRO_OPERATOR_SATURATE:
> /* XXX: This line should never be reached. Glitz backend should
> bail out earlier if saturate operator is used. OpenGL can't do
> saturate with pre-multiplied colors. Solid colors can still be done as
> we can just un-pre-multiply them. However, support for that will have
> to be added to glitz. */
> Safari gives completely different output, and is very close to
> implementing it with non-pre-multiplied colours as:
> CO = 1 - (1-CA)*aA - (1-CB)*aB
> aO = aA + aB
> except not quite like that (see the bottom-right box in the example
> page), and I don't know what it's really doing. Opera is also quite
> like that, except more different.
> KHTML  doesn't implement either "lighter" or "darker" - it treats
> them as "source-over". Rhino Canvas  does the same. Both are
> relying on existing graphics libraries for the actual drawing, which
> don't provide those operations - see QPainter::CompositionMode  and
> java.awt.AlphaComposite .
> Conclusion: The above definition is sensible (in my opinion) and works
> (in practice).
> Opera needs to fix "xor" and "atop". Firefox and Safari are fine.
> [...at least when ignoring other compositing bugs, unrelated to this
> colour calculation.]
> I would be happy if "darker" was removed from the spec - there isn't
> an obvious definition for it, and it's not interoperably implemented
> at all and it sounds like it never will be. Existing implementations
> can add "apple-plusdarker", "moz-saturate", etc, if they still want to
> provide the old functionality.
> "lighter" seems much easier to define, and more useful, so I think
> it's perhaps worth keeping - but it looks like a pain for those using
> Qt/Java/etc libraries which don't support anything other than the
> standard Porter-Duff operators, and I don't know if it's a difficulty
> for Opera to fix their implementation of it. Does anyone have views on
> this or on "darker"?
>  http://keithp.com/~keithp/porterduff/p253-porter.pdf
>  http://doc.trolltech.com/4.1/qpainter.html#CompositionMode-enum
>  http://java.sun.com/j2se/1.5.0/docs/api/java/awt/AlphaComposite.html
> Philip Taylor
> excors at gmail.com
More information about the whatwg