Re: Radial gradients in <canvas>

Anne van Kesteren wrote:
> On Fri, 26 Oct 2007 14:54:03 +0200, Philip Taylor <pjt47@cam.ac.uk> wrote:
>> Anne van Kesteren wrote:
>>> To quote from an internal discussion: "IMO having an inner circle
>> that goes outside the outer circle is a bug in the script and I would
>> prefer to just throw an error if that happens.
>>
>> In that case, authors would have to remember/discover that
>>    ctx.createRadialGradient(10, 10, 100, 20, 20, 0)
>> is an error and has to be rewritten as
>>    ctx.createRadialGradient(20, 20, 0, 10, 10, 100)
> 
> I haven't checked, but I don't believe that's the issue. 

Okay, I (mis)interpreted "an inner circle that goes outside the outer 
circle" as referring to the start and end circles (in that order) - if 
the order is irrelevant, and the question is only about what happens 
when the smaller circle is not contained within the larger circle, then 
this isn't a problem.

Olivier GENDRIN wrote:
> On 10/26/07, Anne van Kesteren <annevk@opera.com> wrote:
>> We don't like the algorithm given for radial gradients. We think it would
>> be better if it was more like in SVG.
> 
> So why don't we use the SVG algo ? It will even help the UA makers to
> factorise the code or to begin to implement SVG...

SVG 1.1:
   Outer circle defined by (cx, cy, r).
   Focal point defined by (fx, fy). If (fx, fy) is outside the outer 
circle, the focal point is the nearest point on the circle.

SVG Tiny 1.2.
   Outer circle defined by (cx, cy, r).
   Focal point is (cx, cy).

Canvas (now):
   Start circle defined by (x0, y0, r0).
   End circle defined by (x1, y1, r1).
   Regardless of whether one circle is inside the other, an infinite 
cone passing through the two circles is drawn.


The canvas API would have to change incompatibly if it were to use 
exactly the same algorithm as SVG 1.1, since it currently has two 
circles instead of one circle and a point.


Both SVG behaviours can be emulated using the canvas behaviour. When one 
circle is inside the other, the canvas behaviour can be emulated using 
the SVG 1.1 behaviour (with some adjustments to colour stop offsets). So 
it should be possible to share most of the code between canvas and SVG 
implementations despite them having different APIs/algorithms, but the 
one-circle-not-inside-the-other case makes it harder. (Firefox uses the 
same Cairo functions for radial gradients in canvas and SVG, but it 
doesn't follow the canvas spec for one-circle-not-inside.)


Adopting SVG 1.1's focal-point-is-forced-inside-circle behaviour, 
extended to handle two circles, does sound reasonable to me - the 
smaller circle (xs,ys) can just be moved towards the larger circle 
(xl,yl) so that hypot(xs-xl, ys-yl) <= rl-rs, and areas outside the 
larger circle can be always painted in the colour of that circle. That 
should be easy to add to the existing implementations, and wouldn't 
require any changes in the low-level rendering code.

-- 
Philip Taylor
pjt47@cam.ac.uk

Received on Saturday, 27 October 2007 14:18:59 UTC