func expnDollar()

in draw/gen.go [207:703]


func expnDollar(prefix, dollar, suffix string, d *data) string {
	switch dollar {
	case "dType":
		return prefix + d.dType + suffix
	case "dTypeRN":
		return prefix + relName(d.dType) + suffix
	case "sratio":
		return prefix + d.sratio + suffix
	case "sType":
		return prefix + d.sType + suffix
	case "sTypeRN":
		return prefix + relName(d.sType) + suffix
	case "receiver":
		return prefix + d.receiver + suffix
	case "op":
		return prefix + d.op + suffix

	case "switch":
		return expnSwitch("", "", true, suffix)
	case "switchD":
		return expnSwitch("", "", false, suffix)
	case "switchS":
		return expnSwitch("", "anyDType", false, suffix)

	case "preOuter":
		switch d.dType {
		default:
			return ";"
		case "Image":
			s := ""
			if d.sType == "image.Image" {
				s = "srcMask, smp := opts.SrcMask, opts.SrcMaskP\n"
			}
			return s +
				"dstMask, dmp := opts.DstMask, opts.DstMaskP\n" +
				"dstColorRGBA64 := &color.RGBA64{}\n" +
				"dstColor := color.Color(dstColorRGBA64)"
		}

	case "preInner":
		switch d.dType {
		default:
			return ";"
		case "*image.RGBA":
			return "d := " + pixOffset("dst", "dr.Min.X+adr.Min.X", "dr.Min.Y+int(dy)", "*4", "*dst.Stride")
		}

	case "preKernelOuter":
		switch d.sType {
		default:
			return ";"
		case "image.Image":
			return "srcMask, smp := opts.SrcMask, opts.SrcMaskP"
		}

	case "preKernelInner":
		switch d.dType {
		default:
			return ";"
		case "*image.RGBA":
			return "d := " + pixOffset("dst", "dr.Min.X+int(dx)", "dr.Min.Y+adr.Min.Y", "*4", "*dst.Stride")
		}

	case "blend":
		args, _ := splitArgs(suffix)
		if len(args) != 4 {
			return ""
		}
		switch d.sType {
		default:
			return argf(args, ""+
				"$3r = $0*$1r + $2*$3r\n"+
				"$3g = $0*$1g + $2*$3g\n"+
				"$3b = $0*$1b + $2*$3b\n"+
				"$3a = $0*$1a + $2*$3a",
			)
		case "*image.Gray":
			return argf(args, ""+
				"$3r = $0*$1r + $2*$3r",
			)
		case "*image.YCbCr":
			return argf(args, ""+
				"$3r = $0*$1r + $2*$3r\n"+
				"$3g = $0*$1g + $2*$3g\n"+
				"$3b = $0*$1b + $2*$3b",
			)
		}

	case "clampToAlpha":
		if alwaysOpaque[d.sType] {
			return ";"
		}
		// Go uses alpha-premultiplied color. The naive computation can lead to
		// invalid colors, e.g. red > alpha, when some weights are negative.
		return `
			if pr > pa {
				pr = pa
			}
			if pg > pa {
				pg = pa
			}
			if pb > pa {
				pb = pa
			}
		`

	case "convFtou":
		args, _ := splitArgs(suffix)
		if len(args) != 2 {
			return ""
		}

		switch d.sType {
		default:
			return argf(args, ""+
				"$0r := uint32($1r)\n"+
				"$0g := uint32($1g)\n"+
				"$0b := uint32($1b)\n"+
				"$0a := uint32($1a)",
			)
		case "*image.Gray":
			return argf(args, ""+
				"$0r := uint32($1r)",
			)
		case "*image.YCbCr":
			return argf(args, ""+
				"$0r := uint32($1r)\n"+
				"$0g := uint32($1g)\n"+
				"$0b := uint32($1b)",
			)
		}

	case "outputu":
		args, _ := splitArgs(suffix)
		if len(args) != 3 {
			return ""
		}

		switch d.op {
		case "Over":
			switch d.dType {
			default:
				log.Fatalf("bad dType %q", d.dType)
			case "Image":
				return argf(args, ""+
					"qr, qg, qb, qa := dst.At($0, $1).RGBA()\n"+
					"if dstMask != nil {\n"+
					"	_, _, _, ma := dstMask.At(dmp.X + $0, dmp.Y + $1).RGBA()\n"+
					"	$2r = $2r * ma / 0xffff\n"+
					"	$2g = $2g * ma / 0xffff\n"+
					"	$2b = $2b * ma / 0xffff\n"+
					"	$2a = $2a * ma / 0xffff\n"+
					"}\n"+
					"$2a1 := 0xffff - $2a\n"+
					"dstColorRGBA64.R = uint16(qr*$2a1/0xffff + $2r)\n"+
					"dstColorRGBA64.G = uint16(qg*$2a1/0xffff + $2g)\n"+
					"dstColorRGBA64.B = uint16(qb*$2a1/0xffff + $2b)\n"+
					"dstColorRGBA64.A = uint16(qa*$2a1/0xffff + $2a)\n"+
					"dst.Set($0, $1, dstColor)",
				)
			case "*image.RGBA":
				return argf(args, ""+
					"$2a1 := (0xffff - $2a) * 0x101\n"+
					"dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*$2a1/0xffff + $2r) >> 8)\n"+
					"dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*$2a1/0xffff + $2g) >> 8)\n"+
					"dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*$2a1/0xffff + $2b) >> 8)\n"+
					"dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*$2a1/0xffff + $2a) >> 8)",
				)
			}

		case "Src":
			switch d.dType {
			default:
				log.Fatalf("bad dType %q", d.dType)
			case "Image":
				return argf(args, ""+
					"if dstMask != nil {\n"+
					"	qr, qg, qb, qa := dst.At($0, $1).RGBA()\n"+
					"	_, _, _, ma := dstMask.At(dmp.X + $0, dmp.Y + $1).RGBA()\n"+
					"	pr = pr * ma / 0xffff\n"+
					"	pg = pg * ma / 0xffff\n"+
					"	pb = pb * ma / 0xffff\n"+
					"	pa = pa * ma / 0xffff\n"+
					"	$2a1 := 0xffff - ma\n"+ // Note that this is ma, not $2a.
					"	dstColorRGBA64.R = uint16(qr*$2a1/0xffff + $2r)\n"+
					"	dstColorRGBA64.G = uint16(qg*$2a1/0xffff + $2g)\n"+
					"	dstColorRGBA64.B = uint16(qb*$2a1/0xffff + $2b)\n"+
					"	dstColorRGBA64.A = uint16(qa*$2a1/0xffff + $2a)\n"+
					"	dst.Set($0, $1, dstColor)\n"+
					"} else {\n"+
					"	dstColorRGBA64.R = uint16($2r)\n"+
					"	dstColorRGBA64.G = uint16($2g)\n"+
					"	dstColorRGBA64.B = uint16($2b)\n"+
					"	dstColorRGBA64.A = uint16($2a)\n"+
					"	dst.Set($0, $1, dstColor)\n"+
					"}",
				)
			case "*image.RGBA":
				switch d.sType {
				default:
					return argf(args, ""+
						"dst.Pix[d+0] = uint8($2r >> 8)\n"+
						"dst.Pix[d+1] = uint8($2g >> 8)\n"+
						"dst.Pix[d+2] = uint8($2b >> 8)\n"+
						"dst.Pix[d+3] = uint8($2a >> 8)",
					)
				case "*image.Gray":
					return argf(args, ""+
						"out := uint8($2r >> 8)\n"+
						"dst.Pix[d+0] = out\n"+
						"dst.Pix[d+1] = out\n"+
						"dst.Pix[d+2] = out\n"+
						"dst.Pix[d+3] = 0xff",
					)
				case "*image.YCbCr":
					return argf(args, ""+
						"dst.Pix[d+0] = uint8($2r >> 8)\n"+
						"dst.Pix[d+1] = uint8($2g >> 8)\n"+
						"dst.Pix[d+2] = uint8($2b >> 8)\n"+
						"dst.Pix[d+3] = 0xff",
					)
				}
			}
		}

	case "outputf":
		args, _ := splitArgs(suffix)
		if len(args) != 5 {
			return ""
		}
		ret := ""

		switch d.op {
		case "Over":
			switch d.dType {
			default:
				log.Fatalf("bad dType %q", d.dType)
			case "Image":
				ret = argf(args, ""+
					"qr, qg, qb, qa := dst.At($0, $1).RGBA()\n"+
					"$3r0 := uint32($2($3r * $4))\n"+
					"$3g0 := uint32($2($3g * $4))\n"+
					"$3b0 := uint32($2($3b * $4))\n"+
					"$3a0 := uint32($2($3a * $4))\n"+
					"if dstMask != nil {\n"+
					"	_, _, _, ma := dstMask.At(dmp.X + $0, dmp.Y + $1).RGBA()\n"+
					"	$3r0 = $3r0 * ma / 0xffff\n"+
					"	$3g0 = $3g0 * ma / 0xffff\n"+
					"	$3b0 = $3b0 * ma / 0xffff\n"+
					"	$3a0 = $3a0 * ma / 0xffff\n"+
					"}\n"+
					"$3a1 := 0xffff - $3a0\n"+
					"dstColorRGBA64.R = uint16(qr*$3a1/0xffff + $3r0)\n"+
					"dstColorRGBA64.G = uint16(qg*$3a1/0xffff + $3g0)\n"+
					"dstColorRGBA64.B = uint16(qb*$3a1/0xffff + $3b0)\n"+
					"dstColorRGBA64.A = uint16(qa*$3a1/0xffff + $3a0)\n"+
					"dst.Set($0, $1, dstColor)",
				)
			case "*image.RGBA":
				ret = argf(args, ""+
					"$3r0 := uint32($2($3r * $4))\n"+
					"$3g0 := uint32($2($3g * $4))\n"+
					"$3b0 := uint32($2($3b * $4))\n"+
					"$3a0 := uint32($2($3a * $4))\n"+
					"$3a1 := (0xffff - uint32($3a0)) * 0x101\n"+
					"dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*$3a1/0xffff + $3r0) >> 8)\n"+
					"dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*$3a1/0xffff + $3g0) >> 8)\n"+
					"dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*$3a1/0xffff + $3b0) >> 8)\n"+
					"dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*$3a1/0xffff + $3a0) >> 8)",
				)
			}

		case "Src":
			switch d.dType {
			default:
				log.Fatalf("bad dType %q", d.dType)
			case "Image":
				ret = argf(args, ""+
					"if dstMask != nil {\n"+
					"	qr, qg, qb, qa := dst.At($0, $1).RGBA()\n"+
					"	_, _, _, ma := dstMask.At(dmp.X + $0, dmp.Y + $1).RGBA()\n"+
					"	pr := uint32($2($3r * $4)) * ma / 0xffff\n"+
					"	pg := uint32($2($3g * $4)) * ma / 0xffff\n"+
					"	pb := uint32($2($3b * $4)) * ma / 0xffff\n"+
					"	pa := uint32($2($3a * $4)) * ma / 0xffff\n"+
					"	pa1 := 0xffff - ma\n"+ // Note that this is ma, not pa.
					"	dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)\n"+
					"	dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)\n"+
					"	dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)\n"+
					"	dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)\n"+
					"	dst.Set($0, $1, dstColor)\n"+
					"} else {\n"+
					"	dstColorRGBA64.R = $2($3r * $4)\n"+
					"	dstColorRGBA64.G = $2($3g * $4)\n"+
					"	dstColorRGBA64.B = $2($3b * $4)\n"+
					"	dstColorRGBA64.A = $2($3a * $4)\n"+
					"	dst.Set($0, $1, dstColor)\n"+
					"}",
				)
			case "*image.RGBA":
				switch d.sType {
				default:
					ret = argf(args, ""+
						"dst.Pix[d+0] = uint8($2($3r * $4) >> 8)\n"+
						"dst.Pix[d+1] = uint8($2($3g * $4) >> 8)\n"+
						"dst.Pix[d+2] = uint8($2($3b * $4) >> 8)\n"+
						"dst.Pix[d+3] = uint8($2($3a * $4) >> 8)",
					)
				case "*image.Gray":
					ret = argf(args, ""+
						"out := uint8($2($3r * $4) >> 8)\n"+
						"dst.Pix[d+0] = out\n"+
						"dst.Pix[d+1] = out\n"+
						"dst.Pix[d+2] = out\n"+
						"dst.Pix[d+3] = 0xff",
					)
				case "*image.YCbCr":
					ret = argf(args, ""+
						"dst.Pix[d+0] = uint8($2($3r * $4) >> 8)\n"+
						"dst.Pix[d+1] = uint8($2($3g * $4) >> 8)\n"+
						"dst.Pix[d+2] = uint8($2($3b * $4) >> 8)\n"+
						"dst.Pix[d+3] = 0xff",
					)
				}
			}
		}

		return strings.Replace(ret, " * 1)", ")", -1)

	case "srcf", "srcu":
		lhs, eqOp := splitEq(prefix)
		if lhs == "" {
			return ""
		}
		args, extra := splitArgs(suffix)
		if len(args) != 2 {
			return ""
		}

		tmp := ""
		if dollar == "srcf" {
			tmp = "u"
		}

		// TODO: there's no need to multiply by 0x101 in the switch below if
		// the next thing we're going to do is shift right by 8.

		buf := new(bytes.Buffer)
		switch d.sType {
		default:
			log.Fatalf("bad sType %q", d.sType)
		case "image.Image":
			fmt.Fprintf(buf, ""+
				"%sr%s, %sg%s, %sb%s, %sa%s := src.At(%s, %s).RGBA()\n",
				lhs, tmp, lhs, tmp, lhs, tmp, lhs, tmp, args[0], args[1],
			)
			if d.dType == "" || d.dType == "Image" {
				fmt.Fprintf(buf, ""+
					"if srcMask != nil {\n"+
					"	_, _, _, ma := srcMask.At(smp.X+%s, smp.Y+%s).RGBA()\n"+
					"	%sr%s = %sr%s * ma / 0xffff\n"+
					"	%sg%s = %sg%s * ma / 0xffff\n"+
					"	%sb%s = %sb%s * ma / 0xffff\n"+
					"	%sa%s = %sa%s * ma / 0xffff\n"+
					"}\n",
					args[0], args[1],
					lhs, tmp, lhs, tmp,
					lhs, tmp, lhs, tmp,
					lhs, tmp, lhs, tmp,
					lhs, tmp, lhs, tmp,
				)
			}
		case "*image.Gray":
			fmt.Fprintf(buf, ""+
				"%si := %s\n"+
				"%sr%s := uint32(src.Pix[%si]) * 0x101\n",
				lhs, pixOffset("src", args[0], args[1], "", "*src.Stride"),
				lhs, tmp, lhs,
			)
		case "*image.NRGBA":
			fmt.Fprintf(buf, ""+
				"%si := %s\n"+
				"%sa%s := uint32(src.Pix[%si+3]) * 0x101\n"+
				"%sr%s := uint32(src.Pix[%si+0]) * %sa%s / 0xff\n"+
				"%sg%s := uint32(src.Pix[%si+1]) * %sa%s / 0xff\n"+
				"%sb%s := uint32(src.Pix[%si+2]) * %sa%s / 0xff\n",
				lhs, pixOffset("src", args[0], args[1], "*4", "*src.Stride"),
				lhs, tmp, lhs,
				lhs, tmp, lhs, lhs, tmp,
				lhs, tmp, lhs, lhs, tmp,
				lhs, tmp, lhs, lhs, tmp,
			)
		case "*image.RGBA":
			fmt.Fprintf(buf, ""+
				"%si := %s\n"+
				"%sr%s := uint32(src.Pix[%si+0]) * 0x101\n"+
				"%sg%s := uint32(src.Pix[%si+1]) * 0x101\n"+
				"%sb%s := uint32(src.Pix[%si+2]) * 0x101\n"+
				"%sa%s := uint32(src.Pix[%si+3]) * 0x101\n",
				lhs, pixOffset("src", args[0], args[1], "*4", "*src.Stride"),
				lhs, tmp, lhs,
				lhs, tmp, lhs,
				lhs, tmp, lhs,
				lhs, tmp, lhs,
			)
		case "*image.YCbCr":
			fmt.Fprintf(buf, ""+
				"%si := %s\n"+
				"%sj := %s\n"+
				"%s\n",
				lhs, pixOffset("src", args[0], args[1], "", "*src.YStride"),
				lhs, cOffset(args[0], args[1], d.sratio),
				ycbcrToRGB(lhs, tmp),
			)
		}

		if dollar == "srcf" {
			switch d.sType {
			default:
				fmt.Fprintf(buf, ""+
					"%sr %s float64(%sru)%s\n"+
					"%sg %s float64(%sgu)%s\n"+
					"%sb %s float64(%sbu)%s\n"+
					"%sa %s float64(%sau)%s\n",
					lhs, eqOp, lhs, extra,
					lhs, eqOp, lhs, extra,
					lhs, eqOp, lhs, extra,
					lhs, eqOp, lhs, extra,
				)
			case "*image.Gray":
				fmt.Fprintf(buf, ""+
					"%sr %s float64(%sru)%s\n",
					lhs, eqOp, lhs, extra,
				)
			case "*image.YCbCr":
				fmt.Fprintf(buf, ""+
					"%sr %s float64(%sru)%s\n"+
					"%sg %s float64(%sgu)%s\n"+
					"%sb %s float64(%sbu)%s\n",
					lhs, eqOp, lhs, extra,
					lhs, eqOp, lhs, extra,
					lhs, eqOp, lhs, extra,
				)
			}
		}

		return strings.TrimSpace(buf.String())

	case "tweakD":
		if d.dType == "*image.RGBA" {
			return "d += dst.Stride"
		}
		return ";"

	case "tweakDx":
		if d.dType == "*image.RGBA" {
			return strings.Replace(prefix, "dx++", "dx, d = dx+1, d+4", 1)
		}
		return prefix

	case "tweakDy":
		if d.dType == "*image.RGBA" {
			return strings.Replace(prefix, "for dy, s", "for _, s", 1)
		}
		return prefix

	case "tweakP":
		switch d.sType {
		case "*image.Gray":
			if strings.HasPrefix(strings.TrimSpace(prefix), "pa * ") {
				return "1,"
			}
			return "pr,"
		case "*image.YCbCr":
			if strings.HasPrefix(strings.TrimSpace(prefix), "pa * ") {
				return "1,"
			}
		}
		return prefix

	case "tweakPr":
		if d.sType == "*image.Gray" {
			return "pr *= s.invTotalWeightFFFF"
		}
		return ";"

	case "tweakVarP":
		switch d.sType {
		case "*image.Gray":
			return strings.Replace(prefix, "var pr, pg, pb, pa", "var pr", 1)
		case "*image.YCbCr":
			return strings.Replace(prefix, "var pr, pg, pb, pa", "var pr, pg, pb", 1)
		}
		return prefix
	}
	return ""
}