forked from joejulian/gio
op/clip: automatically close Path in Outlines
Unclosed path segments in Path will be automatically closed by a line. Fixes: https://todo.sr.ht/~eliasnaur/gio/320 Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
+11
-4
@@ -1186,12 +1186,19 @@ func min(p1, p2 f32.Point) f32.Point {
|
||||
return p
|
||||
}
|
||||
|
||||
func (enc *encoder) encodePath(verts []byte) {
|
||||
for len(verts) >= scene.CommandSize+4 {
|
||||
func (enc *encoder) encodePath(verts []byte, fillMode int) {
|
||||
for ; len(verts) >= scene.CommandSize+4; verts = verts[scene.CommandSize+4:] {
|
||||
cmd := ops.DecodeCommand(verts[4:])
|
||||
if cmd.Op() == scene.OpGap {
|
||||
if fillMode != scene.FillModeNonzero {
|
||||
// Skip gaps in strokes.
|
||||
continue
|
||||
}
|
||||
// Replace them by a straight line in outlines.
|
||||
cmd = scene.Line(scene.DecodeGap(cmd))
|
||||
}
|
||||
enc.scene = append(enc.scene, cmd)
|
||||
enc.npathseg++
|
||||
verts = verts[scene.CommandSize+4:]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2109,7 +2116,7 @@ func encodeOp(viewport image.Point, absOff image.Point, enc *encoder, texOps []t
|
||||
if len(cl.path) == 0 {
|
||||
enc.rect(cl.state.bounds)
|
||||
} else {
|
||||
enc.encodePath(cl.path)
|
||||
enc.encodePath(cl.path, fillMode)
|
||||
}
|
||||
if i != 0 {
|
||||
enc.beginClip(cl.union.Add(absOfff))
|
||||
|
||||
@@ -1344,6 +1344,12 @@ func decodeToOutlineQuads(qs *quadSplitter, tr f32.Affine2D, pathData []byte) {
|
||||
q.Ctrl = q.From.Add(q.To).Mul(.5)
|
||||
q = q.Transform(tr)
|
||||
qs.splitAndEncode(q)
|
||||
case scene.OpGap:
|
||||
var q stroke.QuadSegment
|
||||
q.From, q.To = scene.DecodeGap(cmd)
|
||||
q.Ctrl = q.From.Add(q.To).Mul(.5)
|
||||
q = q.Transform(tr)
|
||||
qs.splitAndEncode(q)
|
||||
case scene.OpQuad:
|
||||
var q stroke.QuadSegment
|
||||
q.From, q.Ctrl, q.To = scene.DecodeQuad(cmd)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 408 B |
Binary file not shown.
|
After Width: | Height: | Size: 488 B |
@@ -357,6 +357,60 @@ func TestImageRGBA(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestGapsInPath(t *testing.T) {
|
||||
ops := new(op.Ops)
|
||||
var p clip.Path
|
||||
p.Begin(ops)
|
||||
// Unclosed square 1
|
||||
p.MoveTo(f32.Point{X: 10})
|
||||
p.LineTo(f32.Point{X: 40})
|
||||
p.LineTo(f32.Point{X: 40, Y: 30})
|
||||
p.LineTo(f32.Point{X: 10, Y: 30})
|
||||
|
||||
// Unclosed square 2
|
||||
p.MoveTo(f32.Point{X: 50})
|
||||
p.LineTo(f32.Point{X: 80})
|
||||
p.LineTo(f32.Point{X: 80, Y: 30})
|
||||
p.LineTo(f32.Point{X: 50, Y: 30})
|
||||
|
||||
spec := p.End()
|
||||
|
||||
t.Run("Stroke", func(t *testing.T) {
|
||||
run(t,
|
||||
func(ops *op.Ops) {
|
||||
stack := clip.Stroke{
|
||||
Path: spec,
|
||||
Width: 2,
|
||||
}.Op().Push(ops)
|
||||
paint.ColorOp{Color: color.NRGBA{R: 255, A: 255}}.Add(ops)
|
||||
paint.PaintOp{}.Add(ops)
|
||||
stack.Pop()
|
||||
},
|
||||
func(r result) {
|
||||
r.expect(10, 20, color.RGBA{})
|
||||
r.expect(50, 20, color.RGBA{})
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("Outline", func(t *testing.T) {
|
||||
run(t,
|
||||
func(ops *op.Ops) {
|
||||
stack := clip.Outline{Path: spec}.Op().Push(ops)
|
||||
paint.ColorOp{Color: color.NRGBA{R: 255, A: 255}}.Add(ops)
|
||||
paint.PaintOp{}.Add(ops)
|
||||
stack.Pop()
|
||||
},
|
||||
func(r result) {
|
||||
r.expect(10, 20, colornames.Red)
|
||||
r.expect(20, 20, colornames.Red)
|
||||
r.expect(50, 20, colornames.Red)
|
||||
r.expect(60, 20, colornames.Red)
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// lerp calculates linear interpolation with color b and p.
|
||||
func lerp(a, b f32color.RGBA, p float32) f32color.RGBA {
|
||||
return f32color.RGBA{
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
@@ -143,11 +144,20 @@ func multiRun(t *testing.T, frames ...frameT) {
|
||||
|
||||
func verifyRef(t *testing.T, img *image.RGBA, frame int) (ok bool) {
|
||||
// ensure identical to ref data
|
||||
path := filepath.Join("refs", t.Name()+".png")
|
||||
if frame != 0 {
|
||||
path = filepath.Join("refs", t.Name()+"_"+strconv.Itoa(frame)+".png")
|
||||
var path string
|
||||
if frame == 0 {
|
||||
path = t.Name()
|
||||
} else {
|
||||
path = t.Name() + "_" + strconv.Itoa(frame)
|
||||
}
|
||||
path = filepath.Join("refs", path+".png")
|
||||
if *dumpImages {
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0766); err != nil {
|
||||
if !os.IsExist(err) {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
saveImage(t, path, img)
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user