From c19ed053429731010493c8a1515ee5dd5c0ac5ec Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Tue, 2 Jun 2020 12:07:20 +0200 Subject: [PATCH] op: change CallOp to be a return value from MacroOp.Stop Converting macro := op.Record(ops) ... macro.Stop() macro.Add() to macro := op.Record(ops) ... call := macro.Stop() call.Add(ops) Which is more general (call.Add can take a different ops than the op.Record that started it), and enforced the order between Stop and the subsequent Add. Signed-off-by: Elias Naur --- font/opentype/opentype.go | 3 ++- internal/opconst/ops.go | 11 +++----- internal/ops/reader.go | 53 +++++++++----------------------------- layout/flex.go | 14 +++++----- layout/layout.go | 4 +-- layout/list.go | 14 +++++----- layout/stack.go | 14 +++++----- op/clip/clip.go | 8 +++--- op/op.go | 54 ++++++++++++++++----------------------- widget/material/editor.go | 4 +-- 10 files changed, 69 insertions(+), 110 deletions(-) diff --git a/font/opentype/opentype.go b/font/opentype/opentype.go index e02a89e8..27afea4b 100644 --- a/font/opentype/opentype.go +++ b/font/opentype/opentype.go @@ -185,6 +185,7 @@ func textPath(buf *sfnt.Buffer, ppem fixed.Int26_6, f *opentype, str []text.Glyp var lastPos f32.Point var builder clip.Path ops := new(op.Ops) + m := op.Record(ops) var x fixed.Int26_6 builder.Begin(ops) for _, g := range str { @@ -238,7 +239,7 @@ func textPath(buf *sfnt.Buffer, ppem fixed.Int26_6, f *opentype, str []text.Glyp x += g.Advance } builder.End().Add(ops) - return op.CallOp{Ops: ops} + return m.Stop() } func readGlyphs(r io.Reader) ([]text.Glyph, error) { diff --git a/internal/opconst/ops.go b/internal/opconst/ops.go index 927da93e..46396aac 100644 --- a/internal/opconst/ops.go +++ b/internal/opconst/ops.go @@ -8,8 +8,8 @@ type OpType byte const firstOpIndex = 200 const ( - TypeMacroDef OpType = iota + firstOpIndex - TypeMacro + TypeMacro OpType = iota + firstOpIndex + TypeCall TypeTransform TypeLayer TypeInvalidate @@ -26,12 +26,11 @@ const ( TypeAux TypeClip TypeProfile - TypeCall ) const ( - TypeMacroDefLen = 1 + 4 + 4 TypeMacroLen = 1 + 4 + 4 + TypeCallLen = 1 + 4 + 4 TypeTransformLen = 1 + 4*2 TypeLayerLen = 1 TypeRedrawLen = 1 + 8 @@ -48,13 +47,12 @@ const ( TypeAuxLen = 1 TypeClipLen = 1 + 4*4 TypeProfileLen = 1 - TypeCallLen = 1 ) func (t OpType) Size() int { return [...]int{ - TypeMacroDefLen, TypeMacroLen, + TypeCallLen, TypeTransformLen, TypeLayerLen, TypeRedrawLen, @@ -71,7 +69,6 @@ func (t OpType) Size() int { TypeAuxLen, TypeClipLen, TypeProfileLen, - TypeCallLen, }[t-firstOpIndex] } diff --git a/internal/ops/reader.go b/internal/ops/reader.go index 52d3a401..077b9d84 100644 --- a/internal/ops/reader.go +++ b/internal/ops/reader.go @@ -33,12 +33,8 @@ type Key struct { // Shadow of op.MacroOp. type macroOp struct { - pc pc -} - -// Shadow of op.CallOp. -type callOp struct { ops *op.Ops + pc pc } type pc struct { @@ -98,32 +94,14 @@ func (r *Reader) Decode() (EncodedOp, bool) { n += block.endPC.data - r.pc.data - opconst.TypeAuxLen data = data[:n] case opconst.TypeCall: - var op callOp - op.decode(data, refs) - endPC := pc{ - data: len(op.ops.Data()), - refs: len(op.ops.Refs()), - } - retPC := r.pc - retPC.data += n - retPC.refs += nrefs - r.stack = append(r.stack, macro{ - ops: r.ops, - retPC: retPC, - endPC: endPC, - }) - r.pc = pc{} - r.ops = op.ops - continue - case opconst.TypeMacro: var op macroOp - op.decode(data) - macroData := r.ops.Data()[op.pc.data:] - if opconst.OpType(macroData[0]) != opconst.TypeMacroDef { + op.decode(data, refs) + macroData := op.ops.Data()[op.pc.data:] + if opconst.OpType(macroData[0]) != opconst.TypeMacro { panic("invalid macro reference") } var opDef opMacroDef - opDef.decode(macroData[:opconst.TypeMacroDef.Size()]) + opDef.decode(macroData[:opconst.TypeMacro.Size()]) retPC := r.pc retPC.data += n retPC.refs += nrefs @@ -132,11 +110,12 @@ func (r *Reader) Decode() (EncodedOp, bool) { retPC: retPC, endPC: opDef.endpc, }) + r.ops = op.ops r.pc = op.pc - r.pc.data += opconst.TypeMacroDef.Size() - r.pc.refs += opconst.TypeMacroDef.NumRefs() + r.pc.data += opconst.TypeMacro.Size() + r.pc.refs += opconst.TypeMacro.NumRefs() continue - case opconst.TypeMacroDef: + case opconst.TypeMacro: var op opMacroDef op.decode(data) r.pc = op.endpc @@ -149,7 +128,7 @@ func (r *Reader) Decode() (EncodedOp, bool) { } func (op *opMacroDef) decode(data []byte) { - if opconst.OpType(data[0]) != opconst.TypeMacroDef { + if opconst.OpType(data[0]) != opconst.TypeMacro { panic("invalid op") } bo := binary.LittleEndian @@ -163,23 +142,15 @@ func (op *opMacroDef) decode(data []byte) { } } -func (m *callOp) decode(data []byte, refs []interface{}) { +func (m *macroOp) decode(data []byte, refs []interface{}) { if opconst.OpType(data[0]) != opconst.TypeCall { panic("invalid op") } - *m = callOp{ - ops: refs[0].(*op.Ops), - } -} - -func (m *macroOp) decode(data []byte) { - if opconst.OpType(data[0]) != opconst.TypeMacro { - panic("invalid op") - } bo := binary.LittleEndian dataIdx := int(int32(bo.Uint32(data[1:]))) refsIdx := int(int32(bo.Uint32(data[5:]))) *m = macroOp{ + ops: refs[0].(*op.Ops), pc: pc{ data: dataIdx, refs: refsIdx, diff --git a/layout/flex.go b/layout/flex.go index 7037d923..bd961769 100644 --- a/layout/flex.go +++ b/layout/flex.go @@ -28,8 +28,8 @@ type FlexChild struct { widget Widget // Scratch space. - macro op.MacroOp - dims Dimensions + call op.CallOp + dims Dimensions } // Spacing determine the spacing mode for a Flex. @@ -93,10 +93,10 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions { gtx := gtx gtx.Constraints = cs dims := child.widget(gtx) - macro.Stop() + c := macro.Stop() sz := axisMain(f.Axis, dims.Size) size += sz - children[i].macro = macro + children[i].call = c children[i].dims = dims } rigidSize := size @@ -127,10 +127,10 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions { gtx := gtx gtx.Constraints = cs dims := child.widget(gtx) - macro.Stop() + c := macro.Stop() sz := axisMain(f.Axis, dims.Size) size += sz - children[i].macro = macro + children[i].call = c children[i].dims = dims } var maxCross int @@ -176,7 +176,7 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions { } stack := op.Push(gtx.Ops) op.TransformOp{}.Offset(FPt(axisPoint(f.Axis, mainSize, cross))).Add(gtx.Ops) - child.macro.Add() + child.call.Add(gtx.Ops) stack.Pop() mainSize += axisMain(f.Axis, dims.Size) if i < len(children)-1 { diff --git a/layout/layout.go b/layout/layout.go index 4930c168..03232dbe 100644 --- a/layout/layout.go +++ b/layout/layout.go @@ -158,7 +158,7 @@ func (a Direction) Layout(gtx Context, w Widget) Dimensions { cs := gtx.Constraints gtx.Constraints.Min = image.Point{} dims := w(gtx) - macro.Stop() + call := macro.Stop() sz := dims.Size if sz.X < cs.Min.X { sz.X = cs.Min.X @@ -181,7 +181,7 @@ func (a Direction) Layout(gtx Context, w Widget) Dimensions { } stack := op.Push(gtx.Ops) op.TransformOp{}.Offset(FPt(p)).Add(gtx.Ops) - macro.Add() + call.Add(gtx.Ops) stack.Pop() return Dimensions{ Size: sz, diff --git a/layout/list.go b/layout/list.go index 64ae1c9d..243948f6 100644 --- a/layout/list.go +++ b/layout/list.go @@ -12,8 +12,8 @@ import ( ) type scrollChild struct { - size image.Point - macro op.MacroOp + size image.Point + call op.CallOp } // List displays a subsection of a potentially infinitely @@ -181,8 +181,8 @@ func (l *List) nextDir() iterationDir { // End the current child by specifying its dimensions. func (l *List) end(dims Dimensions) { - l.child.Stop() - child := scrollChild{dims.Size, l.child} + call := l.child.Stop() + child := scrollChild{dims.Size, call} mainSize := axisMain(l.Axis, child.size) l.maxSize += mainSize switch l.dir { @@ -260,7 +260,7 @@ func (l *List) layout() Dimensions { stack := op.Push(ops) clip.Rect{Rect: FRect(r)}.Op(ops).Add(ops) op.TransformOp{}.Offset(FPt(axisPoint(l.Axis, pos, cross))).Add(ops) - child.macro.Add() + child.call.Add(ops) stack.Pop() pos += childSize } @@ -277,10 +277,10 @@ func (l *List) layout() Dimensions { pos = mainMax } dims := axisPoint(l.Axis, pos, maxCross) - l.macro.Stop() + call := l.macro.Stop() defer op.Push(l.ctx.Ops).Pop() pointer.Rect(image.Rectangle{Max: dims}).Add(ops) l.scroll.Add(ops) - l.macro.Add() + call.Add(ops) return Dimensions{Size: dims} } diff --git a/layout/stack.go b/layout/stack.go index fd030e8d..a39a5994 100644 --- a/layout/stack.go +++ b/layout/stack.go @@ -22,8 +22,8 @@ type StackChild struct { widget Widget // Scratch space. - macro op.MacroOp - dims Dimensions + call op.CallOp + dims Dimensions } // Stacked returns a Stack child that is laid out with no minimum @@ -58,14 +58,14 @@ func (s Stack) Layout(gtx Context, children ...StackChild) Dimensions { gtx := gtx gtx.Constraints.Min = image.Pt(0, 0) dims := w.widget(gtx) - macro.Stop() + call := macro.Stop() if w := dims.Size.X; w > maxSZ.X { maxSZ.X = w } if h := dims.Size.Y; h > maxSZ.Y { maxSZ.Y = h } - children[i].macro = macro + children[i].call = call children[i].dims = dims } // Then lay out Expanded children. @@ -79,14 +79,14 @@ func (s Stack) Layout(gtx Context, children ...StackChild) Dimensions { Min: maxSZ, Max: gtx.Constraints.Max, } dims := w.widget(gtx) - macro.Stop() + call := macro.Stop() if w := dims.Size.X; w > maxSZ.X { maxSZ.X = w } if h := dims.Size.Y; h > maxSZ.Y { maxSZ.Y = h } - children[i].macro = macro + children[i].call = call children[i].dims = dims } @@ -109,7 +109,7 @@ func (s Stack) Layout(gtx Context, children ...StackChild) Dimensions { } stack := op.Push(gtx.Ops) op.TransformOp{}.Offset(FPt(p)).Add(gtx.Ops) - ch.macro.Add() + ch.call.Add(gtx.Ops) stack.Pop() if baseline == 0 { if b := ch.dims.Baseline; b != 0 { diff --git a/op/clip/clip.go b/op/clip/clip.go index c54bdcc8..f77d5a88 100644 --- a/op/clip/clip.go +++ b/op/clip/clip.go @@ -35,12 +35,12 @@ type Path struct { // If you need to reset the clip to its previous values after // applying a Op, use op.StackOp. type Op struct { - macro op.MacroOp + call op.CallOp bounds f32.Rectangle } func (p Op) Add(o *op.Ops) { - p.macro.Add() + p.call.Add(o) data := o.Write(opconst.TypeClipLen) data[0] = byte(opconst.TypeClip) bo := binary.LittleEndian @@ -281,9 +281,9 @@ func (p *Path) simpleQuadTo(ctrl, to f32.Point) { // End the path and return a clip operation that represents it. func (p *Path) End() Op { p.end() - p.macro.Stop() + c := p.macro.Stop() return Op{ - macro: p.macro, + call: c, bounds: p.bounds, } } diff --git a/op/op.go b/op/op.go index 1634a09b..1cd3b1bc 100644 --- a/op/op.go +++ b/op/op.go @@ -49,12 +49,6 @@ end of a function : defer op.Push(ops).Pop() -The CallOp invokes another operation list: - - ops := new(op.Ops) - ops2 := new(op.Ops) - op.CallOp{Ops: ops2}.Add(ops) - The MacroOp records a list of operations to be executed later: ops := new(op.Ops) @@ -63,10 +57,10 @@ The MacroOp records a list of operations to be executed later: op.InvalidateOp{}.Add(ops) ... // End recording. - macro.Stop() + call := macro.Stop() - // replay the recorded operations by calling Add: - macro.Add() + // replay the recorded operations: + call.Add(ops) */ package op @@ -110,11 +104,11 @@ type MacroOp struct { pc pc } -// CallOp invokes all the operations from a separate -// operations list. +// CallOp invokes the operations recorded by Record. type CallOp struct { // Ops is the list of operations to invoke. - Ops *Ops + ops *Ops + pc pc } // InvalidateOp requests a redraw at the given time. Use @@ -146,15 +140,6 @@ type pc struct { refs int } -// Add the call to the operation list. -func (c CallOp) Add(o *Ops) { - if c.Ops == nil { - return - } - data := o.Write(opconst.TypeCallLen, c.Ops) - data[0] = byte(opconst.TypeCall) -} - // Push (save) the current operations state. func Push(o *Ops) StackOp { s := StackOp{ @@ -224,38 +209,43 @@ func Record(o *Ops) MacroOp { pc: o.pc(), } // Reserve room for a macro definition. Updated in Stop. - m.ops.Write(opconst.TypeMacroDefLen) + m.ops.Write(opconst.TypeMacroLen) m.fill() return m } -// Stop ends a previously started recording. -func (m MacroOp) Stop() { +// Stop ends a previously started recording and returns an +// operation for replaying it. +func (m MacroOp) Stop() CallOp { m.ops.macroStack.pop(m.id) m.fill() + return CallOp{ + ops: m.ops, + pc: m.pc, + } } func (m MacroOp) fill() { pc := m.ops.pc() // Fill out the macro definition reserved in Record. data := m.ops.data[m.pc.data:] - data = data[:opconst.TypeMacroDefLen] - data[0] = byte(opconst.TypeMacroDef) + data = data[:opconst.TypeMacroLen] + data[0] = byte(opconst.TypeMacro) bo := binary.LittleEndian bo.PutUint32(data[1:], uint32(pc.data)) bo.PutUint32(data[5:], uint32(pc.refs)) } // Add the recorded list of operations. -func (m MacroOp) Add() { - if m.ops == nil { +func (c CallOp) Add(o *Ops) { + if c.ops == nil { return } - data := m.ops.Write(opconst.TypeMacroLen) - data[0] = byte(opconst.TypeMacro) + data := o.Write(opconst.TypeCallLen, c.ops) + data[0] = byte(opconst.TypeCall) bo := binary.LittleEndian - bo.PutUint32(data[1:], uint32(m.pc.data)) - bo.PutUint32(data[5:], uint32(m.pc.refs)) + bo.PutUint32(data[1:], uint32(c.pc.data)) + bo.PutUint32(data[5:], uint32(c.pc.refs)) } func (r InvalidateOp) Add(o *Ops) { diff --git a/widget/material/editor.go b/widget/material/editor.go index 96739924..2b2a9fe6 100644 --- a/widget/material/editor.go +++ b/widget/material/editor.go @@ -44,7 +44,7 @@ func (e EditorStyle) Layout(gtx layout.Context) layout.Dimensions { paint.ColorOp{Color: e.HintColor}.Add(gtx.Ops) tl := widget.Label{Alignment: e.Editor.Alignment} dims := tl.Layout(gtx, e.shaper, e.Font, e.TextSize, e.Hint) - macro.Stop() + call := macro.Stop() if w := dims.Size.X; gtx.Constraints.Min.X < w { gtx.Constraints.Min.X = w } @@ -56,7 +56,7 @@ func (e EditorStyle) Layout(gtx layout.Context) layout.Dimensions { paint.ColorOp{Color: e.Color}.Add(gtx.Ops) e.Editor.PaintText(gtx) } else { - macro.Add() + call.Add(gtx.Ops) } paint.ColorOp{Color: e.Color}.Add(gtx.Ops) e.Editor.PaintCaret(gtx)