diff --git a/app/internal/gpu/gpu.go b/app/internal/gpu/gpu.go index 1154c936..b9b3f434 100644 --- a/app/internal/gpu/gpu.go +++ b/app/internal/gpu/gpu.go @@ -119,7 +119,7 @@ type material struct { uvOffset f32.Point } -// clipOp is the shadow of paint.ClipOp. +// clipOp is the shadow of clip.Op. type clipOp struct { bounds f32.Rectangle } diff --git a/font/opentype/opentype.go b/font/opentype/opentype.go index ac83f46c..b9057571 100644 --- a/font/opentype/opentype.go +++ b/font/opentype/opentype.go @@ -11,7 +11,7 @@ import ( "gioui.org/f32" "gioui.org/op" - "gioui.org/op/paint" + "gioui.org/op/clip" "gioui.org/text" "golang.org/x/image/font" "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) } -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) } @@ -136,9 +136,9 @@ func layoutText(buf *sfnt.Buffer, ppem fixed.Int26_6, str string, f *opentype, o 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 builder paint.Path + var builder clip.Path ops := new(op.Ops) var x fixed.Int26_6 var advIdx int diff --git a/layout/list.go b/layout/list.go index 917f431a..cd32005d 100644 --- a/layout/list.go +++ b/layout/list.go @@ -8,7 +8,7 @@ import ( "gioui.org/gesture" "gioui.org/io/pointer" "gioui.org/op" - "gioui.org/op/paint" + "gioui.org/op/clip" ) type scrollChild struct { @@ -248,7 +248,7 @@ func (l *List) layout() Dimensions { } var stack op.StackOp stack.Push(ops) - paint.RectClip(r).Add(ops) + clip.Rect(r).Add(ops) op.TransformOp{}.Offset(toPointF(axisPoint(l.Axis, pos, cross))).Add(ops) child.macro.Add(ops) stack.Pop() diff --git a/op/paint/path.go b/op/clip/clip.go similarity index 87% rename from op/paint/path.go rename to op/clip/clip.go index 8aa1edc5..5f64a20b 100644 --- a/op/paint/path.go +++ b/op/clip/clip.go @@ -1,9 +1,10 @@ // SPDX-License-Identifier: Unlicense OR MIT -package paint +package clip import ( "encoding/binary" + "image" "math" "gioui.org/f32" @@ -12,10 +13,13 @@ import ( "gioui.org/op" ) -// Path constructs a ClipOp clip path described by lines and -// Bézier curves. Path generates no garbage and can be used for -// dynamic paths; path data is stored directly in the Ops list -// supplied to Begin. +// Path constructs a Op clip path described by lines and +// Bézier curves, where drawing outside the Path is discarded. +// The inside-ness of a pixel is determines by the even-odd rule, +// 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 { ops *op.Ops contour int @@ -25,17 +29,17 @@ type Path struct { 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. // // If you need to reset the clip to its previous values after -// applying a ClipOp, use op.StackOp. -type ClipOp struct { +// applying a Op, use op.StackOp. +type Op struct { macro op.MacroOp bounds f32.Rectangle } -func (p ClipOp) Add(o *op.Ops) { +func (p Op) Add(o *op.Ops) { p.macro.Add(o) data := o.Write(opconst.TypeClipLen) 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)) } -// 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) { p.ops = ops p.macro.Record(ops) @@ -270,12 +274,24 @@ func (p *Path) simpleQuadTo(ctrl, to f32.Point) { p.pen = to } -// End the path and return the resulting ClipOp. -func (p *Path) End() ClipOp { +// End the path and return a clip operation that represents it. +func (p *Path) End() Op { p.end() p.macro.Stop() - return ClipOp{ + return Op{ macro: p.macro, 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)}, + } +} diff --git a/op/clip/doc.go b/op/clip/doc.go new file mode 100644 index 00000000..6ba55467 --- /dev/null +++ b/op/clip/doc.go @@ -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 diff --git a/op/paint/doc.go b/op/paint/doc.go index eeb15497..5ace0c0a 100644 --- a/op/paint/doc.go +++ b/op/paint/doc.go @@ -1,15 +1,12 @@ // 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 area, taking the current clip path and transformation into account. The material is set by either a ColorOp for a constant color, or 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 diff --git a/op/paint/paint.go b/op/paint/paint.go index c0ce8791..77ec5704 100644 --- a/op/paint/paint.go +++ b/op/paint/paint.go @@ -102,16 +102,3 @@ func (d PaintOp) Add(o *op.Ops) { bo.PutUint32(data[9:], math.Float32bits(d.Rect.Max.X)) 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)}, - } -} diff --git a/text/lru.go b/text/lru.go index f3c769c8..f03b9300 100644 --- a/text/lru.go +++ b/text/lru.go @@ -3,7 +3,7 @@ package text import ( - "gioui.org/op/paint" + "gioui.org/op/clip" "golang.org/x/image/math/fixed" ) @@ -26,7 +26,7 @@ type layoutElem struct { type path struct { next, prev *path key pathKey - val paint.ClipOp + val clip.Op } type layoutKey struct { @@ -81,16 +81,16 @@ func (l *layoutCache) insert(lt *layoutElem) { 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 { c.remove(v) c.insert(v) 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 { c.m = make(map[pathKey]*path) c.head = new(path) diff --git a/text/lru_test.go b/text/lru_test.go index 6d9acdb5..192f6392 100644 --- a/text/lru_test.go +++ b/text/lru_test.go @@ -6,7 +6,7 @@ import ( "strconv" "testing" - "gioui.org/op/paint" + "gioui.org/op/clip" ) func TestLayoutLRU(t *testing.T) { @@ -24,7 +24,7 @@ func TestLayoutLRU(t *testing.T) { func TestPathLRU(t *testing.T) { c := new(pathCache) 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 { _, ok := c.Get(pathKey{str: strconv.Itoa(i)}) diff --git a/text/shaper.go b/text/shaper.go index 1b1d1bd0..b6149a44 100644 --- a/text/shaper.go +++ b/text/shaper.go @@ -5,7 +5,7 @@ package text import ( "unicode/utf8" - "gioui.org/op/paint" + "gioui.org/op/clip" "gioui.org/unit" "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) } -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) 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 } -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 { - return paint.ClipOp{} + return clip.Op{} } pk := pathKey{ ppem: ppem, diff --git a/text/text.go b/text/text.go index a9c001c3..b2b4841f 100644 --- a/text/text.go +++ b/text/text.go @@ -3,7 +3,7 @@ package text import ( - "gioui.org/op/paint" + "gioui.org/op/clip" "gioui.org/unit" "golang.org/x/image/math/fixed" ) @@ -61,7 +61,7 @@ type Font struct { // Face implements text layout and shaping for a particular font. type Face interface { 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 diff --git a/widget/editor.go b/widget/editor.go index d061816a..21809c9e 100644 --- a/widget/editor.go +++ b/widget/editor.go @@ -14,6 +14,7 @@ import ( "gioui.org/io/pointer" "gioui.org/layout" "gioui.org/op" + "gioui.org/op/clip" "gioui.org/op/paint" "gioui.org/text" "gioui.org/unit" @@ -79,7 +80,7 @@ type SubmitEvent struct { type line struct { offset f32.Point - clip paint.ClipOp + clip clip.Op } const ( diff --git a/widget/material/image.go b/widget/material/image.go index c38b0ed8..318de388 100644 --- a/widget/material/image.go +++ b/widget/material/image.go @@ -8,6 +8,7 @@ import ( "gioui.org/f32" "gioui.org/layout" "gioui.org/op" + "gioui.org/op/clip" "gioui.org/op/paint" "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)} var s op.StackOp 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) paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: float32(w), Y: float32(h)}}}.Add(gtx.Ops) s.Pop() diff --git a/widget/material/material.go b/widget/material/material.go index cbcd5db8..d42cea18 100644 --- a/widget/material/material.go +++ b/widget/material/material.go @@ -10,6 +10,7 @@ import ( "gioui.org/font" "gioui.org/layout" "gioui.org/op" + "gioui.org/op/clip" "gioui.org/op/paint" "gioui.org/text" "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) { w, h := float32(width), float32(height) const c = 0.55228475 // 4*(sqrt(2)-1)/3 - var b paint.Path + var b clip.Path b.Begin(ops) 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