@@ -107,11 +107,13 @@ type drawState struct {
107
107
// Current paint.ColorOp, if any.
108
108
color color.NRGBA
109
109
110
- // Current paint.LinearGradientOp.
110
+ // Current paint.LinearGradientOp and paint.RadialGradientOp .
111
111
stop1 f32.Point
112
112
stop2 f32.Point
113
113
color1 color.NRGBA
114
114
color2 color.NRGBA
115
+ // Current paint.RadialGradientOp.
116
+ radiusy float32
115
117
}
116
118
117
119
type pathOp struct {
@@ -187,9 +189,11 @@ type material struct {
187
189
opaque bool
188
190
// For materialTypeColor.
189
191
color f32color.RGBA
190
- // For materialTypeLinearGradient.
192
+ // For materialTypeLinearGradient and materialTypeRadialGradient .
191
193
color1 f32color.RGBA
192
194
color2 f32color.RGBA
195
+ // For materialTypeRadialGradient.
196
+ radiusy float32
193
197
// For materialTypeTexture.
194
198
data imageOpData
195
199
uvTrans f32.Affine2D
@@ -212,9 +216,20 @@ type imageOpData struct {
212
216
}
213
217
214
218
type 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
+
216
232
color1 color.NRGBA
217
- stop2 f32.Point
218
233
color2 color.NRGBA
219
234
}
220
235
@@ -294,6 +309,36 @@ func decodeLinearGradientOp(data []byte) linearGradientOpData {
294
309
}
295
310
}
296
311
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
+
297
342
type clipType uint8
298
343
299
344
type resource interface {
@@ -975,6 +1020,14 @@ loop:
975
1020
state .stop2 = op .stop2
976
1021
state .color1 = op .color1
977
1022
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
978
1031
case opconst .TypeImage :
979
1032
state .matType = materialTexture
980
1033
state .image = decodeImageOp (encOp .Data , encOp .Refs )
@@ -1086,15 +1139,15 @@ func (d *drawState) materialFor(rect f32.Rectangle, off f32.Point, partTrans f32
1086
1139
m .color2 = f32color .LinearFromSRGB (d .color2 )
1087
1140
m .opaque = m .color1 .A == 1.0 && m .color2 .A == 1.0
1088
1141
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 ))
1090
1143
case materialRadialGradient :
1091
1144
m .material = materialRadialGradient
1092
1145
1093
1146
m .color1 = f32color .LinearFromSRGB (d .color1 )
1094
1147
m .color2 = f32color .LinearFromSRGB (d .color2 )
1095
1148
m .opaque = m .color1 .A == 1.0 && m .color2 .A == 1.0
1096
1149
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 ))
1098
1151
case materialTexture :
1099
1152
m .material = materialTexture
1100
1153
dr := boundRectF (rect .Add (off ))
@@ -1286,19 +1339,28 @@ func texSpaceTransform(r f32.Rectangle, bounds image.Point) (f32.Point, f32.Poin
1286
1339
}
1287
1340
1288
1341
// 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 {
1290
1343
d := stop2 .Sub (stop1 )
1291
1344
l := float32 (math .Sqrt (float64 (d .X * d .X + d .Y * d .Y )))
1292
1345
a := float32 (math .Atan2 (float64 (- d .Y ), float64 (d .X )))
1293
1346
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
+
1294
1356
// TODO: optimize
1295
1357
zp := f32.Point {}
1296
1358
return f32.Affine2D {}.
1297
1359
Scale (zp , layout .FPt (clip .Size ())). // scale to pixel space
1298
1360
Offset (zp .Sub (off ).Add (layout .FPt (clip .Min ))). // offset to clip space
1299
1361
Offset (zp .Sub (stop1 )). // offset to first stop point
1300
1362
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
1302
1364
}
1303
1365
1304
1366
// clipSpaceTransform returns the scale and offset that transforms the given
0 commit comments