op/clip: don't accept open Paths for Outline

Outline represents a clipping operations that clips all drawing outside
a closed path. Before this change, paths not closed we're patched up by
adding an implicit line from the endpoint to the beginning.

These fixups are inefficient for a rare case, but acceptable because the
old renderer post-processes all paths anyway. However, the new compute
renderer don't need post-processing in most cases, making fixups too
expensive.

Given that clipping to an open path is fundamentally undefined and that
implicit fixup with a closing line segment is merely a way to force the
clip to be well-defined, this change adds a panic to Outline for Paths
that are not closed.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-03-11 08:09:07 +01:00
parent 4b377aa896
commit 884e7d27e2
4 changed files with 39 additions and 28 deletions
-22
View File
@@ -1385,37 +1385,15 @@ func (d *drawOps) buildVerts(aux []byte, tr f32.Affine2D, outline bool, stroke c
case outline:
// Outline path.
first := true
var firstPt, lastPt f32.Point
for len(aux) >= ops.QuadSize+4 {
d.qs.contour = bo.Uint32(aux)
quad := ops.DecodeQuad(aux[4:])
quad = quad.Transform(tr)
if first {
first = false
firstPt = quad.From
lastPt = quad.From
}
if quad.From != lastPt {
if lastPt != firstPt {
// Close outline before starting a new.
mid := firstPt.Add(lastPt).Mul(.5)
d.qs.splitAndEncode(ops.Quad{From: lastPt, To: firstPt, Ctrl: mid})
}
firstPt = quad.From
}
lastPt = quad.To
d.qs.splitAndEncode(quad)
aux = aux[ops.QuadSize+4:]
}
// Close last outline if necessary.
if !first && lastPt != firstPt {
mid := firstPt.Add(lastPt).Mul(.5)
d.qs.splitAndEncode(ops.Quad{From: lastPt, To: firstPt, Ctrl: mid})
}
}
fillMaxY(d.vertCache[startLength:])
+2
View File
@@ -91,6 +91,7 @@ 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.Close()
clip.Outline{
Path: p.End(),
}.Op().Add(o)
@@ -112,6 +113,7 @@ 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.Close()
clip.Outline{
Path: p.End(),
}.Op().Add(o)