shiny/iconvg: fix panic for out-of-range colors
Fixes golang/go#39526
Change-Id: I4ab207b24e424e92b2d8af86a64294db94631aa7
Reviewed-on: https://go-review.googlesource.com/c/exp/+/291150
Trust: Nigel Tao <nigeltao@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/shiny/iconvg/decode_test.go b/shiny/iconvg/decode_test.go
index c06d816..82356f0 100644
--- a/shiny/iconvg/decode_test.go
+++ b/shiny/iconvg/decode_test.go
@@ -17,6 +17,8 @@
"runtime"
"strings"
"testing"
+
+ "golang.org/x/image/math/f32"
)
// disassemble returns a disassembly of an encoded IconVG graphic. Users of
@@ -286,6 +288,44 @@
}
}
+func TestInvalidAlphaPremultipliedColor(t *testing.T) {
+ // See http://golang.org/issue/39526 for some discussion.
+
+ dst := image.NewRGBA(image.Rect(0, 0, 1, 1))
+ var z Rasterizer
+ z.SetDstImage(dst, dst.Bounds(), draw.Over)
+ z.Reset(Metadata{
+ ViewBox: Rectangle{
+ Min: f32.Vec2{0.0, 0.0},
+ Max: f32.Vec2{1.0, 1.0},
+ },
+ })
+
+ // Fill the unit square with red.
+ z.SetCReg(0, false, RGBAColor(color.RGBA{0x55, 0x00, 0x00, 0x66}))
+ z.StartPath(0, 0.0, 0.0)
+ z.AbsLineTo(1.0, 0.0)
+ z.AbsLineTo(1.0, 1.0)
+ z.AbsLineTo(0.0, 1.0)
+ z.ClosePathEndPath()
+
+ // Fill the unit square with an invalid (non-gradient) alpha-premultiplied
+ // color (super-saturated green). This should be a no-op (and not crash).
+ z.SetCReg(0, false, RGBAColor(color.RGBA{0x00, 0x99, 0x00, 0x88}))
+ z.StartPath(0, 0.0, 0.0)
+ z.AbsLineTo(1.0, 0.0)
+ z.AbsLineTo(1.0, 1.0)
+ z.AbsLineTo(0.0, 1.0)
+ z.ClosePathEndPath()
+
+ // We should see red.
+ got := dst.Pix
+ want := []byte{0x55, 0x00, 0x00, 0x66}
+ if !bytes.Equal(got, want) {
+ t.Errorf("got [% 02x], want [% 02x]", got, want)
+ }
+}
+
func TestBlendColor(t *testing.T) {
// This example comes from doc.go. Look for "orange" in the "Colors"
// section.
diff --git a/shiny/iconvg/doc.go b/shiny/iconvg/doc.go
index 8627814..a16871a 100644
--- a/shiny/iconvg/doc.go
+++ b/shiny/iconvg/doc.go
@@ -133,8 +133,10 @@
defined by two points.
At the time a gradient is used to fill a path, it is invalid for any of the
-stop colors to itself be a gradient, or for any stop offset to be less than or
-equal to a previous offset, or outside the range [0, 1].
+stop colors to be out of alpha-premultiplied range (where red, green or blue is
+greater than alpha), including referencing another gradient. It is also invalid
+for any stop offset to be less than or equal to a previous offset, or outside
+the range [0, 1].
Colors
@@ -177,7 +179,8 @@
It is valid for some encodings to yield a color value where the red, green or
blue value is greater than the alpha value, as this may be a gradient. If it
-isn't a gradient, the subsequent rendering is undefined.
+isn't a valid gradient, it is equivalent to transparent black and drawing with
+that color is a no-op.
Palettes
diff --git a/shiny/iconvg/rasterizer.go b/shiny/iconvg/rasterizer.go
index f3720f8..ec99992 100644
--- a/shiny/iconvg/rasterizer.go
+++ b/shiny/iconvg/rasterizer.go
@@ -234,6 +234,9 @@
} else if z.flatColor.A == 0x00 && z.flatColor.B&0x80 != 0 {
z.fill = &z.gradient
z.disabled = !z.initGradient(z.flatColor)
+ } else {
+ z.fill = nil
+ z.disabled = true
}
width, height := z.r.Dx(), z.r.Dy()