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>
This commit is contained in:
Elias Naur
2020-06-02 12:07:20 +02:00
parent ce0cc706ad
commit c19ed05342
10 changed files with 69 additions and 110 deletions
+2 -1
View File
@@ -185,6 +185,7 @@ func textPath(buf *sfnt.Buffer, ppem fixed.Int26_6, f *opentype, str []text.Glyp
var lastPos f32.Point var lastPos f32.Point
var builder clip.Path var builder clip.Path
ops := new(op.Ops) ops := new(op.Ops)
m := op.Record(ops)
var x fixed.Int26_6 var x fixed.Int26_6
builder.Begin(ops) builder.Begin(ops)
for _, g := range str { 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 x += g.Advance
} }
builder.End().Add(ops) builder.End().Add(ops)
return op.CallOp{Ops: ops} return m.Stop()
} }
func readGlyphs(r io.Reader) ([]text.Glyph, error) { func readGlyphs(r io.Reader) ([]text.Glyph, error) {
+4 -7
View File
@@ -8,8 +8,8 @@ type OpType byte
const firstOpIndex = 200 const firstOpIndex = 200
const ( const (
TypeMacroDef OpType = iota + firstOpIndex TypeMacro OpType = iota + firstOpIndex
TypeMacro TypeCall
TypeTransform TypeTransform
TypeLayer TypeLayer
TypeInvalidate TypeInvalidate
@@ -26,12 +26,11 @@ const (
TypeAux TypeAux
TypeClip TypeClip
TypeProfile TypeProfile
TypeCall
) )
const ( const (
TypeMacroDefLen = 1 + 4 + 4
TypeMacroLen = 1 + 4 + 4 TypeMacroLen = 1 + 4 + 4
TypeCallLen = 1 + 4 + 4
TypeTransformLen = 1 + 4*2 TypeTransformLen = 1 + 4*2
TypeLayerLen = 1 TypeLayerLen = 1
TypeRedrawLen = 1 + 8 TypeRedrawLen = 1 + 8
@@ -48,13 +47,12 @@ const (
TypeAuxLen = 1 TypeAuxLen = 1
TypeClipLen = 1 + 4*4 TypeClipLen = 1 + 4*4
TypeProfileLen = 1 TypeProfileLen = 1
TypeCallLen = 1
) )
func (t OpType) Size() int { func (t OpType) Size() int {
return [...]int{ return [...]int{
TypeMacroDefLen,
TypeMacroLen, TypeMacroLen,
TypeCallLen,
TypeTransformLen, TypeTransformLen,
TypeLayerLen, TypeLayerLen,
TypeRedrawLen, TypeRedrawLen,
@@ -71,7 +69,6 @@ func (t OpType) Size() int {
TypeAuxLen, TypeAuxLen,
TypeClipLen, TypeClipLen,
TypeProfileLen, TypeProfileLen,
TypeCallLen,
}[t-firstOpIndex] }[t-firstOpIndex]
} }
+12 -41
View File
@@ -33,12 +33,8 @@ type Key struct {
// Shadow of op.MacroOp. // Shadow of op.MacroOp.
type macroOp struct { type macroOp struct {
pc pc
}
// Shadow of op.CallOp.
type callOp struct {
ops *op.Ops ops *op.Ops
pc pc
} }
type pc struct { type pc struct {
@@ -98,32 +94,14 @@ func (r *Reader) Decode() (EncodedOp, bool) {
n += block.endPC.data - r.pc.data - opconst.TypeAuxLen n += block.endPC.data - r.pc.data - opconst.TypeAuxLen
data = data[:n] data = data[:n]
case opconst.TypeCall: 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 var op macroOp
op.decode(data) op.decode(data, refs)
macroData := r.ops.Data()[op.pc.data:] macroData := op.ops.Data()[op.pc.data:]
if opconst.OpType(macroData[0]) != opconst.TypeMacroDef { if opconst.OpType(macroData[0]) != opconst.TypeMacro {
panic("invalid macro reference") panic("invalid macro reference")
} }
var opDef opMacroDef var opDef opMacroDef
opDef.decode(macroData[:opconst.TypeMacroDef.Size()]) opDef.decode(macroData[:opconst.TypeMacro.Size()])
retPC := r.pc retPC := r.pc
retPC.data += n retPC.data += n
retPC.refs += nrefs retPC.refs += nrefs
@@ -132,11 +110,12 @@ func (r *Reader) Decode() (EncodedOp, bool) {
retPC: retPC, retPC: retPC,
endPC: opDef.endpc, endPC: opDef.endpc,
}) })
r.ops = op.ops
r.pc = op.pc r.pc = op.pc
r.pc.data += opconst.TypeMacroDef.Size() r.pc.data += opconst.TypeMacro.Size()
r.pc.refs += opconst.TypeMacroDef.NumRefs() r.pc.refs += opconst.TypeMacro.NumRefs()
continue continue
case opconst.TypeMacroDef: case opconst.TypeMacro:
var op opMacroDef var op opMacroDef
op.decode(data) op.decode(data)
r.pc = op.endpc r.pc = op.endpc
@@ -149,7 +128,7 @@ func (r *Reader) Decode() (EncodedOp, bool) {
} }
func (op *opMacroDef) decode(data []byte) { func (op *opMacroDef) decode(data []byte) {
if opconst.OpType(data[0]) != opconst.TypeMacroDef { if opconst.OpType(data[0]) != opconst.TypeMacro {
panic("invalid op") panic("invalid op")
} }
bo := binary.LittleEndian 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 { if opconst.OpType(data[0]) != opconst.TypeCall {
panic("invalid op") 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 bo := binary.LittleEndian
dataIdx := int(int32(bo.Uint32(data[1:]))) dataIdx := int(int32(bo.Uint32(data[1:])))
refsIdx := int(int32(bo.Uint32(data[5:]))) refsIdx := int(int32(bo.Uint32(data[5:])))
*m = macroOp{ *m = macroOp{
ops: refs[0].(*op.Ops),
pc: pc{ pc: pc{
data: dataIdx, data: dataIdx,
refs: refsIdx, refs: refsIdx,
+7 -7
View File
@@ -28,8 +28,8 @@ type FlexChild struct {
widget Widget widget Widget
// Scratch space. // Scratch space.
macro op.MacroOp call op.CallOp
dims Dimensions dims Dimensions
} }
// Spacing determine the spacing mode for a Flex. // Spacing determine the spacing mode for a Flex.
@@ -93,10 +93,10 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions {
gtx := gtx gtx := gtx
gtx.Constraints = cs gtx.Constraints = cs
dims := child.widget(gtx) dims := child.widget(gtx)
macro.Stop() c := macro.Stop()
sz := axisMain(f.Axis, dims.Size) sz := axisMain(f.Axis, dims.Size)
size += sz size += sz
children[i].macro = macro children[i].call = c
children[i].dims = dims children[i].dims = dims
} }
rigidSize := size rigidSize := size
@@ -127,10 +127,10 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions {
gtx := gtx gtx := gtx
gtx.Constraints = cs gtx.Constraints = cs
dims := child.widget(gtx) dims := child.widget(gtx)
macro.Stop() c := macro.Stop()
sz := axisMain(f.Axis, dims.Size) sz := axisMain(f.Axis, dims.Size)
size += sz size += sz
children[i].macro = macro children[i].call = c
children[i].dims = dims children[i].dims = dims
} }
var maxCross int var maxCross int
@@ -176,7 +176,7 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions {
} }
stack := op.Push(gtx.Ops) stack := op.Push(gtx.Ops)
op.TransformOp{}.Offset(FPt(axisPoint(f.Axis, mainSize, cross))).Add(gtx.Ops) op.TransformOp{}.Offset(FPt(axisPoint(f.Axis, mainSize, cross))).Add(gtx.Ops)
child.macro.Add() child.call.Add(gtx.Ops)
stack.Pop() stack.Pop()
mainSize += axisMain(f.Axis, dims.Size) mainSize += axisMain(f.Axis, dims.Size)
if i < len(children)-1 { if i < len(children)-1 {
+2 -2
View File
@@ -158,7 +158,7 @@ func (a Direction) Layout(gtx Context, w Widget) Dimensions {
cs := gtx.Constraints cs := gtx.Constraints
gtx.Constraints.Min = image.Point{} gtx.Constraints.Min = image.Point{}
dims := w(gtx) dims := w(gtx)
macro.Stop() call := macro.Stop()
sz := dims.Size sz := dims.Size
if sz.X < cs.Min.X { if sz.X < cs.Min.X {
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) stack := op.Push(gtx.Ops)
op.TransformOp{}.Offset(FPt(p)).Add(gtx.Ops) op.TransformOp{}.Offset(FPt(p)).Add(gtx.Ops)
macro.Add() call.Add(gtx.Ops)
stack.Pop() stack.Pop()
return Dimensions{ return Dimensions{
Size: sz, Size: sz,
+7 -7
View File
@@ -12,8 +12,8 @@ import (
) )
type scrollChild struct { type scrollChild struct {
size image.Point size image.Point
macro op.MacroOp call op.CallOp
} }
// List displays a subsection of a potentially infinitely // 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. // End the current child by specifying its dimensions.
func (l *List) end(dims Dimensions) { func (l *List) end(dims Dimensions) {
l.child.Stop() call := l.child.Stop()
child := scrollChild{dims.Size, l.child} child := scrollChild{dims.Size, call}
mainSize := axisMain(l.Axis, child.size) mainSize := axisMain(l.Axis, child.size)
l.maxSize += mainSize l.maxSize += mainSize
switch l.dir { switch l.dir {
@@ -260,7 +260,7 @@ func (l *List) layout() Dimensions {
stack := op.Push(ops) stack := op.Push(ops)
clip.Rect{Rect: FRect(r)}.Op(ops).Add(ops) clip.Rect{Rect: FRect(r)}.Op(ops).Add(ops)
op.TransformOp{}.Offset(FPt(axisPoint(l.Axis, pos, cross))).Add(ops) op.TransformOp{}.Offset(FPt(axisPoint(l.Axis, pos, cross))).Add(ops)
child.macro.Add() child.call.Add(ops)
stack.Pop() stack.Pop()
pos += childSize pos += childSize
} }
@@ -277,10 +277,10 @@ func (l *List) layout() Dimensions {
pos = mainMax pos = mainMax
} }
dims := axisPoint(l.Axis, pos, maxCross) dims := axisPoint(l.Axis, pos, maxCross)
l.macro.Stop() call := l.macro.Stop()
defer op.Push(l.ctx.Ops).Pop() defer op.Push(l.ctx.Ops).Pop()
pointer.Rect(image.Rectangle{Max: dims}).Add(ops) pointer.Rect(image.Rectangle{Max: dims}).Add(ops)
l.scroll.Add(ops) l.scroll.Add(ops)
l.macro.Add() call.Add(ops)
return Dimensions{Size: dims} return Dimensions{Size: dims}
} }
+7 -7
View File
@@ -22,8 +22,8 @@ type StackChild struct {
widget Widget widget Widget
// Scratch space. // Scratch space.
macro op.MacroOp call op.CallOp
dims Dimensions dims Dimensions
} }
// Stacked returns a Stack child that is laid out with no minimum // 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 := gtx
gtx.Constraints.Min = image.Pt(0, 0) gtx.Constraints.Min = image.Pt(0, 0)
dims := w.widget(gtx) dims := w.widget(gtx)
macro.Stop() call := macro.Stop()
if w := dims.Size.X; w > maxSZ.X { if w := dims.Size.X; w > maxSZ.X {
maxSZ.X = w maxSZ.X = w
} }
if h := dims.Size.Y; h > maxSZ.Y { if h := dims.Size.Y; h > maxSZ.Y {
maxSZ.Y = h maxSZ.Y = h
} }
children[i].macro = macro children[i].call = call
children[i].dims = dims children[i].dims = dims
} }
// Then lay out Expanded children. // Then lay out Expanded children.
@@ -79,14 +79,14 @@ func (s Stack) Layout(gtx Context, children ...StackChild) Dimensions {
Min: maxSZ, Max: gtx.Constraints.Max, Min: maxSZ, Max: gtx.Constraints.Max,
} }
dims := w.widget(gtx) dims := w.widget(gtx)
macro.Stop() call := macro.Stop()
if w := dims.Size.X; w > maxSZ.X { if w := dims.Size.X; w > maxSZ.X {
maxSZ.X = w maxSZ.X = w
} }
if h := dims.Size.Y; h > maxSZ.Y { if h := dims.Size.Y; h > maxSZ.Y {
maxSZ.Y = h maxSZ.Y = h
} }
children[i].macro = macro children[i].call = call
children[i].dims = dims children[i].dims = dims
} }
@@ -109,7 +109,7 @@ func (s Stack) Layout(gtx Context, children ...StackChild) Dimensions {
} }
stack := op.Push(gtx.Ops) stack := op.Push(gtx.Ops)
op.TransformOp{}.Offset(FPt(p)).Add(gtx.Ops) op.TransformOp{}.Offset(FPt(p)).Add(gtx.Ops)
ch.macro.Add() ch.call.Add(gtx.Ops)
stack.Pop() stack.Pop()
if baseline == 0 { if baseline == 0 {
if b := ch.dims.Baseline; b != 0 { if b := ch.dims.Baseline; b != 0 {
+4 -4
View File
@@ -35,12 +35,12 @@ type Path struct {
// 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 Op, use op.StackOp. // applying a Op, use op.StackOp.
type Op struct { type Op struct {
macro op.MacroOp call op.CallOp
bounds f32.Rectangle bounds f32.Rectangle
} }
func (p Op) Add(o *op.Ops) { func (p Op) Add(o *op.Ops) {
p.macro.Add() p.call.Add(o)
data := o.Write(opconst.TypeClipLen) data := o.Write(opconst.TypeClipLen)
data[0] = byte(opconst.TypeClip) data[0] = byte(opconst.TypeClip)
bo := binary.LittleEndian 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. // End the path and return a clip operation that represents it.
func (p *Path) End() Op { func (p *Path) End() Op {
p.end() p.end()
p.macro.Stop() c := p.macro.Stop()
return Op{ return Op{
macro: p.macro, call: c,
bounds: p.bounds, bounds: p.bounds,
} }
} }
+22 -32
View File
@@ -49,12 +49,6 @@ end of a function :
defer op.Push(ops).Pop() 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: The MacroOp records a list of operations to be executed later:
ops := new(op.Ops) ops := new(op.Ops)
@@ -63,10 +57,10 @@ The MacroOp records a list of operations to be executed later:
op.InvalidateOp{}.Add(ops) op.InvalidateOp{}.Add(ops)
... ...
// End recording. // End recording.
macro.Stop() call := macro.Stop()
// replay the recorded operations by calling Add: // replay the recorded operations:
macro.Add() call.Add(ops)
*/ */
package op package op
@@ -110,11 +104,11 @@ type MacroOp struct {
pc pc pc pc
} }
// CallOp invokes all the operations from a separate // CallOp invokes the operations recorded by Record.
// operations list.
type CallOp struct { type CallOp struct {
// Ops is the list of operations to invoke. // Ops is the list of operations to invoke.
Ops *Ops ops *Ops
pc pc
} }
// InvalidateOp requests a redraw at the given time. Use // InvalidateOp requests a redraw at the given time. Use
@@ -146,15 +140,6 @@ type pc struct {
refs int 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. // Push (save) the current operations state.
func Push(o *Ops) StackOp { func Push(o *Ops) StackOp {
s := StackOp{ s := StackOp{
@@ -224,38 +209,43 @@ func Record(o *Ops) MacroOp {
pc: o.pc(), pc: o.pc(),
} }
// Reserve room for a macro definition. Updated in Stop. // Reserve room for a macro definition. Updated in Stop.
m.ops.Write(opconst.TypeMacroDefLen) m.ops.Write(opconst.TypeMacroLen)
m.fill() m.fill()
return m return m
} }
// Stop ends a previously started recording. // Stop ends a previously started recording and returns an
func (m MacroOp) Stop() { // operation for replaying it.
func (m MacroOp) Stop() CallOp {
m.ops.macroStack.pop(m.id) m.ops.macroStack.pop(m.id)
m.fill() m.fill()
return CallOp{
ops: m.ops,
pc: m.pc,
}
} }
func (m MacroOp) fill() { func (m MacroOp) fill() {
pc := m.ops.pc() pc := m.ops.pc()
// Fill out the macro definition reserved in Record. // Fill out the macro definition reserved in Record.
data := m.ops.data[m.pc.data:] data := m.ops.data[m.pc.data:]
data = data[:opconst.TypeMacroDefLen] data = data[:opconst.TypeMacroLen]
data[0] = byte(opconst.TypeMacroDef) data[0] = byte(opconst.TypeMacro)
bo := binary.LittleEndian bo := binary.LittleEndian
bo.PutUint32(data[1:], uint32(pc.data)) bo.PutUint32(data[1:], uint32(pc.data))
bo.PutUint32(data[5:], uint32(pc.refs)) bo.PutUint32(data[5:], uint32(pc.refs))
} }
// Add the recorded list of operations. // Add the recorded list of operations.
func (m MacroOp) Add() { func (c CallOp) Add(o *Ops) {
if m.ops == nil { if c.ops == nil {
return return
} }
data := m.ops.Write(opconst.TypeMacroLen) data := o.Write(opconst.TypeCallLen, c.ops)
data[0] = byte(opconst.TypeMacro) data[0] = byte(opconst.TypeCall)
bo := binary.LittleEndian bo := binary.LittleEndian
bo.PutUint32(data[1:], uint32(m.pc.data)) bo.PutUint32(data[1:], uint32(c.pc.data))
bo.PutUint32(data[5:], uint32(m.pc.refs)) bo.PutUint32(data[5:], uint32(c.pc.refs))
} }
func (r InvalidateOp) Add(o *Ops) { func (r InvalidateOp) Add(o *Ops) {
+2 -2
View File
@@ -44,7 +44,7 @@ func (e EditorStyle) Layout(gtx layout.Context) layout.Dimensions {
paint.ColorOp{Color: e.HintColor}.Add(gtx.Ops) paint.ColorOp{Color: e.HintColor}.Add(gtx.Ops)
tl := widget.Label{Alignment: e.Editor.Alignment} tl := widget.Label{Alignment: e.Editor.Alignment}
dims := tl.Layout(gtx, e.shaper, e.Font, e.TextSize, e.Hint) 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 { if w := dims.Size.X; gtx.Constraints.Min.X < w {
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) paint.ColorOp{Color: e.Color}.Add(gtx.Ops)
e.Editor.PaintText(gtx) e.Editor.PaintText(gtx)
} else { } else {
macro.Add() call.Add(gtx.Ops)
} }
paint.ColorOp{Color: e.Color}.Add(gtx.Ops) paint.ColorOp{Color: e.Color}.Add(gtx.Ops)
e.Editor.PaintCaret(gtx) e.Editor.PaintCaret(gtx)