1// Copyright 2011 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.
4
5package draw
6
7import (
8	"image"
9	"testing"
10)
11
12type clipTest struct {
13	desc          string
14	r, dr, sr, mr image.Rectangle
15	sp, mp        image.Point
16	nilMask       bool
17	r0            image.Rectangle
18	sp0, mp0      image.Point
19}
20
21var clipTests = []clipTest{
22	// The following tests all have a nil mask.
23	{
24		"basic",
25		image.Rect(0, 0, 100, 100),
26		image.Rect(0, 0, 100, 100),
27		image.Rect(0, 0, 100, 100),
28		image.ZR,
29		image.ZP,
30		image.ZP,
31		true,
32		image.Rect(0, 0, 100, 100),
33		image.ZP,
34		image.ZP,
35	},
36	{
37		"clip dr",
38		image.Rect(0, 0, 100, 100),
39		image.Rect(40, 40, 60, 60),
40		image.Rect(0, 0, 100, 100),
41		image.ZR,
42		image.ZP,
43		image.ZP,
44		true,
45		image.Rect(40, 40, 60, 60),
46		image.Pt(40, 40),
47		image.ZP,
48	},
49	{
50		"clip sr",
51		image.Rect(0, 0, 100, 100),
52		image.Rect(0, 0, 100, 100),
53		image.Rect(20, 20, 80, 80),
54		image.ZR,
55		image.ZP,
56		image.ZP,
57		true,
58		image.Rect(20, 20, 80, 80),
59		image.Pt(20, 20),
60		image.ZP,
61	},
62	{
63		"clip dr and sr",
64		image.Rect(0, 0, 100, 100),
65		image.Rect(0, 0, 50, 100),
66		image.Rect(20, 20, 80, 80),
67		image.ZR,
68		image.ZP,
69		image.ZP,
70		true,
71		image.Rect(20, 20, 50, 80),
72		image.Pt(20, 20),
73		image.ZP,
74	},
75	{
76		"clip dr and sr, sp outside sr (top-left)",
77		image.Rect(0, 0, 100, 100),
78		image.Rect(0, 0, 50, 100),
79		image.Rect(20, 20, 80, 80),
80		image.ZR,
81		image.Pt(15, 8),
82		image.ZP,
83		true,
84		image.Rect(5, 12, 50, 72),
85		image.Pt(20, 20),
86		image.ZP,
87	},
88	{
89		"clip dr and sr, sp outside sr (middle-left)",
90		image.Rect(0, 0, 100, 100),
91		image.Rect(0, 0, 50, 100),
92		image.Rect(20, 20, 80, 80),
93		image.ZR,
94		image.Pt(15, 66),
95		image.ZP,
96		true,
97		image.Rect(5, 0, 50, 14),
98		image.Pt(20, 66),
99		image.ZP,
100	},
101	{
102		"clip dr and sr, sp outside sr (bottom-left)",
103		image.Rect(0, 0, 100, 100),
104		image.Rect(0, 0, 50, 100),
105		image.Rect(20, 20, 80, 80),
106		image.ZR,
107		image.Pt(15, 91),
108		image.ZP,
109		true,
110		image.ZR,
111		image.Pt(15, 91),
112		image.ZP,
113	},
114	{
115		"clip dr and sr, sp inside sr",
116		image.Rect(0, 0, 100, 100),
117		image.Rect(0, 0, 50, 100),
118		image.Rect(20, 20, 80, 80),
119		image.ZR,
120		image.Pt(44, 33),
121		image.ZP,
122		true,
123		image.Rect(0, 0, 36, 47),
124		image.Pt(44, 33),
125		image.ZP,
126	},
127
128	// The following tests all have a non-nil mask.
129	{
130		"basic mask",
131		image.Rect(0, 0, 80, 80),
132		image.Rect(20, 0, 100, 80),
133		image.Rect(0, 0, 50, 49),
134		image.Rect(0, 0, 46, 47),
135		image.ZP,
136		image.ZP,
137		false,
138		image.Rect(20, 0, 46, 47),
139		image.Pt(20, 0),
140		image.Pt(20, 0),
141	},
142	{
143		"clip sr and mr",
144		image.Rect(0, 0, 100, 100),
145		image.Rect(0, 0, 100, 100),
146		image.Rect(23, 23, 55, 86),
147		image.Rect(44, 44, 87, 58),
148		image.Pt(10, 10),
149		image.Pt(11, 11),
150		false,
151		image.Rect(33, 33, 45, 47),
152		image.Pt(43, 43),
153		image.Pt(44, 44),
154	},
155}
156
157func TestClip(t *testing.T) {
158	dst0 := image.NewRGBA(image.Rect(0, 0, 100, 100))
159	src0 := image.NewRGBA(image.Rect(0, 0, 100, 100))
160	mask0 := image.NewRGBA(image.Rect(0, 0, 100, 100))
161	for _, c := range clipTests {
162		dst := dst0.SubImage(c.dr).(*image.RGBA)
163		src := src0.SubImage(c.sr).(*image.RGBA)
164		r, sp, mp := c.r, c.sp, c.mp
165		if c.nilMask {
166			clip(dst, &r, src, &sp, nil, nil)
167		} else {
168			clip(dst, &r, src, &sp, mask0.SubImage(c.mr), &mp)
169		}
170
171		// Check that the actual results equal the expected results.
172		if !c.r0.Eq(r) {
173			t.Errorf("%s: clip rectangle want %v got %v", c.desc, c.r0, r)
174			continue
175		}
176		if !c.sp0.Eq(sp) {
177			t.Errorf("%s: sp want %v got %v", c.desc, c.sp0, sp)
178			continue
179		}
180		if !c.nilMask {
181			if !c.mp0.Eq(mp) {
182				t.Errorf("%s: mp want %v got %v", c.desc, c.mp0, mp)
183				continue
184			}
185		}
186
187		// Check that the clipped rectangle is contained by the dst / src / mask
188		// rectangles, in their respective coordinate spaces.
189		if !r.In(c.dr) {
190			t.Errorf("%s: c.dr %v does not contain r %v", c.desc, c.dr, r)
191		}
192		// sr is r translated into src's coordinate space.
193		sr := r.Add(c.sp.Sub(c.dr.Min))
194		if !sr.In(c.sr) {
195			t.Errorf("%s: c.sr %v does not contain sr %v", c.desc, c.sr, sr)
196		}
197		if !c.nilMask {
198			// mr is r translated into mask's coordinate space.
199			mr := r.Add(c.mp.Sub(c.dr.Min))
200			if !mr.In(c.mr) {
201				t.Errorf("%s: c.mr %v does not contain mr %v", c.desc, c.mr, mr)
202			}
203		}
204	}
205}
206