]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgo/go/exp/draw/draw.go
Add Go frontend, libgo library, and Go testsuite.
[thirdparty/gcc.git] / libgo / go / exp / draw / draw.go
1 // Copyright 2009 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
5 // Package draw provides basic graphics and drawing primitives,
6 // in the style of the Plan 9 graphics library
7 // (see http://plan9.bell-labs.com/magic/man2html/2/draw)
8 // and the X Render extension.
9 package draw
10
11 import "image"
12
13 // m is the maximum color value returned by image.Color.RGBA.
14 const m = 1<<16 - 1
15
16 // A Porter-Duff compositing operator.
17 type Op int
18
19 const (
20 // Over specifies ``(src in mask) over dst''.
21 Over Op = iota
22 // Src specifies ``src in mask''.
23 Src
24 )
25
26 var zeroColor image.Color = image.AlphaColor{0}
27
28 // A draw.Image is an image.Image with a Set method to change a single pixel.
29 type Image interface {
30 image.Image
31 Set(x, y int, c image.Color)
32 }
33
34 // Draw calls DrawMask with a nil mask and an Over op.
35 func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
36 DrawMask(dst, r, src, sp, nil, image.ZP, Over)
37 }
38
39 // DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r
40 // in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque.
41 func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
42 sb := src.Bounds()
43 dx, dy := sb.Max.X-sp.X, sb.Max.Y-sp.Y
44 if mask != nil {
45 mb := mask.Bounds()
46 if dx > mb.Max.X-mp.X {
47 dx = mb.Max.X - mp.X
48 }
49 if dy > mb.Max.Y-mp.Y {
50 dy = mb.Max.Y - mp.Y
51 }
52 }
53 if r.Dx() > dx {
54 r.Max.X = r.Min.X + dx
55 }
56 if r.Dy() > dy {
57 r.Max.Y = r.Min.Y + dy
58 }
59 r = r.Intersect(dst.Bounds())
60 if r.Empty() {
61 return
62 }
63
64 // Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation.
65 if dst0, ok := dst.(*image.RGBA); ok {
66 if op == Over {
67 if mask == nil {
68 if src0, ok := src.(*image.ColorImage); ok {
69 drawFillOver(dst0, r, src0)
70 return
71 }
72 if src0, ok := src.(*image.RGBA); ok {
73 drawCopyOver(dst0, r, src0, sp)
74 return
75 }
76 } else if mask0, ok := mask.(*image.Alpha); ok {
77 if src0, ok := src.(*image.ColorImage); ok {
78 drawGlyphOver(dst0, r, src0, mask0, mp)
79 return
80 }
81 }
82 } else {
83 if mask == nil {
84 if src0, ok := src.(*image.ColorImage); ok {
85 drawFillSrc(dst0, r, src0)
86 return
87 }
88 if src0, ok := src.(*image.RGBA); ok {
89 drawCopySrc(dst0, r, src0, sp)
90 return
91 }
92 }
93 }
94 drawRGBA(dst0, r, src, sp, mask, mp, op)
95 return
96 }
97
98 x0, x1, dx := r.Min.X, r.Max.X, 1
99 y0, y1, dy := r.Min.Y, r.Max.Y, 1
100 if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
101 // Rectangles overlap: process backward?
102 if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
103 x0, x1, dx = x1-1, x0-1, -1
104 y0, y1, dy = y1-1, y0-1, -1
105 }
106 }
107
108 var out *image.RGBA64Color
109 sy := sp.Y + y0 - r.Min.Y
110 my := mp.Y + y0 - r.Min.Y
111 for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
112 sx := sp.X + x0 - r.Min.X
113 mx := mp.X + x0 - r.Min.X
114 for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
115 ma := uint32(m)
116 if mask != nil {
117 _, _, _, ma = mask.At(mx, my).RGBA()
118 }
119 switch {
120 case ma == 0:
121 if op == Over {
122 // No-op.
123 } else {
124 dst.Set(x, y, zeroColor)
125 }
126 case ma == m && op == Src:
127 dst.Set(x, y, src.At(sx, sy))
128 default:
129 sr, sg, sb, sa := src.At(sx, sy).RGBA()
130 if out == nil {
131 out = new(image.RGBA64Color)
132 }
133 if op == Over {
134 dr, dg, db, da := dst.At(x, y).RGBA()
135 a := m - (sa * ma / m)
136 out.R = uint16((dr*a + sr*ma) / m)
137 out.G = uint16((dg*a + sg*ma) / m)
138 out.B = uint16((db*a + sb*ma) / m)
139 out.A = uint16((da*a + sa*ma) / m)
140 } else {
141 out.R = uint16(sr * ma / m)
142 out.G = uint16(sg * ma / m)
143 out.B = uint16(sb * ma / m)
144 out.A = uint16(sa * ma / m)
145 }
146 dst.Set(x, y, out)
147 }
148 }
149 }
150 }
151
152 func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
153 cr, cg, cb, ca := src.RGBA()
154 // The 0x101 is here for the same reason as in drawRGBA.
155 a := (m - ca) * 0x101
156 x0, x1 := r.Min.X, r.Max.X
157 y0, y1 := r.Min.Y, r.Max.Y
158 for y := y0; y != y1; y++ {
159 dbase := y * dst.Stride
160 dpix := dst.Pix[dbase+x0 : dbase+x1]
161 for i, rgba := range dpix {
162 dr := (uint32(rgba.R)*a)/m + cr
163 dg := (uint32(rgba.G)*a)/m + cg
164 db := (uint32(rgba.B)*a)/m + cb
165 da := (uint32(rgba.A)*a)/m + ca
166 dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
167 }
168 }
169 }
170
171 func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
172 dx0, dx1 := r.Min.X, r.Max.X
173 dy0, dy1 := r.Min.Y, r.Max.Y
174 nrows := dy1 - dy0
175 sx0, sx1 := sp.X, sp.X+dx1-dx0
176 d0 := dy0*dst.Stride + dx0
177 d1 := dy0*dst.Stride + dx1
178 s0 := sp.Y*src.Stride + sx0
179 s1 := sp.Y*src.Stride + sx1
180 var (
181 ddelta, sdelta int
182 i0, i1, idelta int
183 )
184 if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
185 ddelta = dst.Stride
186 sdelta = src.Stride
187 i0, i1, idelta = 0, d1-d0, +1
188 } else {
189 // If the source start point is higher than the destination start point, or equal height but to the left,
190 // then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down.
191 d0 += (nrows - 1) * dst.Stride
192 d1 += (nrows - 1) * dst.Stride
193 s0 += (nrows - 1) * src.Stride
194 s1 += (nrows - 1) * src.Stride
195 ddelta = -dst.Stride
196 sdelta = -src.Stride
197 i0, i1, idelta = d1-d0-1, -1, -1
198 }
199 for ; nrows > 0; nrows-- {
200 dpix := dst.Pix[d0:d1]
201 spix := src.Pix[s0:s1]
202 for i := i0; i != i1; i += idelta {
203 // For unknown reasons, even though both dpix[i] and spix[i] are
204 // image.RGBAColors, on an x86 CPU it seems fastest to call RGBA
205 // for the source but to do it manually for the destination.
206 sr, sg, sb, sa := spix[i].RGBA()
207 rgba := dpix[i]
208 dr := uint32(rgba.R)
209 dg := uint32(rgba.G)
210 db := uint32(rgba.B)
211 da := uint32(rgba.A)
212 // The 0x101 is here for the same reason as in drawRGBA.
213 a := (m - sa) * 0x101
214 dr = (dr*a)/m + sr
215 dg = (dg*a)/m + sg
216 db = (db*a)/m + sb
217 da = (da*a)/m + sa
218 dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
219 }
220 d0 += ddelta
221 d1 += ddelta
222 s0 += sdelta
223 s1 += sdelta
224 }
225 }
226
227 func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) {
228 x0, x1 := r.Min.X, r.Max.X
229 y0, y1 := r.Min.Y, r.Max.Y
230 cr, cg, cb, ca := src.RGBA()
231 for y, my := y0, mp.Y; y != y1; y, my = y+1, my+1 {
232 dbase := y * dst.Stride
233 dpix := dst.Pix[dbase+x0 : dbase+x1]
234 mbase := my * mask.Stride
235 mpix := mask.Pix[mbase+mp.X:]
236 for i, rgba := range dpix {
237 ma := uint32(mpix[i].A)
238 if ma == 0 {
239 continue
240 }
241 ma |= ma << 8
242 dr := uint32(rgba.R)
243 dg := uint32(rgba.G)
244 db := uint32(rgba.B)
245 da := uint32(rgba.A)
246 // The 0x101 is here for the same reason as in drawRGBA.
247 a := (m - (ca * ma / m)) * 0x101
248 dr = (dr*a + cr*ma) / m
249 dg = (dg*a + cg*ma) / m
250 db = (db*a + cb*ma) / m
251 da = (da*a + ca*ma) / m
252 dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
253 }
254 }
255 }
256
257 func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
258 if r.Dy() < 1 {
259 return
260 }
261 cr, cg, cb, ca := src.RGBA()
262 color := image.RGBAColor{uint8(cr >> 8), uint8(cg >> 8), uint8(cb >> 8), uint8(ca >> 8)}
263 // The built-in copy function is faster than a straightforward for loop to fill the destination with
264 // the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
265 // then use the first row as the slice source for the remaining rows.
266 dx0, dx1 := r.Min.X, r.Max.X
267 dy0, dy1 := r.Min.Y, r.Max.Y
268 dbase := dy0 * dst.Stride
269 i0, i1 := dbase+dx0, dbase+dx1
270 firstRow := dst.Pix[i0:i1]
271 for i, _ := range firstRow {
272 firstRow[i] = color
273 }
274 for y := dy0 + 1; y < dy1; y++ {
275 i0 += dst.Stride
276 i1 += dst.Stride
277 copy(dst.Pix[i0:i1], firstRow)
278 }
279 }
280
281 func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
282 dx0, dx1 := r.Min.X, r.Max.X
283 dy0, dy1 := r.Min.Y, r.Max.Y
284 nrows := dy1 - dy0
285 sx0, sx1 := sp.X, sp.X+dx1-dx0
286 d0 := dy0*dst.Stride + dx0
287 d1 := dy0*dst.Stride + dx1
288 s0 := sp.Y*src.Stride + sx0
289 s1 := sp.Y*src.Stride + sx1
290 var ddelta, sdelta int
291 if r.Min.Y <= sp.Y {
292 ddelta = dst.Stride
293 sdelta = src.Stride
294 } else {
295 // If the source start point is higher than the destination start point, then we compose the rows
296 // in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to
297 // check the x co-ordinates because the built-in copy function can handle overlapping slices.
298 d0 += (nrows - 1) * dst.Stride
299 d1 += (nrows - 1) * dst.Stride
300 s0 += (nrows - 1) * src.Stride
301 s1 += (nrows - 1) * src.Stride
302 ddelta = -dst.Stride
303 sdelta = -src.Stride
304 }
305 for ; nrows > 0; nrows-- {
306 copy(dst.Pix[d0:d1], src.Pix[s0:s1])
307 d0 += ddelta
308 d1 += ddelta
309 s0 += sdelta
310 s1 += sdelta
311 }
312 }
313
314 func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
315 x0, x1, dx := r.Min.X, r.Max.X, 1
316 y0, y1, dy := r.Min.Y, r.Max.Y, 1
317 if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
318 if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
319 x0, x1, dx = x1-1, x0-1, -1
320 y0, y1, dy = y1-1, y0-1, -1
321 }
322 }
323
324 sy := sp.Y + y0 - r.Min.Y
325 my := mp.Y + y0 - r.Min.Y
326 for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
327 sx := sp.X + x0 - r.Min.X
328 mx := mp.X + x0 - r.Min.X
329 dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
330 for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
331 ma := uint32(m)
332 if mask != nil {
333 _, _, _, ma = mask.At(mx, my).RGBA()
334 }
335 sr, sg, sb, sa := src.At(sx, sy).RGBA()
336 var dr, dg, db, da uint32
337 if op == Over {
338 rgba := dpix[x]
339 dr = uint32(rgba.R)
340 dg = uint32(rgba.G)
341 db = uint32(rgba.B)
342 da = uint32(rgba.A)
343 // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
344 // We work in 16-bit color, and so would normally do:
345 // dr |= dr << 8
346 // and similarly for dg, db and da, but instead we multiply a
347 // (which is a 16-bit color, ranging in [0,65535]) by 0x101.
348 // This yields the same result, but is fewer arithmetic operations.
349 a := (m - (sa * ma / m)) * 0x101
350 dr = (dr*a + sr*ma) / m
351 dg = (dg*a + sg*ma) / m
352 db = (db*a + sb*ma) / m
353 da = (da*a + sa*ma) / m
354 } else {
355 dr = sr * ma / m
356 dg = sg * ma / m
357 db = sb * ma / m
358 da = sa * ma / m
359 }
360 dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
361 }
362 }
363 }
364
365 // Border aligns r.Min in dst with sp in src and then replaces pixels
366 // in a w-pixel border around r in dst with the result of the Porter-Duff compositing
367 // operation ``src over dst.'' If w is positive, the border extends w pixels inside r.
368 // If w is negative, the border extends w pixels outside r.
369 func Border(dst Image, r image.Rectangle, w int, src image.Image, sp image.Point) {
370 i := w
371 if i > 0 {
372 // inside r
373 Draw(dst, image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+i), src, sp) // top
374 Draw(dst, image.Rect(r.Min.X, r.Min.Y+i, r.Min.X+i, r.Max.Y-i), src, sp.Add(image.Pt(0, i))) // left
375 Draw(dst, image.Rect(r.Max.X-i, r.Min.Y+i, r.Max.X, r.Max.Y-i), src, sp.Add(image.Pt(r.Dx()-i, i))) // right
376 Draw(dst, image.Rect(r.Min.X, r.Max.Y-i, r.Max.X, r.Max.Y), src, sp.Add(image.Pt(0, r.Dy()-i))) // bottom
377 return
378 }
379
380 // outside r;
381 i = -i
382 Draw(dst, image.Rect(r.Min.X-i, r.Min.Y-i, r.Max.X+i, r.Min.Y), src, sp.Add(image.Pt(-i, -i))) // top
383 Draw(dst, image.Rect(r.Min.X-i, r.Min.Y, r.Min.X, r.Max.Y), src, sp.Add(image.Pt(-i, 0))) // left
384 Draw(dst, image.Rect(r.Max.X, r.Min.Y, r.Max.X+i, r.Max.Y), src, sp.Add(image.Pt(r.Dx(), 0))) // right
385 Draw(dst, image.Rect(r.Min.X-i, r.Max.Y, r.Max.X+i, r.Max.Y+i), src, sp.Add(image.Pt(-i, 0))) // bottom
386 }