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:
Pierre Curto
2021-12-19 17:09:54 +01:00
committed by Elias Naur
parent 0117de71d3
commit 11bb86166a
10 changed files with 123 additions and 28 deletions
+13 -9
View File
@@ -90,9 +90,6 @@ func (s Stack) Pop() {
type PathSpec struct {
spec op.CallOp
// open is true if any path contour is not closed. A closed contour starts
// and ends in the same point.
open bool
// hasSegments tracks whether there are any segments in the path.
hasSegments bool
bounds image.Rectangle
@@ -109,7 +106,6 @@ type PathSpec struct {
// data is stored directly in the Ops list supplied to Begin.
type Path struct {
ops *ops.Ops
open bool
contour int
pen f32.Point
macro op.MacroOp
@@ -136,10 +132,10 @@ func (p *Path) Begin(o *op.Ops) {
// End returns a PathSpec ready to use in clipping operations.
func (p *Path) End() PathSpec {
p.gap()
c := p.macro.Stop()
return PathSpec{
spec: c,
open: p.open || p.pen != p.start,
hasSegments: p.hasSegments,
bounds: boundRectF(p.bounds),
hash: p.hash.Sum64(),
@@ -157,12 +153,23 @@ func (p *Path) MoveTo(to f32.Point) {
if p.pen == to {
return
}
p.open = p.open || p.pen != p.start
p.gap()
p.end()
p.pen = to
p.start = to
}
func (p *Path) gap() {
if p.pen != p.start {
// A closed contour starts and ends in the same point.
// This move creates a gap in the contour, register it.
data := ops.Write(p.ops, scene.CommandSize+4)
bo := binary.LittleEndian
bo.PutUint32(data[0:], uint32(p.contour))
p.cmd(data[4:], scene.Gap(p.pen, p.start))
}
}
// end completes the current contour.
func (p *Path) end() {
p.contour++
@@ -331,9 +338,6 @@ type Outline struct {
// Op returns a clip operation representing the outline.
func (o Outline) Op() Op {
if o.Path.open {
panic("not all path contours are closed")
}
return Op{
path: o.Path,
outline: true,
-11
View File
@@ -15,17 +15,6 @@ import (
)
func TestPathOutline(t *testing.T) {
t.Run("unclosed path", func(t *testing.T) {
defer func() {
if err := recover(); err == nil {
t.Error("Outline of an open path didn't panic")
}
}()
var p clip.Path
p.Begin(new(op.Ops))
p.Line(f32.Pt(10, 10))
clip.Outline{Path: p.End()}.Op()
})
t.Run("closed path", func(t *testing.T) {
defer func() {
if err := recover(); err != nil {