M internal/opconst/ops.go => internal/opconst/ops.go +4 -1
@@ 26,6 26,7 @@ const (
TypeAux
TypeClip
TypeProfile
+ TypeCall
)
const (
@@ 47,6 48,7 @@ const (
TypeAuxLen = 1
TypeClipLen = 1 + 4*4
TypeProfileLen = 1
+ TypeCallLen = 1
)
func (t OpType) Size() int {
@@ 69,12 71,13 @@ func (t OpType) Size() int {
TypeAuxLen,
TypeClipLen,
TypeProfileLen,
+ TypeCallLen,
}[t-firstOpIndex]
}
func (t OpType) NumRefs() int {
switch t {
- case TypeMacro, TypeKeyInput, TypePointerInput, TypeProfile:
+ case TypeMacro, TypeKeyInput, TypePointerInput, TypeProfile, TypeCall:
return 1
case TypeImage:
return 2
M internal/ops/reader.go => internal/ops/reader.go +32 -0
@@ 38,6 38,11 @@ type macroOp struct {
pc pc
}
+// Shadow of op.CallOp.
+type callOp struct {
+ ops *op.Ops
+}
+
type pc struct {
data int
refs int
@@ 94,6 99,24 @@ func (r *Reader) Decode() (EncodedOp, bool) {
block := r.stack[len(r.stack)-1]
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, refs)
@@ 148,6 171,15 @@ func (op *opMacroDef) decode(data []byte) {
}
}
+func (m *callOp) 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, refs []interface{}) {
if opconst.OpType(data[0]) != opconst.TypeMacro {
panic("invalid op")
M op/op.go => op/op.go +22 -0
@@ 45,6 45,12 @@ The StackOp saves the current state to the state stack and restores it later:
// Restore the previous transform.
stack.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)
@@ 105,6 111,13 @@ type MacroOp struct {
pc pc
}
+// CallOp invokes all the operations from a separate
+// operations list.
+type CallOp struct {
+ // Ops is the list of operations to invoke.
+ Ops *Ops
+}
+
// InvalidateOp requests a redraw at the given time. Use
// the zero value to request an immediate redraw.
type InvalidateOp struct {
@@ 134,6 147,15 @@ 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 (s *StackOp) Push(o *Ops) {
if s.active {