op/clip: split clip operations into its own package

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-11-09 19:05:03 +01:00
parent 560cf6054c
commit e864ac3fc3
14 changed files with 72 additions and 53 deletions
+1 -1
View File
@@ -119,7 +119,7 @@ type material struct {
uvOffset f32.Point uvOffset f32.Point
} }
// clipOp is the shadow of paint.ClipOp. // clipOp is the shadow of clip.Op.
type clipOp struct { type clipOp struct {
bounds f32.Rectangle bounds f32.Rectangle
} }
+4 -4
View File
@@ -11,7 +11,7 @@ import (
"gioui.org/f32" "gioui.org/f32"
"gioui.org/op" "gioui.org/op"
"gioui.org/op/paint" "gioui.org/op/clip"
"gioui.org/text" "gioui.org/text"
"golang.org/x/image/font" "golang.org/x/image/font"
"golang.org/x/image/font/sfnt" "golang.org/x/image/font/sfnt"
@@ -43,7 +43,7 @@ func (f *Font) Layout(ppem fixed.Int26_6, str string, opts text.LayoutOptions) *
return layoutText(&f.buf, ppem, str, &opentype{Font: f.font, Hinting: font.HintingFull}, opts) return layoutText(&f.buf, ppem, str, &opentype{Font: f.font, Hinting: font.HintingFull}, opts)
} }
func (f *Font) Shape(ppem fixed.Int26_6, str text.String) paint.ClipOp { func (f *Font) Shape(ppem fixed.Int26_6, str text.String) clip.Op {
return textPath(&f.buf, ppem, &opentype{Font: f.font, Hinting: font.HintingFull}, str) return textPath(&f.buf, ppem, &opentype{Font: f.font, Hinting: font.HintingFull}, str)
} }
@@ -136,9 +136,9 @@ func layoutText(buf *sfnt.Buffer, ppem fixed.Int26_6, str string, f *opentype, o
return &text.Layout{Lines: lines} return &text.Layout{Lines: lines}
} }
func textPath(buf *sfnt.Buffer, ppem fixed.Int26_6, f *opentype, str text.String) paint.ClipOp { func textPath(buf *sfnt.Buffer, ppem fixed.Int26_6, f *opentype, str text.String) clip.Op {
var lastPos f32.Point var lastPos f32.Point
var builder paint.Path var builder clip.Path
ops := new(op.Ops) ops := new(op.Ops)
var x fixed.Int26_6 var x fixed.Int26_6
var advIdx int var advIdx int
+2 -2
View File
@@ -8,7 +8,7 @@ import (
"gioui.org/gesture" "gioui.org/gesture"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/op" "gioui.org/op"
"gioui.org/op/paint" "gioui.org/op/clip"
) )
type scrollChild struct { type scrollChild struct {
@@ -248,7 +248,7 @@ func (l *List) layout() Dimensions {
} }
var stack op.StackOp var stack op.StackOp
stack.Push(ops) stack.Push(ops)
paint.RectClip(r).Add(ops) clip.Rect(r).Add(ops)
op.TransformOp{}.Offset(toPointF(axisPoint(l.Axis, pos, cross))).Add(ops) op.TransformOp{}.Offset(toPointF(axisPoint(l.Axis, pos, cross))).Add(ops)
child.macro.Add(ops) child.macro.Add(ops)
stack.Pop() stack.Pop()
+29 -13
View File
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package paint package clip
import ( import (
"encoding/binary" "encoding/binary"
"image"
"math" "math"
"gioui.org/f32" "gioui.org/f32"
@@ -12,10 +13,13 @@ import (
"gioui.org/op" "gioui.org/op"
) )
// Path constructs a ClipOp clip path described by lines and // Path constructs a Op clip path described by lines and
// Bézier curves. Path generates no garbage and can be used for // Bézier curves, where drawing outside the Path is discarded.
// dynamic paths; path data is stored directly in the Ops list // The inside-ness of a pixel is determines by the even-odd rule,
// supplied to Begin. // similar to the SVG rule of the same name.
//
// Path generates no garbage and can be used for dynamic paths; path
// data is stored directly in the Ops list supplied to Begin.
type Path struct { type Path struct {
ops *op.Ops ops *op.Ops
contour int contour int
@@ -25,17 +29,17 @@ type Path struct {
macro op.MacroOp macro op.MacroOp
} }
// ClipOp sets the current clip to the intersection of // Op sets the current clip to the intersection of
// the existing clip with this clip. // the existing clip with this clip.
// //
// If you need to reset the clip to its previous values after // If you need to reset the clip to its previous values after
// applying a ClipOp, use op.StackOp. // applying a Op, use op.StackOp.
type ClipOp struct { type Op struct {
macro op.MacroOp macro op.MacroOp
bounds f32.Rectangle bounds f32.Rectangle
} }
func (p ClipOp) Add(o *op.Ops) { func (p Op) Add(o *op.Ops) {
p.macro.Add(o) p.macro.Add(o)
data := o.Write(opconst.TypeClipLen) data := o.Write(opconst.TypeClipLen)
data[0] = byte(opconst.TypeClip) data[0] = byte(opconst.TypeClip)
@@ -46,7 +50,7 @@ func (p ClipOp) Add(o *op.Ops) {
bo.PutUint32(data[13:], math.Float32bits(p.bounds.Max.Y)) bo.PutUint32(data[13:], math.Float32bits(p.bounds.Max.Y))
} }
// Begin the path, storing the path data and final ClipOp into ops. // Begin the path, storing the path data and final Op into ops.
func (p *Path) Begin(ops *op.Ops) { func (p *Path) Begin(ops *op.Ops) {
p.ops = ops p.ops = ops
p.macro.Record(ops) p.macro.Record(ops)
@@ -270,12 +274,24 @@ func (p *Path) simpleQuadTo(ctrl, to f32.Point) {
p.pen = to p.pen = to
} }
// End the path and return the resulting ClipOp. // End the path and return a clip operation that represents it.
func (p *Path) End() ClipOp { func (p *Path) End() Op {
p.end() p.end()
p.macro.Stop() p.macro.Stop()
return ClipOp{ return Op{
macro: p.macro, macro: p.macro,
bounds: p.bounds, bounds: p.bounds,
} }
} }
// Rect returns the clip area of a pixel aligned rectangular area.
func Rect(r image.Rectangle) Op {
return Op{bounds: toRectF(r)}
}
func toRectF(r image.Rectangle) f32.Rectangle {
return f32.Rectangle{
Min: f32.Point{X: float32(r.Min.X), Y: float32(r.Min.Y)},
Max: f32.Point{X: float32(r.Max.X), Y: float32(r.Max.Y)},
}
}
+16
View File
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: Unlicense OR MIT
/*
Package clip provides operations for clipping paint operations.
Drawing outside the current clip area is ignored.
The current clip is initially the infinite set. An Op sets the clip
to the intersection of the current clip and the clip area it
represents. If you need to reset the current clip to its value
before applying an Op, use op.StackOp.
General clipping areas are constructed with Path. Simpler special
cases such as rectangular clip areas also exist as convenient
constructors.
*/
package clip
+1 -4
View File
@@ -1,15 +1,12 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
/* /*
Package paint provides operations for 2D graphics. Package paint provides drawing operations for 2D graphics.
The PaintOp operation draws the current material into a rectangular The PaintOp operation draws the current material into a rectangular
area, taking the current clip path and transformation into account. area, taking the current clip path and transformation into account.
The material is set by either a ColorOp for a constant color, or The material is set by either a ColorOp for a constant color, or
ImageOp for an image. ImageOp for an image.
The ClipOp operation sets the clip path. Drawing outside the clip
path is ignored. A path is a closed shape of lines or curves.
*/ */
package paint package paint
-13
View File
@@ -102,16 +102,3 @@ func (d PaintOp) Add(o *op.Ops) {
bo.PutUint32(data[9:], math.Float32bits(d.Rect.Max.X)) bo.PutUint32(data[9:], math.Float32bits(d.Rect.Max.X))
bo.PutUint32(data[13:], math.Float32bits(d.Rect.Max.Y)) bo.PutUint32(data[13:], math.Float32bits(d.Rect.Max.Y))
} }
// RectClip returns a ClipOp corresponding to a pixel aligned
// rectangular area.
func RectClip(r image.Rectangle) ClipOp {
return ClipOp{bounds: toRectF(r)}
}
func toRectF(r image.Rectangle) f32.Rectangle {
return f32.Rectangle{
Min: f32.Point{X: float32(r.Min.X), Y: float32(r.Min.Y)},
Max: f32.Point{X: float32(r.Max.X), Y: float32(r.Max.Y)},
}
}
+5 -5
View File
@@ -3,7 +3,7 @@
package text package text
import ( import (
"gioui.org/op/paint" "gioui.org/op/clip"
"golang.org/x/image/math/fixed" "golang.org/x/image/math/fixed"
) )
@@ -26,7 +26,7 @@ type layoutElem struct {
type path struct { type path struct {
next, prev *path next, prev *path
key pathKey key pathKey
val paint.ClipOp val clip.Op
} }
type layoutKey struct { type layoutKey struct {
@@ -81,16 +81,16 @@ func (l *layoutCache) insert(lt *layoutElem) {
lt.next.prev = lt lt.next.prev = lt
} }
func (c *pathCache) Get(k pathKey) (paint.ClipOp, bool) { func (c *pathCache) Get(k pathKey) (clip.Op, bool) {
if v, ok := c.m[k]; ok { if v, ok := c.m[k]; ok {
c.remove(v) c.remove(v)
c.insert(v) c.insert(v)
return v.val, true return v.val, true
} }
return paint.ClipOp{}, false return clip.Op{}, false
} }
func (c *pathCache) Put(k pathKey, v paint.ClipOp) { func (c *pathCache) Put(k pathKey, v clip.Op) {
if c.m == nil { if c.m == nil {
c.m = make(map[pathKey]*path) c.m = make(map[pathKey]*path)
c.head = new(path) c.head = new(path)
+2 -2
View File
@@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"testing" "testing"
"gioui.org/op/paint" "gioui.org/op/clip"
) )
func TestLayoutLRU(t *testing.T) { func TestLayoutLRU(t *testing.T) {
@@ -24,7 +24,7 @@ func TestLayoutLRU(t *testing.T) {
func TestPathLRU(t *testing.T) { func TestPathLRU(t *testing.T) {
c := new(pathCache) c := new(pathCache)
put := func(i int) { put := func(i int) {
c.Put(pathKey{str: strconv.Itoa(i)}, paint.ClipOp{}) c.Put(pathKey{str: strconv.Itoa(i)}, clip.Op{})
} }
get := func(i int) bool { get := func(i int) bool {
_, ok := c.Get(pathKey{str: strconv.Itoa(i)}) _, ok := c.Get(pathKey{str: strconv.Itoa(i)})
+4 -4
View File
@@ -5,7 +5,7 @@ package text
import ( import (
"unicode/utf8" "unicode/utf8"
"gioui.org/op/paint" "gioui.org/op/clip"
"gioui.org/unit" "gioui.org/unit"
"golang.org/x/image/math/fixed" "golang.org/x/image/math/fixed"
) )
@@ -46,7 +46,7 @@ func (s *Shaper) Layout(c unit.Converter, font Font, str string, opts LayoutOpti
return tf.layout(fixed.I(c.Px(font.Size)), str, opts) return tf.layout(fixed.I(c.Px(font.Size)), str, opts)
} }
func (s *Shaper) Shape(c unit.Converter, font Font, str String) paint.ClipOp { func (s *Shaper) Shape(c unit.Converter, font Font, str String) clip.Op {
tf := s.faceForFont(font) tf := s.faceForFont(font)
return tf.shape(fixed.I(c.Px(font.Size)), str) return tf.shape(fixed.I(c.Px(font.Size)), str)
} }
@@ -99,9 +99,9 @@ func (t *face) layout(ppem fixed.Int26_6, str string, opts LayoutOptions) *Layou
return l return l
} }
func (t *face) shape(ppem fixed.Int26_6, str String) paint.ClipOp { func (t *face) shape(ppem fixed.Int26_6, str String) clip.Op {
if t == nil { if t == nil {
return paint.ClipOp{} return clip.Op{}
} }
pk := pathKey{ pk := pathKey{
ppem: ppem, ppem: ppem,
+2 -2
View File
@@ -3,7 +3,7 @@
package text package text
import ( import (
"gioui.org/op/paint" "gioui.org/op/clip"
"gioui.org/unit" "gioui.org/unit"
"golang.org/x/image/math/fixed" "golang.org/x/image/math/fixed"
) )
@@ -61,7 +61,7 @@ type Font struct {
// Face implements text layout and shaping for a particular font. // Face implements text layout and shaping for a particular font.
type Face interface { type Face interface {
Layout(ppem fixed.Int26_6, str string, opts LayoutOptions) *Layout Layout(ppem fixed.Int26_6, str string, opts LayoutOptions) *Layout
Shape(ppem fixed.Int26_6, str String) paint.ClipOp Shape(ppem fixed.Int26_6, str String) clip.Op
} }
// Typeface identifies a particular typeface design. The empty // Typeface identifies a particular typeface design. The empty
+2 -1
View File
@@ -14,6 +14,7 @@ import (
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/layout" "gioui.org/layout"
"gioui.org/op" "gioui.org/op"
"gioui.org/op/clip"
"gioui.org/op/paint" "gioui.org/op/paint"
"gioui.org/text" "gioui.org/text"
"gioui.org/unit" "gioui.org/unit"
@@ -79,7 +80,7 @@ type SubmitEvent struct {
type line struct { type line struct {
offset f32.Point offset f32.Point
clip paint.ClipOp clip clip.Op
} }
const ( const (
+2 -1
View File
@@ -8,6 +8,7 @@ import (
"gioui.org/f32" "gioui.org/f32"
"gioui.org/layout" "gioui.org/layout"
"gioui.org/op" "gioui.org/op"
"gioui.org/op/clip"
"gioui.org/op/paint" "gioui.org/op/paint"
"gioui.org/unit" "gioui.org/unit"
) )
@@ -36,7 +37,7 @@ func (im Image) Layout(gtx *layout.Context) {
d := image.Point{X: cs.Width.Constrain(w), Y: cs.Height.Constrain(h)} d := image.Point{X: cs.Width.Constrain(w), Y: cs.Height.Constrain(h)}
var s op.StackOp var s op.StackOp
s.Push(gtx.Ops) s.Push(gtx.Ops)
paint.RectClip(image.Rectangle{Max: d}).Add(gtx.Ops) clip.Rect(image.Rectangle{Max: d}).Add(gtx.Ops)
im.Src.Add(gtx.Ops) im.Src.Add(gtx.Ops)
paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: float32(w), Y: float32(h)}}}.Add(gtx.Ops) paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: float32(w), Y: float32(h)}}}.Add(gtx.Ops)
s.Pop() s.Pop()
+2 -1
View File
@@ -10,6 +10,7 @@ import (
"gioui.org/font" "gioui.org/font"
"gioui.org/layout" "gioui.org/layout"
"gioui.org/op" "gioui.org/op"
"gioui.org/op/clip"
"gioui.org/op/paint" "gioui.org/op/paint"
"gioui.org/text" "gioui.org/text"
"gioui.org/unit" "gioui.org/unit"
@@ -79,7 +80,7 @@ func fill(gtx *layout.Context, col color.RGBA) {
func rrect(ops *op.Ops, width, height, se, sw, nw, ne float32) { func rrect(ops *op.Ops, width, height, se, sw, nw, ne float32) {
w, h := float32(width), float32(height) w, h := float32(width), float32(height)
const c = 0.55228475 // 4*(sqrt(2)-1)/3 const c = 0.55228475 // 4*(sqrt(2)-1)/3
var b paint.Path var b clip.Path
b.Begin(ops) b.Begin(ops)
b.Move(f32.Point{X: w, Y: h - se}) b.Move(f32.Point{X: w, Y: h - se})
b.Cube(f32.Point{X: 0, Y: se * c}, f32.Point{X: -se + se*c, Y: se}, f32.Point{X: -se, Y: se}) // SE b.Cube(f32.Point{X: 0, Y: se * c}, f32.Point{X: -se + se*c, Y: se}, f32.Point{X: -se, Y: se}) // SE