@@ -107,11 +107,13 @@ type drawState struct {
107107 // Current paint.ColorOp, if any.
108108 color color.NRGBA
109109
110- // Current paint.LinearGradientOp.
110+ // Current paint.LinearGradientOp and paint.RadialGradientOp .
111111 stop1 f32.Point
112112 stop2 f32.Point
113113 color1 color.NRGBA
114114 color2 color.NRGBA
115+ // Current paint.RadialGradientOp.
116+ radiusy float32
115117}
116118
117119type pathOp struct {
@@ -187,9 +189,11 @@ type material struct {
187189 opaque bool
188190 // For materialTypeColor.
189191 color f32color.RGBA
190- // For materialTypeLinearGradient.
192+ // For materialTypeLinearGradient and materialTypeRadialGradient .
191193 color1 f32color.RGBA
192194 color2 f32color.RGBA
195+ // For materialTypeRadialGradient.
196+ radiusy float32
193197 // For materialTypeTexture.
194198 data imageOpData
195199 uvTrans f32.Affine2D
@@ -212,9 +216,20 @@ type imageOpData struct {
212216}
213217
214218type linearGradientOpData struct {
215- stop1 f32.Point
219+ stop1 f32.Point
220+ stop2 f32.Point
221+
222+ color1 color.NRGBA
223+ color2 color.NRGBA
224+ }
225+
226+ type radialGradientOpData struct {
227+ stop1 f32.Point
228+ stop2 f32.Point
229+
230+ radiusy float32
231+
216232 color1 color.NRGBA
217- stop2 f32.Point
218233 color2 color.NRGBA
219234}
220235
@@ -294,6 +309,36 @@ func decodeLinearGradientOp(data []byte) linearGradientOpData {
294309 }
295310}
296311
312+ func decodeRadialGradientOp (data []byte ) radialGradientOpData {
313+ if opconst .OpType (data [0 ]) != opconst .TypeRadialGradient {
314+ panic ("invalid op" )
315+ }
316+ bo := binary .LittleEndian
317+ return radialGradientOpData {
318+ stop1 : f32.Point {
319+ X : math .Float32frombits (bo .Uint32 (data [1 :])),
320+ Y : math .Float32frombits (bo .Uint32 (data [5 :])),
321+ },
322+ stop2 : f32.Point {
323+ X : math .Float32frombits (bo .Uint32 (data [9 :])),
324+ Y : math .Float32frombits (bo .Uint32 (data [13 :])),
325+ },
326+ radiusy : math .Float32frombits (bo .Uint32 (data [17 :])),
327+ color1 : color.NRGBA {
328+ R : data [21 + 0 ],
329+ G : data [21 + 1 ],
330+ B : data [21 + 2 ],
331+ A : data [21 + 3 ],
332+ },
333+ color2 : color.NRGBA {
334+ R : data [25 + 0 ],
335+ G : data [25 + 1 ],
336+ B : data [25 + 2 ],
337+ A : data [25 + 3 ],
338+ },
339+ }
340+ }
341+
297342type clipType uint8
298343
299344type resource interface {
@@ -975,6 +1020,14 @@ loop:
9751020 state .stop2 = op .stop2
9761021 state .color1 = op .color1
9771022 state .color2 = op .color2
1023+ case opconst .TypeRadialGradient :
1024+ state .matType = materialRadialGradient
1025+ op := decodeRadialGradientOp (encOp .Data )
1026+ state .stop1 = op .stop1
1027+ state .stop2 = op .stop2
1028+ state .radiusy = op .radiusy
1029+ state .color1 = op .color1
1030+ state .color2 = op .color2
9781031 case opconst .TypeImage :
9791032 state .matType = materialTexture
9801033 state .image = decodeImageOp (encOp .Data , encOp .Refs )
@@ -1086,15 +1139,15 @@ func (d *drawState) materialFor(rect f32.Rectangle, off f32.Point, partTrans f32
10861139 m .color2 = f32color .LinearFromSRGB (d .color2 )
10871140 m .opaque = m .color1 .A == 1.0 && m .color2 .A == 1.0
10881141
1089- m .uvTrans = partTrans .Mul (gradientSpaceTransform (clip , off , d .stop1 , d .stop2 ))
1142+ m .uvTrans = partTrans .Mul (gradientSpaceTransform (clip , off , d .stop1 , d .stop2 , - 1 ))
10901143 case materialRadialGradient :
10911144 m .material = materialRadialGradient
10921145
10931146 m .color1 = f32color .LinearFromSRGB (d .color1 )
10941147 m .color2 = f32color .LinearFromSRGB (d .color2 )
10951148 m .opaque = m .color1 .A == 1.0 && m .color2 .A == 1.0
10961149
1097- m .uvTrans = partTrans .Mul (gradientSpaceTransform (clip , off , d .stop1 , d .stop2 ))
1150+ m .uvTrans = partTrans .Mul (gradientSpaceTransform (clip , off , d .stop1 , d .stop2 , d . radiusy ))
10981151 case materialTexture :
10991152 m .material = materialTexture
11001153 dr := boundRectF (rect .Add (off ))
@@ -1286,19 +1339,28 @@ func texSpaceTransform(r f32.Rectangle, bounds image.Point) (f32.Point, f32.Poin
12861339}
12871340
12881341// gradientSpaceTransform transforms stop1 and stop2 to [(0,0), (1,1)].
1289- func gradientSpaceTransform (clip image.Rectangle , off f32.Point , stop1 , stop2 f32.Point ) f32.Affine2D {
1342+ func gradientSpaceTransform (clip image.Rectangle , off f32.Point , stop1 , stop2 f32.Point , radiusy float32 ) f32.Affine2D {
12901343 d := stop2 .Sub (stop1 )
12911344 l := float32 (math .Sqrt (float64 (d .X * d .X + d .Y * d .Y )))
12921345 a := float32 (math .Atan2 (float64 (- d .Y ), float64 (d .X )))
12931346
1347+ scalex := 1 / l
1348+
1349+ var scaley float32
1350+ if radiusy == - 1 {
1351+ scaley = scalex
1352+ } else if radiusy != 0 {
1353+ scaley = 1 / radiusy
1354+ }
1355+
12941356 // TODO: optimize
12951357 zp := f32.Point {}
12961358 return f32.Affine2D {}.
12971359 Scale (zp , layout .FPt (clip .Size ())). // scale to pixel space
12981360 Offset (zp .Sub (off ).Add (layout .FPt (clip .Min ))). // offset to clip space
12991361 Offset (zp .Sub (stop1 )). // offset to first stop point
13001362 Rotate (zp , a ). // rotate to align gradient
1301- Scale (zp , f32 .Pt (1 / l , 1 / l )) // scale gradient to right size
1363+ Scale (zp , f32 .Pt (scalex , scaley )) // scale gradient to right size
13021364}
13031365
13041366// clipSpaceTransform returns the scale and offset that transforms the given
0 commit comments