summaryrefslogtreecommitdiff
path: root/src/pkg/exp
diff options
context:
space:
mode:
authorNigel Tao <nigeltao@golang.org>2010-05-10 10:32:08 +1000
committerNigel Tao <nigeltao@golang.org>2010-05-10 10:32:08 +1000
commit03339a24bc08840777d0c72888c9779661fa83bb (patch)
tree867807836b77420de13380fba9ce16870d44d4f4 /src/pkg/exp
parent8675f36b64fd8dc030b7397b0fb6f80196fbe7d9 (diff)
downloadgolang-03339a24bc08840777d0c72888c9779661fa83bb.tar.gz
exp/draw fast path for glyph images.
To draw.Draw a 32x32 image.Alpha 10000 times, Before: 633ms with 10000 mallocs After: 49ms with 0 mallocs These times are just blitting an image.Alpha, and do not include rasterizing a glyph's vector contours to an image.Alpha. The "generic" test case in draw_test.go tests this fast path. R=rsc CC=golang-dev http://codereview.appspot.com/1122043
Diffstat (limited to 'src/pkg/exp')
-rw-r--r--src/pkg/exp/draw/draw.go44
1 files changed, 43 insertions, 1 deletions
diff --git a/src/pkg/exp/draw/draw.go b/src/pkg/exp/draw/draw.go
index bf5a08479..0589dde5e 100644
--- a/src/pkg/exp/draw/draw.go
+++ b/src/pkg/exp/draw/draw.go
@@ -62,7 +62,12 @@ func DrawMask(dst Image, r Rectangle, src image.Image, sp Point, mask image.Imag
// Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation.
if dst0, ok := dst.(*image.RGBA); ok {
if op == Over {
- // TODO(nigeltao): Implement a fast path for font glyphs (i.e. when mask is an image.Alpha).
+ if mask0, ok := mask.(*image.Alpha); ok {
+ if src0, ok := src.(image.ColorImage); ok {
+ drawGlyphOver(dst0, r, src0, mask0, mp)
+ return
+ }
+ }
} else {
if mask == nil {
if src0, ok := src.(image.ColorImage); ok {
@@ -147,6 +152,43 @@ func DrawMask(dst Image, r Rectangle, src image.Image, sp Point, mask image.Imag
}
}
+func drawGlyphOver(dst *image.RGBA, r Rectangle, src image.ColorImage, mask *image.Alpha, mp Point) {
+ x0, x1 := r.Min.X, r.Max.X
+ y0, y1 := r.Min.Y, r.Max.Y
+ cr, cg, cb, ca := src.RGBA()
+ cr >>= 16
+ cg >>= 16
+ cb >>= 16
+ ca >>= 16
+ for y, my := y0, mp.Y; y != y1; y, my = y+1, my+1 {
+ for x, mx := x0, mp.X; x != x1; x, mx = x+1, mx+1 {
+ ma := uint32(mask.Pixel[my][mx].A)
+ if ma == 0 {
+ continue
+ }
+ ma |= ma << 8
+ dr := uint32(dst.Pixel[y][x].R)
+ dg := uint32(dst.Pixel[y][x].G)
+ db := uint32(dst.Pixel[y][x].B)
+ da := uint32(dst.Pixel[y][x].A)
+ // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
+ // We work in 16-bit color, and so would normally do:
+ // dr |= dr << 8
+ // and similarly for dg, db and da, but instead we multiply a
+ // (which is a 16-bit color, ranging in [0,65535]) by 0x101.
+ // This yields the same result, but is fewer arithmetic operations.
+ const M = 1<<16 - 1
+ a := M - (ca * ma / M)
+ a *= 0x101
+ dr = (dr*a + cr*ma) / M
+ dg = (dg*a + cg*ma) / M
+ db = (db*a + cb*ma) / M
+ da = (da*a + ca*ma) / M
+ dst.Pixel[y][x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+ }
+ }
+}
+
func drawFill(dst *image.RGBA, r Rectangle, src image.ColorImage) {
if r.Dy() < 1 {
return