// Copyright 2010 The Freetype-Go Authors. All rights reserved.
// Use of this source code is governed by your choice of either the
// FreeType License or the GNU General Public License version 2 (or
// any later version), both of which can be found in the LICENSE file.

package raster

import (
	
	
	
	
)

// A Span is a horizontal segment of pixels with constant alpha. X0 is an
// inclusive bound and X1 is exclusive, the same as for slices. A fully opaque
// Span has Alpha == 0xffff.
type Span struct {
	Y, X0, X1 int
	Alpha     uint32
}

// A Painter knows how to paint a batch of Spans. Rasterization may involve
// Painting multiple batches, and done will be true for the final batch. The
// Spans' Y values are monotonically increasing during a rasterization. Paint
// may use all of ss as scratch space during the call.
type Painter interface {
	Paint(ss []Span, done bool)
}

// The PainterFunc type adapts an ordinary function to the Painter interface.
type PainterFunc func(ss []Span, done bool)

// Paint just delegates the call to f.
func ( PainterFunc) ( []Span,  bool) { (, ) }

// An AlphaOverPainter is a Painter that paints Spans onto a *image.Alpha using
// the Over Porter-Duff composition operator.
type AlphaOverPainter struct {
	Image *image.Alpha
}

// Paint satisfies the Painter interface.
func ( AlphaOverPainter) ( []Span,  bool) {
	 := .Image.Bounds()
	for ,  := range  {
		if .Y < .Min.Y {
			continue
		}
		if .Y >= .Max.Y {
			return
		}
		if .X0 < .Min.X {
			.X0 = .Min.X
		}
		if .X1 > .Max.X {
			.X1 = .Max.X
		}
		if .X0 >= .X1 {
			continue
		}
		 := (.Y-.Image.Rect.Min.Y)*.Image.Stride - .Image.Rect.Min.X
		 := .Image.Pix[+.X0 : +.X1]
		 := int(.Alpha >> 8)
		for ,  := range  {
			 := int()
			[] = uint8((*255 + (255-)*) / 255)
		}
	}
}

// NewAlphaOverPainter creates a new AlphaOverPainter for the given image.
func ( *image.Alpha) AlphaOverPainter {
	return AlphaOverPainter{}
}

// An AlphaSrcPainter is a Painter that paints Spans onto a *image.Alpha using
// the Src Porter-Duff composition operator.
type AlphaSrcPainter struct {
	Image *image.Alpha
}

// Paint satisfies the Painter interface.
func ( AlphaSrcPainter) ( []Span,  bool) {
	 := .Image.Bounds()
	for ,  := range  {
		if .Y < .Min.Y {
			continue
		}
		if .Y >= .Max.Y {
			return
		}
		if .X0 < .Min.X {
			.X0 = .Min.X
		}
		if .X1 > .Max.X {
			.X1 = .Max.X
		}
		if .X0 >= .X1 {
			continue
		}
		 := (.Y-.Image.Rect.Min.Y)*.Image.Stride - .Image.Rect.Min.X
		 := .Image.Pix[+.X0 : +.X1]
		 := uint8(.Alpha >> 8)
		for  := range  {
			[] = 
		}
	}
}

// NewAlphaSrcPainter creates a new AlphaSrcPainter for the given image.
func ( *image.Alpha) AlphaSrcPainter {
	return AlphaSrcPainter{}
}

// An RGBAPainter is a Painter that paints Spans onto a *image.RGBA.
type RGBAPainter struct {
	// Image is the image to compose onto.
	Image *image.RGBA
	// Op is the Porter-Duff composition operator.
	Op draw.Op
	// cr, cg, cb and ca are the 16-bit color to paint the spans.
	cr, cg, cb, ca uint32
}

// Paint satisfies the Painter interface.
func ( *RGBAPainter) ( []Span,  bool) {
	 := .Image.Bounds()
	for ,  := range  {
		if .Y < .Min.Y {
			continue
		}
		if .Y >= .Max.Y {
			return
		}
		if .X0 < .Min.X {
			.X0 = .Min.X
		}
		if .X1 > .Max.X {
			.X1 = .Max.X
		}
		if .X0 >= .X1 {
			continue
		}
		// This code mimics drawGlyphOver in $GOROOT/src/image/draw/draw.go.
		 := .Alpha
		const  = 1<<16 - 1
		 := (.Y-.Image.Rect.Min.Y)*.Image.Stride + (.X0-.Image.Rect.Min.X)*4
		 :=  + (.X1-.X0)*4
		if .Op == draw.Over {
			for  := ;  < ;  += 4 {
				 := uint32(.Image.Pix[+0])
				 := uint32(.Image.Pix[+1])
				 := uint32(.Image.Pix[+2])
				 := uint32(.Image.Pix[+3])
				 := ( - (.ca *  / )) * 0x101
				.Image.Pix[+0] = uint8((* + .cr*) /  >> 8)
				.Image.Pix[+1] = uint8((* + .cg*) /  >> 8)
				.Image.Pix[+2] = uint8((* + .cb*) /  >> 8)
				.Image.Pix[+3] = uint8((* + .ca*) /  >> 8)
			}
		} else {
			for  := ;  < ;  += 4 {
				.Image.Pix[+0] = uint8(.cr *  /  >> 8)
				.Image.Pix[+1] = uint8(.cg *  /  >> 8)
				.Image.Pix[+2] = uint8(.cb *  /  >> 8)
				.Image.Pix[+3] = uint8(.ca *  /  >> 8)
			}
		}
	}
}

// SetColor sets the color to paint the spans.
func ( *RGBAPainter) ( color.Color) {
	.cr, .cg, .cb, .ca = .RGBA()
}

// NewRGBAPainter creates a new RGBAPainter for the given image.
func ( *image.RGBA) *RGBAPainter {
	return &RGBAPainter{Image: }
}

// A MonochromePainter wraps another Painter, quantizing each Span's alpha to
// be either fully opaque or fully transparent.
type MonochromePainter struct {
	Painter   Painter
	y, x0, x1 int
}

// Paint delegates to the wrapped Painter after quantizing each Span's alpha
// value and merging adjacent fully opaque Spans.
func ( *MonochromePainter) ( []Span,  bool) {
	// We compact the ss slice, discarding any Spans whose alpha quantizes to zero.
	 := 0
	for ,  := range  {
		if .Alpha >= 0x8000 {
			if .y == .Y && .x1 == .X0 {
				.x1 = .X1
			} else {
				[] = Span{.y, .x0, .x1, 1<<16 - 1}
				++
				.y, .x0, .x1 = .Y, .X0, .X1
			}
		}
	}
	if  {
		// Flush the accumulated Span.
		 := Span{.y, .x0, .x1, 1<<16 - 1}
		if  < len() {
			[] = 
			++
			.Painter.Paint([:], true)
		} else if  == len() {
			.Painter.Paint(, false)
			if cap() > 0 {
				 = [:1]
			} else {
				 = make([]Span, 1)
			}
			[0] = 
			.Painter.Paint(, true)
		} else {
			panic("unreachable")
		}
		// Reset the accumulator, so that this Painter can be re-used.
		.y, .x0, .x1 = 0, 0, 0
	} else {
		.Painter.Paint([:], false)
	}
}

// NewMonochromePainter creates a new MonochromePainter that wraps the given
// Painter.
func ( Painter) *MonochromePainter {
	return &MonochromePainter{Painter: }
}

// A GammaCorrectionPainter wraps another Painter, performing gamma-correction
// on each Span's alpha value.
type GammaCorrectionPainter struct {
	// Painter is the wrapped Painter.
	Painter Painter
	// a is the precomputed alpha values for linear interpolation, with fully
	// opaque == 0xffff.
	a [256]uint16
	// gammaIsOne is whether gamma correction is a no-op.
	gammaIsOne bool
}

// Paint delegates to the wrapped Painter after performing gamma-correction on
// each Span.
func ( *GammaCorrectionPainter) ( []Span,  bool) {
	if !.gammaIsOne {
		const  = 0x101
		for ,  := range  {
			if .Alpha == 0 || .Alpha == 0xffff {
				continue
			}
			,  := .Alpha/, .Alpha%
			// The resultant alpha is a linear interpolation of g.a[p] and g.a[p+1].
			 := uint32(.a[])*(-) + uint32(.a[+1])*
			[].Alpha = ( + /2) / 
		}
	}
	.Painter.Paint(, )
}

// SetGamma sets the gamma value.
func ( *GammaCorrectionPainter) ( float64) {
	.gammaIsOne =  == 1
	if .gammaIsOne {
		return
	}
	for  := 0;  < 256; ++ {
		 := float64() / 0xff
		 = math.Pow(, )
		.a[] = uint16(0xffff * )
	}
}

// NewGammaCorrectionPainter creates a new GammaCorrectionPainter that wraps
// the given Painter.
func ( Painter,  float64) *GammaCorrectionPainter {
	 := &GammaCorrectionPainter{Painter: }
	.SetGamma()
	return 
}