Please see my in-line comments below:

________________________________
From: [email protected] [mailto:[email protected]] On Behalf Of ext 
Robert O'Callahan
Sent: Monday, January 03, 2011 5:56 PM
To: Szabo Carol (Nokia-MS/Boston)
Cc: [email protected]; [email protected]
Subject: Re: [whatwg] Fwd: RE: Inconsistent behaviour of 
globalCompositeOperation property


HTML5 - Canvas.

I have read this thread (from and of July 2010) and I happen to agree that the 
Safari/Chromium implementation is more intuitive, and likely less expensive to 
implement, therefore I offer these 2 proposals for changing the spec's Drawing 
model section to match what I perceive to be the preference of most people in 
that discussion.

Of note: According to the current Drawing model, an opaque shape's shadow would 
be erased as part of step 6 when drawn with source-in composite Mode if 
globalAlpha is 1, which is probably not the intended behavior.

Version 1:

4.8.11.1.13 Drawing model



When a shape or image is painted, user agents must follow these steps, in the 
order given (or act as if they do):

1. Render the shape or image onto an infinite transparent black bitmap, 
creating image M1, as described in the previous sections except that for the 
purpose of this step every pixel of the image will be considered to be fully 
opaque white and the current fillStyle will be considered to be solid fully 
opaque white and the strokeStyle will be considered fullyOpaque white as well

2. When shadows are drawn, render the shadow from image M1, using a fully 
opaque white shadow color as described in the shadows section, creating image 
M2.

3. Let C1 be a region obtained by intersecting the canvas's cliping region with 
the set of pixels in the canvas that correspond to pixels in M1 (by having the 
same coordinates) that are not fully transparent.

4. Let C2 be a region obtained by intersecting the canvas's cliping region with 
the set of pixels in the canvas that correspond to pixels in M2 (by having the 
same coordinates) that are not fully transparent.

5. Render the shape or image onto an infinite transparent black bitmap, 
creating image A, as described in the previous sections. For shapes, the 
current fill, stroke, and line styles must be honored, and the stroke must 
itself also be subjected to the current transformation matrix.

6. When shadows are drawn, render the shadow from image A, using the current 
shadow styles, creating image B.

7. When shadows are drawn, multiply the alpha component of every pixel in B by 
globalAlpha.

8. When shadows are drawn, composite B with the current canvas bitmap, cliping 
results to region C2 defined above, using the current composition operator.

9. Multiply the alpha component of every pixel in A by globalAlpha.

10. Composite A with the current canvas bitmap, cliping results to region C1 
defined above, using the current composition operator.

Making a binary fully-transparent/not-fully-transparent per-pixel decision to 
create regions C1 and C2 seems like it can't be right in the presence of 
antialiasing.

Suppose we have a path filled with black and operator "copy". Any pixel on the 
edge of that path that gets any nonzero coverage value from antialiasing will 
end up solid black with this proposal. That's going to look very ugly. We'll 
want a solution where any canvas pixel which has a very small amount of 
coverage by the path will be mostly unchanged in the final result.

I do not understand why pixels touched by antialiasing are going to be solid 
black.
The way I understand antialiasing (and maybe I am wrong), pixels that are 
partly touched retained partly their old color and transparency and get parly 
the new color and transparency. More precisely the resulting transparency and 
color components an average of the color component being painted and the 
previous color component weighted by the coverage fraction of the pixel. Hence 
partially covered pixels are partially transparent, thus the background behind 
the canvas should shine through and the partially covered pixels won't be 
entirely black unless that background is black as well. I agree with you though 
that there are cases when inappropriately using globalCompositeOperation can 
yield ugly and perhaps surprising results, such as in the case you described if 
the canvas is completely red before the operation and it is put on a page that 
has green background, thus the shape will acquire an unexpected slightly green 
rim between black and red.
I still believe that this behavior as ugly as it may be in some cases, is still 
preferable to not being able to do shadows when using the copy operation (as 
results from the standard's current language), is more intuitive and less 
resource intensive (to me the less resource intensive is the most important 
part).

Version 2:



4.8.11.1.13 Drawing model



When a shape or image is painted, user agents must follow these steps, in the 
order given (or act as if they do):

1. Render the shape or image onto an infinite transparent black bitmap, 
creating image A, as described in the previous sections. For shapes, the 
current fill, stroke, and line styles must be honored, and the stroke must 
itself also be subjected to the current transformation matrix.

2. When shadows are drawn, render the shadow from image A, using the current 
shadow styles, creating image B.

3. When shadows are drawn, multiply the alpha component of every pixel in B by 
globalAlpha.

4. When shadows are drawn, composite, using the current composition operator, B 
with the current canvas bitmap, cliping results to the cliping region of the 
canvas and to the pixels that would have taken the shadow's color if the 
composition operator would have been source-over and the shadow would have been 
fully opaque and the globalAlpha would have been 1.

5. Multiply the alpha component of every pixel in A by globalAlpha.

6. Composite, using the current composition operator, A with the current canvas 
bitmap, cliping results to the cliping region of the canvas and to the pixels 
that would have taken the shape's or image's pixel color if the composition 
operator would have been source-over and the image would have been fully 
opaque, the fillStyle and strokeStyle would have been a solid fully opaque 
color, and the globalAlpha would have been 1

Again, this needs to be modified to take into account the possibility that some 
pixels are partially covered.

Again, as above, Porter-Duff does not allow for partially applying the 
composition operator. For every pair of source and target pixels, the operator 
is applied. The only question is what are the source pixels to be paired with 
the target. The current language of the standard provides one or even two (in 
case of shadows) source pixel(s) for every target pixel inside the cliping 
region. This is expensive and leads to non-intuitive behaviors such as loss 
shadows with some operations.
My proposal is to apply the composition operator only to pixels covered by the 
source inside the cliping region, of course. The question is the definition of 
covered. I chose for that the pixels that would be changed by a plain solid 
brush/pen in the graphics system. The hope is that the whole trick with 2 
infinite canvases in reality will be just a way of explaining how the result 
should look like and that drawing a shape and compositing an image shall be 
done using simple graphics primitives in-place avoiding the need for extra 
memory and calculation.
I myself have no particular quarel with the current spec language other than 
the fact that it looses shadows and that it is very expensive to implement with 
graphics primitives that I know of, due to the need to alocate large 
intermediary images to be composited later, rather then drawing directly on the 
target bitmap using an appropriate pen and compositor.
If the current spec is to survive, then I suggest instead of steps 3 to 6 of 
the drawing model, to say:

3. When shadows are 
drawn<http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#when-shadows-are-drawn>,
 composite A over B in A.

4. Multiply the alpha component of every pixel in A by 
globalAlpha<http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-globalalpha>.

5. Composite A within the clipping 
region<http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#clipping-region>
 over the current canvas bitmap using the current composition operator.

Given that Microsoft have indicated they're happy with the current spec, and 
are presumably implementing it, I think we should get their explicit approval 
before we change the spec here. I'm still happy with either the current spec or 
your proposed change (after the issues have been addressed).

My understanding from some older thread was that Microsoft favored the approach 
where only pixels covered by the shape are composited, but that information may 
be outdated.

In any case, I wish that this aspect of the spec is firmed up so that 
implementations can be aligned.

Thanks for the review,

Carol

Reply via email to