~eliasnaur/gio

c19ed053429731010493c8a1515ee5dd5c0ac5ec — Elias Naur a month ago ce0cc70
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 <mail@eliasnaur.com>
M font/opentype/opentype.go => font/opentype/opentype.go +2 -1
@@ 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) {

M internal/opconst/ops.go => internal/opconst/ops.go +4 -7
@@ 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]
}


M internal/ops/reader.go => internal/ops/reader.go +12 -41
@@ 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,

M layout/flex.go => layout/flex.go +7 -7
@@ 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 {

M layout/layout.go => layout/layout.go +2 -2
@@ 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,

M layout/list.go => layout/list.go +7 -7
@@ 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}
}

M layout/stack.go => layout/stack.go +7 -7
@@ 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 {

M op/clip/clip.go => op/clip/clip.go +4 -4
@@ 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,
	}
}

M op/op.go => op/op.go +22 -32
@@ 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) {

M widget/material/editor.go => widget/material/editor.go +2 -2
@@ 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)