Merge from mainline (167278:168000).
[official-gcc/graphite-test-results.git] / libgo / go / exp / draw / draw_test.go
blob90c9e823d3e834fbc129e2ae9811d79ad463fd9e
1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 package draw
7 import (
8 "image"
9 "testing"
12 func eq(c0, c1 image.Color) bool {
13 r0, g0, b0, a0 := c0.RGBA()
14 r1, g1, b1, a1 := c1.RGBA()
15 return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1
18 func fillBlue(alpha int) image.Image {
19 return image.NewColorImage(image.RGBAColor{0, 0, uint8(alpha), uint8(alpha)})
22 func fillAlpha(alpha int) image.Image {
23 return image.NewColorImage(image.AlphaColor{uint8(alpha)})
26 func vgradGreen(alpha int) image.Image {
27 m := image.NewRGBA(16, 16)
28 for y := 0; y < 16; y++ {
29 for x := 0; x < 16; x++ {
30 m.Set(x, y, image.RGBAColor{0, uint8(y * alpha / 15), 0, uint8(alpha)})
33 return m
36 func vgradAlpha(alpha int) image.Image {
37 m := image.NewAlpha(16, 16)
38 for y := 0; y < 16; y++ {
39 for x := 0; x < 16; x++ {
40 m.Set(x, y, image.AlphaColor{uint8(y * alpha / 15)})
43 return m
46 func hgradRed(alpha int) Image {
47 m := image.NewRGBA(16, 16)
48 for y := 0; y < 16; y++ {
49 for x := 0; x < 16; x++ {
50 m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), 0, 0, uint8(alpha)})
53 return m
56 func gradYellow(alpha int) Image {
57 m := image.NewRGBA(16, 16)
58 for y := 0; y < 16; y++ {
59 for x := 0; x < 16; x++ {
60 m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), uint8(y * alpha / 15), 0, uint8(alpha)})
63 return m
66 type drawTest struct {
67 desc string
68 src image.Image
69 mask image.Image
70 op Op
71 expected image.Color
74 var drawTests = []drawTest{
75 // Uniform mask (0% opaque).
76 {"nop", vgradGreen(255), fillAlpha(0), Over, image.RGBAColor{136, 0, 0, 255}},
77 {"clear", vgradGreen(255), fillAlpha(0), Src, image.RGBAColor{0, 0, 0, 0}},
78 // Uniform mask (100%, 75%, nil) and uniform source.
79 // At (x, y) == (8, 8):
80 // The destination pixel is {136, 0, 0, 255}.
81 // The source pixel is {0, 0, 90, 90}.
82 {"fill", fillBlue(90), fillAlpha(255), Over, image.RGBAColor{88, 0, 90, 255}},
83 {"fillSrc", fillBlue(90), fillAlpha(255), Src, image.RGBAColor{0, 0, 90, 90}},
84 {"fillAlpha", fillBlue(90), fillAlpha(192), Over, image.RGBAColor{100, 0, 68, 255}},
85 {"fillAlphaSrc", fillBlue(90), fillAlpha(192), Src, image.RGBAColor{0, 0, 68, 68}},
86 {"fillNil", fillBlue(90), nil, Over, image.RGBAColor{88, 0, 90, 255}},
87 {"fillNilSrc", fillBlue(90), nil, Src, image.RGBAColor{0, 0, 90, 90}},
88 // Uniform mask (100%, 75%, nil) and variable source.
89 // At (x, y) == (8, 8):
90 // The destination pixel is {136, 0, 0, 255}.
91 // The source pixel is {0, 48, 0, 90}.
92 {"copy", vgradGreen(90), fillAlpha(255), Over, image.RGBAColor{88, 48, 0, 255}},
93 {"copySrc", vgradGreen(90), fillAlpha(255), Src, image.RGBAColor{0, 48, 0, 90}},
94 {"copyAlpha", vgradGreen(90), fillAlpha(192), Over, image.RGBAColor{100, 36, 0, 255}},
95 {"copyAlphaSrc", vgradGreen(90), fillAlpha(192), Src, image.RGBAColor{0, 36, 0, 68}},
96 {"copyNil", vgradGreen(90), nil, Over, image.RGBAColor{88, 48, 0, 255}},
97 {"copyNilSrc", vgradGreen(90), nil, Src, image.RGBAColor{0, 48, 0, 90}},
98 // Variable mask and variable source.
99 // At (x, y) == (8, 8):
100 // The destination pixel is {136, 0, 0, 255}.
101 // The source pixel is {0, 0, 255, 255}.
102 // The mask pixel's alpha is 102, or 40%.
103 {"generic", fillBlue(255), vgradAlpha(192), Over, image.RGBAColor{81, 0, 102, 255}},
104 {"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
107 func makeGolden(dst, src, mask image.Image, op Op) image.Image {
108 // Since golden is a newly allocated image, we don't have to check if the
109 // input source and mask images and the output golden image overlap.
110 b := dst.Bounds()
111 sx0 := src.Bounds().Min.X - b.Min.X
112 sy0 := src.Bounds().Min.Y - b.Min.Y
113 var mx0, my0 int
114 if mask != nil {
115 mx0 = mask.Bounds().Min.X - b.Min.X
116 my0 = mask.Bounds().Min.Y - b.Min.Y
118 golden := image.NewRGBA(b.Max.X, b.Max.Y)
119 for y := b.Min.Y; y < b.Max.Y; y++ {
120 my, sy := my0+y, sy0+y
121 for x := b.Min.X; x < b.Max.X; x++ {
122 mx, sx := mx0+x, sx0+x
123 const M = 1<<16 - 1
124 var dr, dg, db, da uint32
125 if op == Over {
126 dr, dg, db, da = dst.At(x, y).RGBA()
128 sr, sg, sb, sa := src.At(sx, sy).RGBA()
129 ma := uint32(M)
130 if mask != nil {
131 _, _, _, ma = mask.At(mx, my).RGBA()
133 a := M - (sa * ma / M)
134 golden.Set(x, y, image.RGBA64Color{
135 uint16((dr*a + sr*ma) / M),
136 uint16((dg*a + sg*ma) / M),
137 uint16((db*a + sb*ma) / M),
138 uint16((da*a + sa*ma) / M),
142 golden.Rect = b
143 return golden
146 func TestDraw(t *testing.T) {
147 loop:
148 for _, test := range drawTests {
149 dst := hgradRed(255)
150 // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
151 golden := makeGolden(dst, test.src, test.mask, test.op)
152 b := dst.Bounds()
153 if !b.Eq(golden.Bounds()) {
154 t.Errorf("draw %s: bounds %v versus %v", test.desc, dst.Bounds(), golden.Bounds())
155 continue
157 // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
158 DrawMask(dst, b, test.src, image.ZP, test.mask, image.ZP, test.op)
159 // Check that the resultant pixel at (8, 8) matches what we expect
160 // (the expected value can be verified by hand).
161 if !eq(dst.At(8, 8), test.expected) {
162 t.Errorf("draw %s: at (8, 8) %v versus %v", test.desc, dst.At(8, 8), test.expected)
163 continue
165 // Check that the resultant dst image matches the golden output.
166 for y := b.Min.Y; y < b.Max.Y; y++ {
167 for x := b.Min.X; x < b.Max.X; x++ {
168 if !eq(dst.At(x, y), golden.At(x, y)) {
169 t.Errorf("draw %s: at (%d, %d), %v versus golden %v", test.desc, x, y, dst.At(x, y), golden.At(x, y))
170 continue loop
177 func TestDrawOverlap(t *testing.T) {
178 for _, op := range []Op{Over, Src} {
179 for yoff := -2; yoff <= 2; yoff++ {
180 loop:
181 for xoff := -2; xoff <= 2; xoff++ {
182 m := gradYellow(127).(*image.RGBA)
183 dst := &image.RGBA{
184 Pix: m.Pix,
185 Stride: m.Stride,
186 Rect: image.Rect(5, 5, 10, 10),
188 src := &image.RGBA{
189 Pix: m.Pix,
190 Stride: m.Stride,
191 Rect: image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff),
193 // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
194 golden := makeGolden(dst, src, nil, op)
195 b := dst.Bounds()
196 if !b.Eq(golden.Bounds()) {
197 t.Errorf("drawOverlap xoff=%d,yoff=%d: bounds %v versus %v", xoff, yoff, dst.Bounds(), golden.Bounds())
198 continue
200 // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
201 DrawMask(dst, b, src, src.Bounds().Min, nil, image.ZP, op)
202 // Check that the resultant dst image matches the golden output.
203 for y := b.Min.Y; y < b.Max.Y; y++ {
204 for x := b.Min.X; x < b.Max.X; x++ {
205 if !eq(dst.At(x, y), golden.At(x, y)) {
206 t.Errorf("drawOverlap xoff=%d,yoff=%d: at (%d, %d), %v versus golden %v", xoff, yoff, x, y, dst.At(x, y), golden.At(x, y))
207 continue loop
216 // TestIssue836 verifies http://code.google.com/p/go/issues/detail?id=836.
217 func TestIssue836(t *testing.T) {
218 a := image.NewRGBA(1, 1)
219 b := image.NewRGBA(2, 2)
220 b.Set(0, 0, image.RGBAColor{0, 0, 0, 5})
221 b.Set(1, 0, image.RGBAColor{0, 0, 5, 5})
222 b.Set(0, 1, image.RGBAColor{0, 5, 0, 5})
223 b.Set(1, 1, image.RGBAColor{5, 0, 0, 5})
224 Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1))
225 if !eq(image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) {
226 t.Errorf("Issue 836: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))