all: introduce Outline and Stroke builders

This CL introduces 2 new path builders:
- Outline which takes a PathSpec to be outlined
- Stroke which takes a PathSpec and a stroke style, to stroke a path.

typically, code like this:

  var p clip.Path
  ...
  p.Outline().Add(o)

should be replaced with:

  var p clip.Path
  ...
  clip.Outline{Path: p.End()}.Op().Add(o)

similarly, stroking should be modified from:

  var p clip.Path
  ...
  p.Stroke(width, clip.StrokeStyle{...}).Add(o)

to:

  var p clip.Path
  ...
  clip.Stroke{Path: p.End(), Style: clip.StrokeStyle{Width:...}}.Op().Add(o)

here are tentative 'rf' scripts (see rsc.io/rf for more details):

  ```
  ex {
  	import "gioui.org/op";
  	import "gioui.org/op/clip";

  	var p clip.Path;
  	var o *op.Ops;

  	p.Outline().Add(o) -> clip.Outline{Path:p.End()}.Op().Add(o);
  }

  ex {
  	import "gioui.org/op";
  	import "gioui.org/op/clip";

  	var o *op.Ops;
  	var p clip.Path;
  	var sty clip.StrokeStyle;
  	var width float32;

  	p.Stroke(width, sty).Add(o) ->   \
	    clip.Stroke{                 \
		Path:p.End(),            \
		Style: clip.StrokeStyle{ \
		    Width: width,        \
	    }}.Op().Add(o);
  }
  ```

Signed-off-by: Sebastien Binet <s@sbinet.org>
This commit is contained in:
Sebastien Binet
2020-12-08 14:55:26 +00:00
committed by Elias Naur
parent 7c5bcd3db8
commit be89f8b945
12 changed files with 355 additions and 259 deletions
+132 -132
View File
@@ -68,7 +68,9 @@ func TestPaintArc(t *testing.T) {
p.Arc(f32.Pt(-10, -20), f32.Pt(10, -5), math.Pi)
p.Line(f32.Pt(0, -10))
p.Line(f32.Pt(-50, 0))
p.Outline().Add(o)
clip.Outline{
Path: p.End(),
}.Op().Add(o)
paint.FillShape(o, red, clip.Rect(image.Rect(0, 0, 128, 128)).Op())
}, func(r result) {
@@ -87,7 +89,9 @@ func TestPaintAbsolute(t *testing.T) {
p.MoveTo(f32.Pt(20, 20))
p.LineTo(f32.Pt(80, 20))
p.QuadTo(f32.Pt(80, 80), f32.Pt(20, 80))
p.Outline().Add(o)
clip.Outline{
Path: p.End(),
}.Op().Add(o)
paint.FillShape(o, red, clip.Rect(image.Rect(0, 0, 128, 128)).Op())
}, func(r result) {
@@ -125,23 +129,15 @@ func TestPaintClippedTexture(t *testing.T) {
func TestStrokedPathBevelFlat(t *testing.T) {
run(t, func(o *op.Ops) {
const width = 2.5
sty := clip.StrokeStyle{
Cap: clip.FlatCap,
Join: clip.BevelJoin,
}
p := new(clip.Path)
p.Begin(o)
p.Move(f32.Pt(10, 50))
p.Line(f32.Pt(10, 0))
p.Arc(f32.Pt(10, 0), f32.Pt(20, 0), math.Pi)
p.Line(f32.Pt(10, 0))
p.Line(f32.Pt(10, 10))
p.Arc(f32.Pt(0, 30), f32.Pt(0, 30), 2*math.Pi)
p.Line(f32.Pt(-20, 0))
p.Quad(f32.Pt(-10, -10), f32.Pt(-30, 30))
p.Stroke(width, sty).Add(o)
p := newStrokedPath(o)
clip.Stroke{
Path: p,
Style: clip.StrokeStyle{
Width: 2.5,
Cap: clip.FlatCap,
Join: clip.BevelJoin,
},
}.Op().Add(o)
paint.Fill(o, red)
}, func(r result) {
@@ -152,23 +148,15 @@ func TestStrokedPathBevelFlat(t *testing.T) {
func TestStrokedPathBevelRound(t *testing.T) {
run(t, func(o *op.Ops) {
const width = 2.5
sty := clip.StrokeStyle{
Cap: clip.RoundCap,
Join: clip.BevelJoin,
}
p := new(clip.Path)
p.Begin(o)
p.Move(f32.Pt(10, 50))
p.Line(f32.Pt(10, 0))
p.Arc(f32.Pt(10, 0), f32.Pt(20, 0), math.Pi)
p.Line(f32.Pt(10, 0))
p.Line(f32.Pt(10, 10))
p.Arc(f32.Pt(0, 30), f32.Pt(0, 30), 2*math.Pi)
p.Line(f32.Pt(-20, 0))
p.Quad(f32.Pt(-10, -10), f32.Pt(-30, 30))
p.Stroke(width, sty).Add(o)
p := newStrokedPath(o)
clip.Stroke{
Path: p,
Style: clip.StrokeStyle{
Width: 2.5,
Cap: clip.RoundCap,
Join: clip.BevelJoin,
},
}.Op().Add(o)
paint.Fill(o, red)
}, func(r result) {
@@ -179,23 +167,15 @@ func TestStrokedPathBevelRound(t *testing.T) {
func TestStrokedPathBevelSquare(t *testing.T) {
run(t, func(o *op.Ops) {
const width = 2.5
sty := clip.StrokeStyle{
Cap: clip.SquareCap,
Join: clip.BevelJoin,
}
p := new(clip.Path)
p.Begin(o)
p.Move(f32.Pt(10, 50))
p.Line(f32.Pt(10, 0))
p.Arc(f32.Pt(10, 0), f32.Pt(20, 0), math.Pi)
p.Line(f32.Pt(10, 0))
p.Line(f32.Pt(10, 10))
p.Arc(f32.Pt(0, 30), f32.Pt(0, 30), 2*math.Pi)
p.Line(f32.Pt(-20, 0))
p.Quad(f32.Pt(-10, -10), f32.Pt(-30, 30))
p.Stroke(width, sty).Add(o)
p := newStrokedPath(o)
clip.Stroke{
Path: p,
Style: clip.StrokeStyle{
Width: 2.5,
Cap: clip.SquareCap,
Join: clip.BevelJoin,
},
}.Op().Add(o)
paint.Fill(o, red)
}, func(r result) {
@@ -206,23 +186,15 @@ func TestStrokedPathBevelSquare(t *testing.T) {
func TestStrokedPathRoundRound(t *testing.T) {
run(t, func(o *op.Ops) {
const width = 2.5
sty := clip.StrokeStyle{
Cap: clip.RoundCap,
Join: clip.RoundJoin,
}
p := new(clip.Path)
p.Begin(o)
p.Move(f32.Pt(10, 50))
p.Line(f32.Pt(10, 0))
p.Arc(f32.Pt(10, 0), f32.Pt(20, 0), math.Pi)
p.Line(f32.Pt(10, 0))
p.Line(f32.Pt(10, 10))
p.Arc(f32.Pt(0, 30), f32.Pt(0, 30), 2*math.Pi)
p.Line(f32.Pt(-20, 0))
p.Quad(f32.Pt(-10, -10), f32.Pt(-30, 30))
p.Stroke(width, sty).Add(o)
p := newStrokedPath(o)
clip.Stroke{
Path: p,
Style: clip.StrokeStyle{
Width: 2.5,
Cap: clip.RoundCap,
Join: clip.RoundJoin,
},
}.Op().Add(o)
paint.Fill(o, red)
}, func(r result) {
@@ -233,40 +205,32 @@ func TestStrokedPathRoundRound(t *testing.T) {
func TestStrokedPathFlatMiter(t *testing.T) {
run(t, func(o *op.Ops) {
const width = 10
sty := clip.StrokeStyle{
Cap: clip.FlatCap,
Join: clip.BevelJoin,
Miter: 5,
}
beg := f32.Pt(40, 10)
{
p := new(clip.Path)
p.Begin(o)
p.Move(beg)
p.Line(f32.Pt(50, 0))
p.Line(f32.Pt(-50, 50))
p.Line(f32.Pt(50, 0))
p.Quad(f32.Pt(-50, 20), f32.Pt(-50, 50))
p.Line(f32.Pt(50, 0))
p.Stroke(width, sty).Add(o)
stk := op.Push(o)
p := newZigZagPath(o)
clip.Stroke{
Path: p,
Style: clip.StrokeStyle{
Width: 10,
Cap: clip.FlatCap,
Join: clip.BevelJoin,
Miter: 5,
},
}.Op().Add(o)
paint.Fill(o, red)
stk.Pop()
}
{
p := new(clip.Path)
p.Begin(o)
p.Move(beg)
p.Line(f32.Pt(50, 0))
p.Line(f32.Pt(-50, 50))
p.Line(f32.Pt(50, 0))
p.Quad(f32.Pt(-50, 20), f32.Pt(-50, 50))
p.Line(f32.Pt(50, 0))
p.Stroke(2, clip.StrokeStyle{}).Add(o)
stk := op.Push(o)
p := newZigZagPath(o)
clip.Stroke{
Path: p,
Style: clip.StrokeStyle{
Width: 2,
},
}.Op().Add(o)
paint.Fill(o, black)
stk.Pop()
}
}, func(r result) {
@@ -278,40 +242,32 @@ func TestStrokedPathFlatMiter(t *testing.T) {
func TestStrokedPathFlatMiterInf(t *testing.T) {
run(t, func(o *op.Ops) {
const width = 10
sty := clip.StrokeStyle{
Cap: clip.FlatCap,
Join: clip.BevelJoin,
Miter: float32(math.Inf(+1)),
}
beg := f32.Pt(40, 10)
{
p := new(clip.Path)
p.Begin(o)
p.Move(beg)
p.Line(f32.Pt(50, 0))
p.Line(f32.Pt(-50, 50))
p.Line(f32.Pt(50, 0))
p.Quad(f32.Pt(-50, 20), f32.Pt(-50, 50))
p.Line(f32.Pt(50, 0))
p.Stroke(width, sty).Add(o)
stk := op.Push(o)
p := newZigZagPath(o)
clip.Stroke{
Path: p,
Style: clip.StrokeStyle{
Width: 10,
Cap: clip.FlatCap,
Join: clip.BevelJoin,
Miter: float32(math.Inf(+1)),
},
}.Op().Add(o)
paint.Fill(o, red)
stk.Pop()
}
{
p := new(clip.Path)
p.Begin(o)
p.Move(beg)
p.Line(f32.Pt(50, 0))
p.Line(f32.Pt(-50, 50))
p.Line(f32.Pt(50, 0))
p.Quad(f32.Pt(-50, 20), f32.Pt(-50, 50))
p.Line(f32.Pt(50, 0))
p.Stroke(2, clip.StrokeStyle{}).Add(o)
stk := op.Push(o)
p := newZigZagPath(o)
clip.Stroke{
Path: p,
Style: clip.StrokeStyle{
Width: 2,
},
}.Op().Add(o)
paint.Fill(o, black)
stk.Pop()
}
}, func(r result) {
@@ -323,26 +279,35 @@ func TestStrokedPathFlatMiterInf(t *testing.T) {
func TestStrokedPathZeroWidth(t *testing.T) {
run(t, func(o *op.Ops) {
const width = 2
var sty clip.StrokeStyle
{
stk := op.Push(o)
p := new(clip.Path)
p.Begin(o)
p.Move(f32.Pt(10, 50))
p.Line(f32.Pt(50, 0))
p.Stroke(width, sty).Add(o)
clip.Stroke{
Path: p.End(),
Style: clip.StrokeStyle{
Width: 2,
},
}.Op().Add(o)
paint.Fill(o, black)
stk.Pop()
}
{
stk := op.Push(o)
p := new(clip.Path)
p.Begin(o)
p.Move(f32.Pt(10, 50))
p.Line(f32.Pt(30, 0))
p.Stroke(0, sty).Add(o) // width=0, disable stroke
clip.Stroke{
Path: p.End(),
}.Op().Add(o) // width=0, disable stroke
paint.Fill(o, red)
stk.Pop()
}
}, func(r result) {
@@ -352,3 +317,38 @@ func TestStrokedPathZeroWidth(t *testing.T) {
r.expect(65, 50, colornames.White)
})
}
func newStrokedPath(o *op.Ops) clip.PathSpec {
p := new(clip.Path)
p.Begin(o)
p.Move(f32.Pt(10, 50))
p.Line(f32.Pt(10, 0))
p.Arc(f32.Pt(10, 0), f32.Pt(20, 0), math.Pi)
p.Line(f32.Pt(10, 0))
p.Line(f32.Pt(10, 10))
p.Arc(f32.Pt(0, 30), f32.Pt(0, 30), 2*math.Pi)
p.Line(f32.Pt(-20, 0))
p.Quad(f32.Pt(-10, -10), f32.Pt(-30, 30))
return p.End()
}
func newZigZagPath(o *op.Ops) clip.PathSpec {
p := new(clip.Path)
p.Begin(o)
p.Move(f32.Pt(40, 10))
p.Line(f32.Pt(50, 0))
p.Line(f32.Pt(-50, 50))
p.Line(f32.Pt(50, 0))
p.Quad(f32.Pt(-50, 20), f32.Pt(-50, 50))
p.Line(f32.Pt(50, 0))
return p.End()
}
func newEllipsePath(o *op.Ops) clip.PathSpec {
p := new(clip.Path)
p.Begin(o)
p.Move(f32.Pt(0, 65))
p.Line(f32.Pt(20, 0))
p.Arc(f32.Pt(20, 0), f32.Pt(70, 0), 2*math.Pi)
return p.End()
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

+6 -2
View File
@@ -71,7 +71,10 @@ func TestRepeatedPaintsZ(t *testing.T) {
builder.Line(f32.Pt(0, 10))
builder.Line(f32.Pt(-10, 0))
builder.Line(f32.Pt(0, -10))
builder.Outline().Add(o)
p := builder.End()
clip.Outline{
Path: p,
}.Op().Add(o)
paint.Fill(o, red)
}, func(r result) {
r.expect(5, 5, colornames.Red)
@@ -109,7 +112,8 @@ func constSqPath() op.CallOp {
builder.Line(f32.Pt(0, 10))
builder.Line(f32.Pt(-10, 0))
builder.Line(f32.Pt(0, -10))
builder.Outline().Add(innerOps)
p := builder.End()
clip.Outline{Path: p}.Op().Add(innerOps)
return m.Stop()
}