draw: make op a mandatory argument, not optional.

Change-Id: Ic08ce587cf458444b098b752f0fa7ab16d43c914
Reviewed-on: https://go-review.googlesource.com/9468
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/draw/example_test.go b/draw/example_test.go
index 6a2cacf..5a1ee69 100644
--- a/draw/example_test.go
+++ b/draw/example_test.go
@@ -30,7 +30,7 @@
 
 	dst := image.NewRGBA(image.Rect(0, 0, 400, 300))
 	green := image.NewUniform(color.RGBA{0x00, 0x1f, 0x00, 0xff})
-	draw.Copy(dst, image.Point{}, green, dst.Bounds(), nil)
+	draw.Copy(dst, image.Point{}, green, dst.Bounds(), draw.Src, nil)
 	qs := []draw.Interpolator{
 		draw.NearestNeighbor,
 		draw.ApproxBiLinear,
@@ -42,11 +42,11 @@
 		+2 * sin60, +2 * cos60, 100,
 	}
 
-	draw.Copy(dst, image.Point{20, 30}, src, src.Bounds(), nil)
+	draw.Copy(dst, image.Point{20, 30}, src, src.Bounds(), draw.Over, nil)
 	for i, q := range qs {
-		q.Scale(dst, image.Rect(200+10*i, 100*i, 600+10*i, 150+100*i), src, src.Bounds(), nil)
+		q.Scale(dst, image.Rect(200+10*i, 100*i, 600+10*i, 150+100*i), src, src.Bounds(), draw.Over, nil)
 	}
-	draw.NearestNeighbor.Transform(dst, t, src, src.Bounds(), nil)
+	draw.NearestNeighbor.Transform(dst, t, src, src.Bounds(), draw.Over, nil)
 
 	red := image.NewNRGBA(image.Rect(0, 0, 16, 16))
 	for y := 0; y < 16; y++ {
@@ -65,14 +65,13 @@
 		draw.Src,
 	}
 	for i, op := range ops {
-		q, opts := draw.NearestNeighbor, &draw.Options{Op: op}
 		dr := image.Rect(120+10*i, 150+60*i, 170+10*i, 200+60*i)
-		q.Scale(dst, dr, red, red.Bounds(), opts)
+		draw.NearestNeighbor.Scale(dst, dr, red, red.Bounds(), op, nil)
 		t := &f64.Aff3{
 			+cos60, -sin60, float64(190 + 10*i),
 			+sin60, +cos60, float64(140 + 50*i),
 		}
-		q.Transform(dst, t, red, red.Bounds(), opts)
+		draw.NearestNeighbor.Transform(dst, t, red, red.Bounds(), op, nil)
 	}
 
 	dr := image.Rect(0, 0, 128, 128)
@@ -95,7 +94,7 @@
 		}
 	}
 	cyan := image.NewUniform(color.RGBA{0x00, 0xff, 0xff, 0xff})
-	draw.NearestNeighbor.Scale(dst, dr, cyan, sr, &draw.Options{
+	draw.NearestNeighbor.Scale(dst, dr, cyan, sr, draw.Over, &draw.Options{
 		DstMask: checkerboard,
 		SrcMask: circle,
 	})
diff --git a/draw/gen.go b/draw/gen.go
index 8cb3e74..42505a5 100644
--- a/draw/gen.go
+++ b/draw/gen.go
@@ -703,7 +703,7 @@
 
 func expnSwitch(op, dType string, expandBoth bool, template string) string {
 	if op == "" && dType != "anyDType" {
-		lines := []string{"switch o.Op {"}
+		lines := []string{"switch op {"}
 		for _, op = range ops {
 			lines = append(lines,
 				fmt.Sprintf("case %s:", op),
@@ -876,7 +876,7 @@
 
 const (
 	codeRoot = `
-		func (z $receiver) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+		func (z $receiver) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
 			var o Options
 			if opts != nil {
 				o = *opts
@@ -890,8 +890,8 @@
 			}
 			// Make adr relative to dr.Min.
 			adr = adr.Sub(dr.Min)
-			if o.Op == Over && o.SrcMask == nil && opaque(src) {
-				o.Op = Src
+			if op == Over && o.SrcMask == nil && opaque(src) {
+				op = Src
 			}
 
 			// sr is the source pixels. If it extends beyond the src bounds,
@@ -900,20 +900,20 @@
 			//
 			// Similarly, the fast paths assume that the masks are nil.
 			if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
-				switch o.Op {
+				switch op {
 				case Over:
 					z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
 				case Src:
 					z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
 				}
 			} else if _, ok := src.(*image.Uniform); ok {
-				Draw(dst, dr, src, src.Bounds().Min, o.Op)
+				Draw(dst, dr, src, src.Bounds().Min, op)
 			} else {
 				$switch z.scale_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, src, sr, &o)
 			}
 		}
 
-		func (z $receiver) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
+		func (z $receiver) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
 			var o Options
 			if opts != nil {
 				o = *opts
@@ -926,8 +926,8 @@
 			if adr.Empty() || sr.Empty() {
 				return
 			}
-			if o.Op == Over && o.SrcMask == nil && opaque(src) {
-				o.Op = Src
+			if op == Over && o.SrcMask == nil && opaque(src) {
+				op = Src
 			}
 
 			d2s := invert(s2d)
@@ -951,14 +951,14 @@
 			//
 			// Similarly, the fast paths assume that the masks are nil.
 			if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
-				switch o.Op {
+				switch op {
 				case Over:
 					z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
 				case Src:
 					z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
 				}
 			} else if u, ok := src.(*image.Uniform); ok {
-				transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, o.Op)
+				transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
 			} else {
 				$switch z.transform_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, &d2s, src, sr, bias, &o)
 			}
@@ -1116,9 +1116,9 @@
 	`
 
 	codeKernelRoot = `
-		func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+		func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
 			if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
-				z.kernel.Scale(dst, dr, src, sr, opts)
+				z.kernel.Scale(dst, dr, src, sr, op, opts)
 				return
 			}
 
@@ -1135,12 +1135,12 @@
 			}
 			// Make adr relative to dr.Min.
 			adr = adr.Sub(dr.Min)
-			if o.Op == Over && o.SrcMask == nil && opaque(src) {
-				o.Op = Src
+			if op == Over && o.SrcMask == nil && opaque(src) {
+				op = Src
 			}
 
 			if _, ok := src.(*image.Uniform); ok && o.DstMask == nil && o.SrcMask == nil && sr.In(src.Bounds()) {
-				Draw(dst, dr, src, src.Bounds().Min, o.Op)
+				Draw(dst, dr, src, src.Bounds().Min, op)
 				return
 			}
 
@@ -1168,7 +1168,7 @@
 			}
 
 			if o.DstMask != nil {
-				switch o.Op {
+				switch op {
 				case Over:
 					z.scaleY_Image_Over(dst, dr, adr, tmp, &o)
 				case Src:
@@ -1179,7 +1179,7 @@
 			}
 		}
 
-		func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
+		func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
 			var o Options
 			if opts != nil {
 				o = *opts
@@ -1192,8 +1192,8 @@
 			if adr.Empty() || sr.Empty() {
 				return
 			}
-			if o.Op == Over && o.SrcMask == nil && opaque(src) {
-				o.Op = Src
+			if op == Over && o.SrcMask == nil && opaque(src) {
+				op = Src
 			}
 			d2s := invert(s2d)
 			// bias is a translation of the mapping from dst coordinates to src
@@ -1212,7 +1212,7 @@
 			adr = adr.Sub(dr.Min)
 
 			if u, ok := src.(*image.Uniform); ok && o.DstMask != nil && o.SrcMask != nil && sr.In(src.Bounds()) {
-				transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, o.Op)
+				transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
 				return
 			}
 
@@ -1231,7 +1231,7 @@
 			//
 			// Similarly, the fast paths assume that the masks are nil.
 			if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
-				switch o.Op {
+				switch op {
 				case Over:
 					q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
 				case Src:
diff --git a/draw/impl.go b/draw/impl.go
index 0bf27e9..13274fa 100644
--- a/draw/impl.go
+++ b/draw/impl.go
@@ -10,7 +10,7 @@
 	"golang.org/x/image/math/f64"
 )
 
-func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
 	var o Options
 	if opts != nil {
 		o = *opts
@@ -24,8 +24,8 @@
 	}
 	// Make adr relative to dr.Min.
 	adr = adr.Sub(dr.Min)
-	if o.Op == Over && o.SrcMask == nil && opaque(src) {
-		o.Op = Src
+	if op == Over && o.SrcMask == nil && opaque(src) {
+		op = Src
 	}
 
 	// sr is the source pixels. If it extends beyond the src bounds,
@@ -34,16 +34,16 @@
 	//
 	// Similarly, the fast paths assume that the masks are nil.
 	if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
-		switch o.Op {
+		switch op {
 		case Over:
 			z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
 		case Src:
 			z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
 		}
 	} else if _, ok := src.(*image.Uniform); ok {
-		Draw(dst, dr, src, src.Bounds().Min, o.Op)
+		Draw(dst, dr, src, src.Bounds().Min, op)
 	} else {
-		switch o.Op {
+		switch op {
 		case Over:
 			switch dst := dst.(type) {
 			case *image.RGBA:
@@ -97,7 +97,7 @@
 	}
 }
 
-func (z nnInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
+func (z nnInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
 	var o Options
 	if opts != nil {
 		o = *opts
@@ -110,8 +110,8 @@
 	if adr.Empty() || sr.Empty() {
 		return
 	}
-	if o.Op == Over && o.SrcMask == nil && opaque(src) {
-		o.Op = Src
+	if op == Over && o.SrcMask == nil && opaque(src) {
+		op = Src
 	}
 
 	d2s := invert(s2d)
@@ -135,16 +135,16 @@
 	//
 	// Similarly, the fast paths assume that the masks are nil.
 	if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
-		switch o.Op {
+		switch op {
 		case Over:
 			z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
 		case Src:
 			z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
 		}
 	} else if u, ok := src.(*image.Uniform); ok {
-		transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, o.Op)
+		transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
 	} else {
-		switch o.Op {
+		switch op {
 		case Over:
 			switch dst := dst.(type) {
 			case *image.RGBA:
@@ -1031,7 +1031,7 @@
 	}
 }
 
-func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
 	var o Options
 	if opts != nil {
 		o = *opts
@@ -1045,8 +1045,8 @@
 	}
 	// Make adr relative to dr.Min.
 	adr = adr.Sub(dr.Min)
-	if o.Op == Over && o.SrcMask == nil && opaque(src) {
-		o.Op = Src
+	if op == Over && o.SrcMask == nil && opaque(src) {
+		op = Src
 	}
 
 	// sr is the source pixels. If it extends beyond the src bounds,
@@ -1055,16 +1055,16 @@
 	//
 	// Similarly, the fast paths assume that the masks are nil.
 	if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
-		switch o.Op {
+		switch op {
 		case Over:
 			z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
 		case Src:
 			z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
 		}
 	} else if _, ok := src.(*image.Uniform); ok {
-		Draw(dst, dr, src, src.Bounds().Min, o.Op)
+		Draw(dst, dr, src, src.Bounds().Min, op)
 	} else {
-		switch o.Op {
+		switch op {
 		case Over:
 			switch dst := dst.(type) {
 			case *image.RGBA:
@@ -1118,7 +1118,7 @@
 	}
 }
 
-func (z ablInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
+func (z ablInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
 	var o Options
 	if opts != nil {
 		o = *opts
@@ -1131,8 +1131,8 @@
 	if adr.Empty() || sr.Empty() {
 		return
 	}
-	if o.Op == Over && o.SrcMask == nil && opaque(src) {
-		o.Op = Src
+	if op == Over && o.SrcMask == nil && opaque(src) {
+		op = Src
 	}
 
 	d2s := invert(s2d)
@@ -1156,16 +1156,16 @@
 	//
 	// Similarly, the fast paths assume that the masks are nil.
 	if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
-		switch o.Op {
+		switch op {
 		case Over:
 			z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
 		case Src:
 			z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
 		}
 	} else if u, ok := src.(*image.Uniform); ok {
-		transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, o.Op)
+		transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
 	} else {
-		switch o.Op {
+		switch op {
 		case Over:
 			switch dst := dst.(type) {
 			case *image.RGBA:
@@ -4398,9 +4398,9 @@
 	}
 }
 
-func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
 	if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
-		z.kernel.Scale(dst, dr, src, sr, opts)
+		z.kernel.Scale(dst, dr, src, sr, op, opts)
 		return
 	}
 
@@ -4417,12 +4417,12 @@
 	}
 	// Make adr relative to dr.Min.
 	adr = adr.Sub(dr.Min)
-	if o.Op == Over && o.SrcMask == nil && opaque(src) {
-		o.Op = Src
+	if op == Over && o.SrcMask == nil && opaque(src) {
+		op = Src
 	}
 
 	if _, ok := src.(*image.Uniform); ok && o.DstMask == nil && o.SrcMask == nil && sr.In(src.Bounds()) {
-		Draw(dst, dr, src, src.Bounds().Min, o.Op)
+		Draw(dst, dr, src, src.Bounds().Min, op)
 		return
 	}
 
@@ -4472,14 +4472,14 @@
 	}
 
 	if o.DstMask != nil {
-		switch o.Op {
+		switch op {
 		case Over:
 			z.scaleY_Image_Over(dst, dr, adr, tmp, &o)
 		case Src:
 			z.scaleY_Image_Src(dst, dr, adr, tmp, &o)
 		}
 	} else {
-		switch o.Op {
+		switch op {
 		case Over:
 			switch dst := dst.(type) {
 			case *image.RGBA:
@@ -4498,7 +4498,7 @@
 	}
 }
 
-func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
+func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
 	var o Options
 	if opts != nil {
 		o = *opts
@@ -4511,8 +4511,8 @@
 	if adr.Empty() || sr.Empty() {
 		return
 	}
-	if o.Op == Over && o.SrcMask == nil && opaque(src) {
-		o.Op = Src
+	if op == Over && o.SrcMask == nil && opaque(src) {
+		op = Src
 	}
 	d2s := invert(s2d)
 	// bias is a translation of the mapping from dst coordinates to src
@@ -4531,7 +4531,7 @@
 	adr = adr.Sub(dr.Min)
 
 	if u, ok := src.(*image.Uniform); ok && o.DstMask != nil && o.SrcMask != nil && sr.In(src.Bounds()) {
-		transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, o.Op)
+		transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
 		return
 	}
 
@@ -4550,14 +4550,14 @@
 	//
 	// Similarly, the fast paths assume that the masks are nil.
 	if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
-		switch o.Op {
+		switch op {
 		case Over:
 			q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
 		case Src:
 			q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
 		}
 	} else {
-		switch o.Op {
+		switch op {
 		case Over:
 			switch dst := dst.(type) {
 			case *image.RGBA:
diff --git a/draw/scale.go b/draw/scale.go
index 4d77764..6c9e93a 100644
--- a/draw/scale.go
+++ b/draw/scale.go
@@ -15,33 +15,34 @@
 	"golang.org/x/image/math/f64"
 )
 
-// Copy copies the part of the source image defined by src and sr and writes to
-// the part of the destination image defined by dst and the translation of sr
-// so that sr.Min translates to dp.
-func Copy(dst Image, dp image.Point, src image.Image, sr image.Rectangle, opts *Options) {
+// Copy copies the part of the source image defined by src and sr and writes
+// the result of a Porter-Duff composition to the part of the destination image
+// defined by dst and the translation of sr so that sr.Min translates to dp.
+func Copy(dst Image, dp image.Point, src image.Image, sr image.Rectangle, op Op, opts *Options) {
 	var o Options
 	if opts != nil {
 		o = *opts
 	}
 	dr := sr.Add(dp.Sub(sr.Min))
 	if o.DstMask == nil {
-		DrawMask(dst, dr, src, sr.Min, o.SrcMask, o.SrcMaskP.Add(sr.Min), o.Op)
+		DrawMask(dst, dr, src, sr.Min, o.SrcMask, o.SrcMaskP.Add(sr.Min), op)
 	} else {
-		NearestNeighbor.Scale(dst, dr, src, sr, opts)
+		NearestNeighbor.Scale(dst, dr, src, sr, op, opts)
 	}
 }
 
 // Scaler scales the part of the source image defined by src and sr and writes
-// to the part of the destination image defined by dst and dr.
+// the result of a Porter-Duff composition to the part of the destination image
+// defined by dst and dr.
 //
 // A Scaler is safe to use concurrently.
 type Scaler interface {
-	Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options)
+	Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options)
 }
 
 // Transformer transforms the part of the source image defined by src and sr
-// and writes to the part of the destination image defined by dst and the
-// affine transform m applied to sr.
+// and writes the result of a Porter-Duff composition to the part of the
+// destination image defined by dst and the affine transform m applied to sr.
 //
 // For example, if m is the matrix
 //
@@ -53,16 +54,13 @@
 //
 // A Transformer is safe to use concurrently.
 type Transformer interface {
-	Transform(dst Image, m *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options)
+	Transform(dst Image, m *f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options)
 }
 
 // Options are optional parameters to Copy, Scale and Transform.
 //
 // A nil *Options means to use the default (zero) values of each field.
 type Options struct {
-	// Op is the compositing operator. The default value is Over.
-	Op Op
-
 	// Masks limit what parts of the dst image are drawn to and what parts of
 	// the src image are drawn from.
 	//
@@ -124,8 +122,8 @@
 }
 
 // Scale implements the Scaler interface.
-func (q *Kernel) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
-	q.newScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy(), false).Scale(dst, dr, src, sr, opts)
+func (q *Kernel) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+	q.newScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy(), false).Scale(dst, dr, src, sr, op, opts)
 }
 
 // NewScaler returns a Scaler that is optimized for scaling multiple times with
diff --git a/draw/scale_test.go b/draw/scale_test.go
index cfa38a7..b1f3db9 100644
--- a/draw/scale_test.go
+++ b/draw/scale_test.go
@@ -64,9 +64,6 @@
 	if prefix == "tux" {
 		op, scale = Over, 0.125
 	}
-	opts := &Options{
-		Op: op,
-	}
 	green := image.NewUniform(color.RGBA{0x00, 0x22, 0x11, 0xff})
 
 	testCases := map[string]Interpolator{
@@ -79,11 +76,11 @@
 		goldenFilename := fmt.Sprintf("../testdata/%s-%s-%s.png", prefix, direction, name)
 
 		got := image.NewRGBA(image.Rect(0, 0, w, h))
-		Copy(got, image.Point{}, green, got.Bounds(), nil)
+		Copy(got, image.Point{}, green, got.Bounds(), Src, nil)
 		if direction == "rotate" {
-			q.Transform(got, transformMatrix(scale, 40, 10), src, src.Bounds(), opts)
+			q.Transform(got, transformMatrix(scale, 40, 10), src, src.Bounds(), op, nil)
 		} else {
-			q.Scale(got, got.Bounds(), src, src.Bounds(), opts)
+			q.Scale(got, got.Bounds(), src, src.Bounds(), op, nil)
 		}
 
 		if *genGoldenFiles {
@@ -132,12 +129,12 @@
 	}
 	for op, want := range testCases {
 		dst := image.NewRGBA(image.Rect(0, 0, 2, 2))
-		Copy(dst, image.Point{}, blue, dst.Bounds(), nil)
+		Copy(dst, image.Point{}, blue, dst.Bounds(), Src, nil)
 
 		src := image.NewRGBA(image.Rect(0, 0, 1, 1))
 		src.SetRGBA(0, 0, color.RGBA{0x7f, 0x00, 0x00, 0x7f})
 
-		NearestNeighbor.Scale(dst, dst.Bounds(), src, src.Bounds(), &Options{Op: op})
+		NearestNeighbor.Scale(dst, dst.Bounds(), src, src.Bounds(), op, nil)
 
 		if got := dst.RGBAAt(0, 0); got != want {
 			t.Errorf("op=%v: got %v, want %v", op, got, want)
@@ -176,7 +173,7 @@
 	}
 
 	dst := image.NewRGBA(image.Rect(0, 0, 32, 32))
-	CatmullRom.Scale(dst, dst.Bounds(), src, src.Bounds(), nil)
+	CatmullRom.Scale(dst, dst.Bounds(), src, src.Bounds(), Over, nil)
 	if err := check(dst); err != nil {
 		t.Fatalf("dst image: %v", err)
 	}
@@ -213,11 +210,11 @@
 			var interp func(dst *image.RGBA)
 			if transform {
 				interp = func(dst *image.RGBA) {
-					q.Transform(dst, transformMatrix(3.75, 2, 1), src, src.Bounds(), nil)
+					q.Transform(dst, transformMatrix(3.75, 2, 1), src, src.Bounds(), Over, nil)
 				}
 			} else {
 				interp = func(dst *image.RGBA) {
-					q.Scale(dst, outer, src, src.Bounds(), nil)
+					q.Scale(dst, outer, src, src.Bounds(), Over, nil)
 				}
 			}
 
@@ -292,9 +289,9 @@
 		for _, q := range qs {
 			want := image.NewRGBA(image.Rect(0, 0, 20, 20))
 			if transform {
-				q.Transform(want, m00, src, sr, nil)
+				q.Transform(want, m00, src, sr, Over, nil)
 			} else {
-				q.Scale(want, want.Bounds(), src, sr, nil)
+				q.Scale(want, want.Bounds(), src, sr, Over, nil)
 			}
 			for _, delta := range deltas {
 				tsrc := &translatedImage{src, delta}
@@ -304,9 +301,9 @@
 						1, 0, -float64(delta.X),
 						0, 1, -float64(delta.Y),
 					})
-					q.Transform(got, &m, tsrc, sr.Add(delta), nil)
+					q.Transform(got, &m, tsrc, sr.Add(delta), Over, nil)
 				} else {
-					q.Scale(got, got.Bounds(), tsrc, sr.Add(delta), nil)
+					q.Scale(got, got.Bounds(), tsrc, sr.Add(delta), Over, nil)
 				}
 				if !bytes.Equal(got.Pix, want.Pix) {
 					t.Errorf("pix differ for delta=%v, transform=%t, q=%T", delta, transform, q)
@@ -325,8 +322,8 @@
 	red := image.NewUniform(color.RGBA{0xff, 0x00, 0x00, 0xff})
 	blue := image.NewUniform(color.RGBA{0x00, 0x00, 0xff, 0xff})
 	dst := image.NewRGBA(image.Rect(0, 0, 6, 1))
-	Copy(dst, image.Point{}, blue, dst.Bounds(), nil)
-	NearestNeighbor.Scale(dst, dst.Bounds(), red, image.Rect(0, 0, 3, 1), &Options{
+	Copy(dst, image.Point{}, blue, dst.Bounds(), Src, nil)
+	NearestNeighbor.Scale(dst, dst.Bounds(), red, image.Rect(0, 0, 3, 1), Over, &Options{
 		SrcMask:  srcMask,
 		SrcMaskP: image.Point{20, 0},
 	})
@@ -367,8 +364,8 @@
 	}
 	for _, q := range qs {
 		dst := image.NewRGBA(image.Rect(0, 0, 3, 1))
-		Copy(dst, image.Point{}, blue, dst.Bounds(), nil)
-		q.Scale(dst, dst.Bounds(), red, red.Bounds(), &Options{
+		Copy(dst, image.Point{}, blue, dst.Bounds(), Src, nil)
+		q.Scale(dst, dst.Bounds(), red, red.Bounds(), Over, &Options{
 			DstMask:  dstMask,
 			DstMaskP: image.Point{20, 0},
 		})
@@ -410,8 +407,8 @@
 
 	mk := func(q Transformer, dstMask image.Image, dstMaskP image.Point) *image.RGBA {
 		m := image.NewRGBA(bounds)
-		Copy(m, bounds.Min, dstOutside, bounds, nil)
-		q.Transform(m, m00, src, src.Bounds(), &Options{
+		Copy(m, bounds.Min, dstOutside, bounds, Src, nil)
+		q.Transform(m, m00, src, src.Bounds(), Over, &Options{
 			DstMask:  dstMask,
 			DstMaskP: dstMaskP,
 		})
@@ -536,7 +533,6 @@
 				for _, transform := range []bool{false, true} {
 					for _, q := range qs {
 						for _, op := range ops {
-							opts := &Options{Op: op}
 							dst0 := image.NewRGBA(drs[0])
 							dst1 := image.NewRGBA(drs[0])
 							Draw(dst0, dst0.Bounds(), blue, image.Point{}, Src)
@@ -544,11 +540,11 @@
 
 							if transform {
 								m := transformMatrix(3.75, 2, 1)
-								q.Transform(dst0, m, src, sr, opts)
-								q.Transform(dstWrapper{dst1}, m, srcWrapper{src}, sr, opts)
+								q.Transform(dst0, m, src, sr, op, nil)
+								q.Transform(dstWrapper{dst1}, m, srcWrapper{src}, sr, op, nil)
 							} else {
-								q.Scale(dst0, dr, src, sr, opts)
-								q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr, opts)
+								q.Scale(dst0, dr, src, sr, op, nil)
+								q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr, op, nil)
 							}
 
 							if !bytes.Equal(dst0.Pix, dst1.Pix) {
@@ -631,14 +627,11 @@
 	}); ok {
 		scaler = n.NewScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy())
 	}
-	opts := &Options{
-		Op: op,
-	}
 
 	b.ReportAllocs()
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
-		scaler.Scale(dst, dr, src, sr, opts)
+		scaler.Scale(dst, dr, src, sr, op, nil)
 	}
 }
 
@@ -650,14 +643,11 @@
 	}
 	sr := src.Bounds()
 	m := transformMatrix(3.75, 40, 10)
-	opts := &Options{
-		Op: op,
-	}
 
 	b.ReportAllocs()
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
-		q.Transform(dst, m, src, sr, opts)
+		q.Transform(dst, m, src, sr, op, nil)
 	}
 }