154
154
{"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
157
func makeGolden(dst, src, mask image.Image, op Op) image.Image {
157
func makeGolden(dst image.Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) image.Image {
158
158
// Since golden is a newly allocated image, we don't have to check if the
159
159
// input source and mask images and the output golden image overlap.
160
160
b := dst.Bounds()
161
sx0 := src.Bounds().Min.X - b.Min.X
162
sy0 := src.Bounds().Min.Y - b.Min.Y
162
mb := image.Rect(-1e9, -1e9, 1e9, 1e9)
165
mx0 = mask.Bounds().Min.X - b.Min.X
166
my0 = mask.Bounds().Min.Y - b.Min.Y
168
166
golden := image.NewRGBA(b.Max.X, b.Max.Y)
169
for y := b.Min.Y; y < b.Max.Y; y++ {
170
my, sy := my0+y, sy0+y
171
for x := b.Min.X; x < b.Max.X; x++ {
172
mx, sx := mx0+x, sx0+x
167
for y := r.Min.Y; y < r.Max.Y; y++ {
168
sy := y + sp.Y - r.Min.Y
169
my := y + mp.Y - r.Min.Y
170
for x := r.Min.X; x < r.Max.X; x++ {
171
if !(image.Point{x, y}.In(b)) {
174
sx := x + sp.X - r.Min.X
175
if !(image.Point{sx, sy}.In(sb)) {
178
mx := x + mp.X - r.Min.X
179
if !(image.Point{mx, my}.In(mb)) {
173
183
const M = 1<<16 - 1
174
184
var dr, dg, db, da uint32
202
return golden.SubImage(b)
196
205
func TestDraw(t *testing.T) {
198
for _, test := range drawTests {
200
// Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
201
golden := makeGolden(dst, test.src, test.mask, test.op)
203
if !b.Eq(golden.Bounds()) {
204
t.Errorf("draw %s: bounds %v versus %v", test.desc, dst.Bounds(), golden.Bounds())
207
// Draw the same combination onto the actual dst using the optimized DrawMask implementation.
208
DrawMask(dst, b, test.src, image.ZP, test.mask, image.ZP, test.op)
209
// Check that the resultant pixel at (8, 8) matches what we expect
210
// (the expected value can be verified by hand).
211
if !eq(dst.At(8, 8), test.expected) {
212
t.Errorf("draw %s: at (8, 8) %v versus %v", test.desc, dst.At(8, 8), test.expected)
215
// Check that the resultant dst image matches the golden output.
216
for y := b.Min.Y; y < b.Max.Y; y++ {
217
for x := b.Min.X; x < b.Max.X; x++ {
218
if !eq(dst.At(x, y), golden.At(x, y)) {
219
t.Errorf("draw %s: at (%d, %d), %v versus golden %v", test.desc, x, y, dst.At(x, y), golden.At(x, y))
206
rr := []image.Rectangle{
207
image.Rect(0, 0, 0, 0),
208
image.Rect(0, 0, 16, 16),
209
image.Rect(3, 5, 12, 10),
210
image.Rect(0, 0, 9, 9),
211
image.Rect(8, 8, 16, 16),
212
image.Rect(8, 0, 9, 16),
213
image.Rect(0, 8, 16, 9),
214
image.Rect(8, 8, 9, 9),
215
image.Rect(8, 8, 8, 8),
217
for _, r := range rr {
219
for _, test := range drawTests {
220
dst := hgradRed(255).(*image.RGBA).SubImage(r).(Image)
221
// Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
222
golden := makeGolden(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
224
if !b.Eq(golden.Bounds()) {
225
t.Errorf("draw %v %s: bounds %v versus %v", r, test.desc, dst.Bounds(), golden.Bounds())
228
// Draw the same combination onto the actual dst using the optimized DrawMask implementation.
229
DrawMask(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
230
if image.Pt(8, 8).In(r) {
231
// Check that the resultant pixel at (8, 8) matches what we expect
232
// (the expected value can be verified by hand).
233
if !eq(dst.At(8, 8), test.expected) {
234
t.Errorf("draw %v %s: at (8, 8) %v versus %v", r, test.desc, dst.At(8, 8), test.expected)
238
// Check that the resultant dst image matches the golden output.
239
for y := b.Min.Y; y < b.Max.Y; y++ {
240
for x := b.Min.X; x < b.Max.X; x++ {
241
if !eq(dst.At(x, y), golden.At(x, y)) {
242
t.Errorf("draw %v %s: at (%d, %d), %v versus golden %v", r, test.desc, x, y, dst.At(x, y), golden.At(x, y))
231
255
for xoff := -2; xoff <= 2; xoff++ {
232
256
m := gradYellow(127).(*image.RGBA)
236
Rect: image.Rect(5, 5, 10, 10),
241
Rect: image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff),
257
dst := m.SubImage(image.Rect(5, 5, 10, 10)).(*image.RGBA)
258
src := m.SubImage(image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff)).(*image.RGBA)
243
260
// Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
244
golden := makeGolden(dst, src, nil, op)
261
golden := makeGolden(dst, b, src, src.Bounds().Min, nil, image.ZP, op)
246
262
if !b.Eq(golden.Bounds()) {
247
263
t.Errorf("drawOverlap xoff=%d,yoff=%d: bounds %v versus %v", xoff, yoff, dst.Bounds(), golden.Bounds())
271
287
b.Set(1, 0, image.RGBAColor{0, 0, 5, 5})
272
288
b.Set(0, 1, image.RGBAColor{0, 5, 0, 5})
273
289
b.Set(1, 1, image.RGBAColor{5, 0, 0, 5})
274
Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1))
290
Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1), Over)
275
291
if !eq(image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) {
276
292
t.Errorf("non-zero src pt: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
296
func TestFill(t *testing.T) {
297
rr := []image.Rectangle{
298
image.Rect(0, 0, 0, 0),
299
image.Rect(0, 0, 40, 30),
300
image.Rect(10, 0, 40, 30),
301
image.Rect(0, 20, 40, 30),
302
image.Rect(10, 20, 40, 30),
303
image.Rect(10, 20, 15, 25),
304
image.Rect(10, 0, 35, 30),
305
image.Rect(0, 15, 40, 16),
306
image.Rect(24, 24, 25, 25),
307
image.Rect(23, 23, 26, 26),
308
image.Rect(22, 22, 27, 27),
309
image.Rect(21, 21, 28, 28),
310
image.Rect(20, 20, 29, 29),
312
for _, r := range rr {
313
m := image.NewRGBA(40, 30).SubImage(r).(*image.RGBA)
315
c := image.RGBAColor{11, 0, 0, 255}
316
src := &image.ColorImage{c}
317
check := func(desc string) {
318
for y := b.Min.Y; y < b.Max.Y; y++ {
319
for x := b.Min.X; x < b.Max.X; x++ {
320
if !eq(c, m.At(x, y)) {
321
t.Errorf("%s fill: at (%d, %d), sub-image bounds=%v: want %v got %v", desc, x, y, r, c, m.At(x, y))
327
// Draw 1 pixel at a time.
328
for y := b.Min.Y; y < b.Max.Y; y++ {
329
for x := b.Min.X; x < b.Max.X; x++ {
330
DrawMask(m, image.Rect(x, y, x+1, y+1), src, image.ZP, nil, image.ZP, Src)
334
// Draw 1 row at a time.
335
c = image.RGBAColor{0, 22, 0, 255}
336
src = &image.ColorImage{c}
337
for y := b.Min.Y; y < b.Max.Y; y++ {
338
DrawMask(m, image.Rect(b.Min.X, y, b.Max.X, y+1), src, image.ZP, nil, image.ZP, Src)
341
// Draw 1 column at a time.
342
c = image.RGBAColor{0, 0, 33, 255}
343
src = &image.ColorImage{c}
344
for x := b.Min.X; x < b.Max.X; x++ {
345
DrawMask(m, image.Rect(x, b.Min.Y, x+1, b.Max.Y), src, image.ZP, nil, image.ZP, Src)
348
// Draw the whole image at once.
349
c = image.RGBAColor{44, 55, 66, 77}
350
src = &image.ColorImage{c}
351
DrawMask(m, b, src, image.ZP, nil, image.ZP, Src)