greatly improve clipping performance

This commit is contained in:
Michael Fogleman 2016-12-14 17:06:16 -05:00
parent 62c697d628
commit bc0c0e9e67
3 changed files with 16 additions and 34 deletions

View File

@ -173,8 +173,6 @@ ClipPreserve()
ResetClip() ResetClip()
``` ```
Note: As currently implemented, clipping isn't very fast, but it works.
## Helper Functions ## Helper Functions
Sometimes you just don't want to write these yourself. Sometimes you just don't want to write these yourself.

View File

@ -402,17 +402,8 @@ func (dc *Context) fill(painter raster.Painter) {
// line cap, line join and dash settings. The path is preserved after this // line cap, line join and dash settings. The path is preserved after this
// operation. // operation.
func (dc *Context) StrokePreserve() { func (dc *Context) StrokePreserve() {
if dc.mask == nil { painter := newPatternPainter(dc.im, dc.mask, dc.strokePattern)
painter := newPatternPainter(dc.im)
painter.setPattern(dc.strokePattern)
dc.stroke(painter) dc.stroke(painter)
} else {
im := image.NewRGBA(image.Rect(0, 0, dc.width, dc.height))
painter := newPatternPainter(im)
painter.setPattern(dc.strokePattern)
dc.stroke(painter)
draw.DrawMask(dc.im, dc.im.Bounds(), im, image.ZP, dc.mask, image.ZP, draw.Over)
}
} }
// Stroke strokes the current path with the current color, line width, // Stroke strokes the current path with the current color, line width,
@ -426,17 +417,8 @@ func (dc *Context) Stroke() {
// FillPreserve fills the current path with the current color. Open subpaths // FillPreserve fills the current path with the current color. Open subpaths
// are implicity closed. The path is preserved after this operation. // are implicity closed. The path is preserved after this operation.
func (dc *Context) FillPreserve() { func (dc *Context) FillPreserve() {
if dc.mask == nil { painter := newPatternPainter(dc.im, dc.mask, dc.fillPattern)
painter := newPatternPainter(dc.im)
painter.setPattern(dc.fillPattern)
dc.fill(painter) dc.fill(painter)
} else {
im := image.NewRGBA(image.Rect(0, 0, dc.width, dc.height))
painter := newPatternPainter(im)
painter.setPattern(dc.fillPattern)
dc.fill(painter)
draw.DrawMask(dc.im, dc.im.Bounds(), im, image.ZP, dc.mask, image.ZP, draw.Over)
}
} }
// Fill fills the current path with the current color. Open subpaths // Fill fills the current path with the current color. Open subpaths

View File

@ -66,6 +66,7 @@ func NewSurfacePattern(im image.Image, op RepeatOp) Pattern {
type patternPainter struct { type patternPainter struct {
im *image.RGBA im *image.RGBA
mask *image.Alpha
p Pattern p Pattern
} }
@ -88,15 +89,20 @@ func (r *patternPainter) Paint(ss []raster.Span, done bool) {
if s.X0 >= s.X1 { if s.X0 >= s.X1 {
continue continue
} }
ma := s.Alpha
const m = 1<<16 - 1 const m = 1<<16 - 1
y := s.Y - r.im.Rect.Min.Y y := s.Y - r.im.Rect.Min.Y
x0 := s.X0 - r.im.Rect.Min.X x0 := s.X0 - r.im.Rect.Min.X
// x1 := x0 + s.X1 - s.X0
// RGBAPainter.Paint() in $GOPATH/src/github.com/golang/freetype/raster/paint.go // RGBAPainter.Paint() in $GOPATH/src/github.com/golang/freetype/raster/paint.go
i0 := (s.Y-r.im.Rect.Min.Y)*r.im.Stride + (s.X0-r.im.Rect.Min.X)*4 i0 := (s.Y-r.im.Rect.Min.Y)*r.im.Stride + (s.X0-r.im.Rect.Min.X)*4
i1 := i0 + (s.X1-s.X0)*4 i1 := i0 + (s.X1-s.X0)*4
for i, x := i0, x0; i < i1; i, x = i+4, x+1 { for i, x := i0, x0; i < i1; i, x = i+4, x+1 {
ma := s.Alpha
if r.mask != nil {
ma = ma * uint32(r.mask.AlphaAt(x, y).A) / 255
if ma == 0 {
continue
}
}
c := r.p.ColorAt(x, y) c := r.p.ColorAt(x, y)
cr, cg, cb, ca := c.RGBA() cr, cg, cb, ca := c.RGBA()
dr := uint32(r.im.Pix[i+0]) dr := uint32(r.im.Pix[i+0])
@ -112,10 +118,6 @@ func (r *patternPainter) Paint(ss []raster.Span, done bool) {
} }
} }
func (r *patternPainter) setPattern(pattern Pattern) { func newPatternPainter(im *image.RGBA, mask *image.Alpha, p Pattern) *patternPainter {
r.p = pattern return &patternPainter{im, mask, p}
}
func newPatternPainter(im *image.RGBA) *patternPainter {
return &patternPainter{im: im}
} }