diff --git a/ui/app/internal/gpu/caches.go b/ui/app/internal/gpu/caches.go index 7b6f9559..4de57bfd 100644 --- a/ui/app/internal/gpu/caches.go +++ b/ui/app/internal/gpu/caches.go @@ -3,7 +3,7 @@ package gpu import ( "fmt" - "gioui.org/ui" + "gioui.org/ui/internal/ops" ) type resourceCache struct { @@ -11,11 +11,11 @@ type resourceCache struct { newRes map[interface{}]resource } -// opCache is like a resourceCache using the concrete OpKey +// opCache is like a resourceCache using the concrete Key // key type to avoid allocations. type opCache struct { - res map[ui.OpKey]resource - newRes map[ui.OpKey]resource + res map[ops.Key]resource + newRes map[ops.Key]resource } func newResourceCache() *resourceCache { @@ -64,12 +64,12 @@ func (r *resourceCache) release(ctx *context) { func newOpCache() *opCache { return &opCache{ - res: make(map[ui.OpKey]resource), - newRes: make(map[ui.OpKey]resource), + res: make(map[ops.Key]resource), + newRes: make(map[ops.Key]resource), } } -func (r *opCache) get(key ui.OpKey) (resource, bool) { +func (r *opCache) get(key ops.Key) (resource, bool) { v, exists := r.res[key] if exists { r.newRes[key] = v @@ -77,7 +77,7 @@ func (r *opCache) get(key ui.OpKey) (resource, bool) { return v, exists } -func (r *opCache) put(key ui.OpKey, val resource) { +func (r *opCache) put(key ops.Key, val resource) { if _, exists := r.newRes[key]; exists { panic(fmt.Errorf("key exists, %p", key)) } diff --git a/ui/app/internal/gpu/gpu.go b/ui/app/internal/gpu/gpu.go index d2a7da45..1f2521b6 100644 --- a/ui/app/internal/gpu/gpu.go +++ b/ui/app/internal/gpu/gpu.go @@ -16,6 +16,7 @@ import ( "gioui.org/ui/app/internal/gl" gdraw "gioui.org/ui/draw" "gioui.org/ui/f32" + "gioui.org/ui/internal/opconst" "gioui.org/ui/internal/ops" "golang.org/x/image/draw" ) @@ -58,7 +59,7 @@ type renderer struct { } type drawOps struct { - reader ui.OpsReader + reader ops.Reader cache *resourceCache viewport image.Point clearColor [3]float32 @@ -90,7 +91,7 @@ type pathOp struct { // clip is the union of all // later clip rectangles. clip image.Rectangle - pathKey ui.OpKey + pathKey ops.Key path bool pathVerts []byte parent *pathOp @@ -124,7 +125,7 @@ type opClip struct { } func (op *opClip) decode(data []byte) { - if ops.OpType(data[0]) != ops.TypeClip { + if opconst.OpType(data[0]) != opconst.TypeClip { panic("invalid op") } bo := binary.LittleEndian @@ -641,20 +642,20 @@ func (d *drawOps) newPathOp() *pathOp { return &d.pathOpCache[len(d.pathOpCache)-1] } -func (d *drawOps) collectOps(r *ui.OpsReader, state drawState) int { +func (d *drawOps) collectOps(r *ops.Reader, state drawState) int { var aux []byte - var auxKey ui.OpKey + var auxKey ops.Key loop: for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() { - switch ops.OpType(encOp.Data[0]) { - case ops.TypeTransform: + switch opconst.OpType(encOp.Data[0]) { + case opconst.TypeTransform: var op ui.TransformOp op.Decode(encOp.Data) state.t = state.t.Multiply(op) - case ops.TypeAux: - aux = encOp.Data[ops.TypeAuxLen:] + case opconst.TypeAux: + aux = encOp.Data[opconst.TypeAuxLen:] auxKey = encOp.Key - case ops.TypeClip: + case opconst.TypeClip: var op opClip op.decode(encOp.Data) off := state.t.Transform(f32.Point{}) @@ -676,18 +677,18 @@ loop: d.pathOps = append(d.pathOps, state.cpath) } aux = nil - auxKey = ui.OpKey{} - case ops.TypeColor: + auxKey = ops.Key{} + case opconst.TypeColor: var op gdraw.ColorOp op.Decode(encOp.Data, encOp.Refs) state.img = nil state.color = op.Color - case ops.TypeImage: + case opconst.TypeImage: var op gdraw.ImageOp op.Decode(encOp.Data, encOp.Refs) state.img = op.Src state.imgRect = op.Rect - case ops.TypeDraw: + case opconst.TypeDraw: var op gdraw.DrawOp op.Decode(encOp.Data, encOp.Refs) off := state.t.Transform(f32.Point{}) @@ -723,9 +724,9 @@ loop: } else { d.imageOps = append(d.imageOps, img) } - case ops.TypePush: + case opconst.TypePush: state.z = d.collectOps(r, state) - case ops.TypePop: + case opconst.TypePop: break loop } } diff --git a/ui/app/internal/input/key.go b/ui/app/internal/input/key.go index bbcd7fc2..252a7a70 100644 --- a/ui/app/internal/input/key.go +++ b/ui/app/internal/input/key.go @@ -5,6 +5,7 @@ package input import ( "gioui.org/ui" "gioui.org/ui/input" + "gioui.org/ui/internal/opconst" "gioui.org/ui/internal/ops" "gioui.org/ui/key" ) @@ -14,7 +15,7 @@ type TextInputState uint8 type keyQueue struct { focus input.Key handlers map[input.Key]*keyHandler - reader ui.OpsReader + reader ops.Reader state TextInputState } @@ -94,8 +95,8 @@ func (q *keyQueue) resolveFocus(events *handlerEvents) (input.Key, listenerPrior var hide bool loop: for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() { - switch ops.OpType(encOp.Data[0]) { - case ops.TypeKeyHandler: + switch opconst.OpType(encOp.Data[0]) { + case opconst.TypeKeyHandler: var op key.HandlerOp op.Decode(encOp.Data, encOp.Refs) var newPri listenerPriority @@ -119,15 +120,15 @@ loop: events.Set(op.Key, []input.Event{key.FocusEvent{Focus: false}}) } h.active = true - case ops.TypeHideInput: + case opconst.TypeHideInput: hide = true - case ops.TypePush: + case opconst.TypePush: newK, newPri, h := q.resolveFocus(events) hide = hide || h if newPri.replaces(pri) { k, pri = newK, newPri } - case ops.TypePop: + case opconst.TypePop: break loop } } diff --git a/ui/app/internal/input/pointer.go b/ui/app/internal/input/pointer.go index 9e761293..47175352 100644 --- a/ui/app/internal/input/pointer.go +++ b/ui/app/internal/input/pointer.go @@ -9,6 +9,7 @@ import ( "gioui.org/ui" "gioui.org/ui/f32" "gioui.org/ui/input" + "gioui.org/ui/internal/opconst" "gioui.org/ui/internal/ops" "gioui.org/ui/pointer" ) @@ -18,7 +19,7 @@ type pointerQueue struct { areas []areaNode handlers map[input.Key]*pointerHandler pointers []pointerInfo - reader ui.OpsReader + reader ops.Reader scratch []input.Key } @@ -63,18 +64,18 @@ const ( areaEllipse ) -func (q *pointerQueue) collectHandlers(r *ui.OpsReader, events *handlerEvents, t ui.TransformOp, area, node int, pass bool) { +func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t ui.TransformOp, area, node int, pass bool) { for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() { - switch ops.OpType(encOp.Data[0]) { - case ops.TypePush: + switch opconst.OpType(encOp.Data[0]) { + case opconst.TypePush: q.collectHandlers(r, events, t, area, node, pass) - case ops.TypePop: + case opconst.TypePop: return - case ops.TypePass: + case opconst.TypePass: var op pointer.PassOp op.Decode(encOp.Data) pass = op.Pass - case ops.TypeArea: + case opconst.TypeArea: var op areaOp op.Decode(encOp.Data) q.areas = append(q.areas, areaNode{trans: t, next: area, area: op}) @@ -85,11 +86,11 @@ func (q *pointerQueue) collectHandlers(r *ui.OpsReader, events *handlerEvents, t pass: pass, }) node = len(q.hitTree) - 1 - case ops.TypeTransform: + case opconst.TypeTransform: var op ui.TransformOp op.Decode(encOp.Data) t = t.Multiply(op) - case ops.TypePointerHandler: + case opconst.TypePointerHandler: var op pointer.HandlerOp op.Decode(encOp.Data, encOp.Refs) q.hitTree = append(q.hitTree, hitNode{ @@ -264,7 +265,7 @@ func (q *pointerQueue) Push(e pointer.Event, events *handlerEvents) { } func (op *areaOp) Decode(d []byte) { - if ops.OpType(d[0]) != ops.TypeArea { + if opconst.OpType(d[0]) != opconst.TypeArea { panic("invalid op") } bo := binary.LittleEndian diff --git a/ui/app/internal/input/router.go b/ui/app/internal/input/router.go index 912ad20e..e3171245 100644 --- a/ui/app/internal/input/router.go +++ b/ui/app/internal/input/router.go @@ -7,6 +7,7 @@ import ( "gioui.org/ui" "gioui.org/ui/input" + "gioui.org/ui/internal/opconst" "gioui.org/ui/internal/ops" "gioui.org/ui/key" "gioui.org/ui/pointer" @@ -21,7 +22,7 @@ type Router struct { handlers handlerEvents - reader ui.OpsReader + reader ops.Reader // InvalidateOp summary. wakeup bool @@ -71,15 +72,15 @@ func (q *Router) TextInputState() TextInputState { func (q *Router) collect() { for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() { - switch ops.OpType(encOp.Data[0]) { - case ops.TypeInvalidate: + switch opconst.OpType(encOp.Data[0]) { + case opconst.TypeInvalidate: var op ui.InvalidateOp op.Decode(encOp.Data) if !q.wakeup || op.At.Before(q.wakeupTime) { q.wakeup = true q.wakeupTime = op.At } - case ops.TypeProfile: + case opconst.TypeProfile: var op system.ProfileOp op.Decode(encOp.Data, encOp.Refs) q.profHandlers = append(q.profHandlers, op.Key) diff --git a/ui/draw/draw.go b/ui/draw/draw.go index 2ddb8159..fad9df5b 100644 --- a/ui/draw/draw.go +++ b/ui/draw/draw.go @@ -10,7 +10,7 @@ import ( "gioui.org/ui" "gioui.org/ui/f32" - "gioui.org/ui/internal/ops" + "gioui.org/ui/internal/opconst" ) type ImageOp struct { @@ -27,8 +27,8 @@ type DrawOp struct { } func (i ImageOp) Add(o *ui.Ops) { - data := make([]byte, ops.TypeImageLen) - data[0] = byte(ops.TypeImage) + data := make([]byte, opconst.TypeImageLen) + data[0] = byte(opconst.TypeImage) bo := binary.LittleEndian bo.PutUint32(data[1:], uint32(i.Rect.Min.X)) bo.PutUint32(data[5:], uint32(i.Rect.Min.Y)) @@ -39,7 +39,7 @@ func (i ImageOp) Add(o *ui.Ops) { func (i *ImageOp) Decode(data []byte, refs []interface{}) { bo := binary.LittleEndian - if ops.OpType(data[0]) != ops.TypeImage { + if opconst.OpType(data[0]) != opconst.TypeImage { panic("invalid op") } sr := image.Rectangle{ @@ -59,8 +59,8 @@ func (i *ImageOp) Decode(data []byte, refs []interface{}) { } func (c ColorOp) Add(o *ui.Ops) { - data := make([]byte, ops.TypeColorLen) - data[0] = byte(ops.TypeColor) + data := make([]byte, opconst.TypeColorLen) + data[0] = byte(opconst.TypeColor) data[1] = c.Color.R data[2] = c.Color.G data[3] = c.Color.B @@ -69,7 +69,7 @@ func (c ColorOp) Add(o *ui.Ops) { } func (c *ColorOp) Decode(data []byte, refs []interface{}) { - if ops.OpType(data[0]) != ops.TypeColor { + if opconst.OpType(data[0]) != opconst.TypeColor { panic("invalid op") } *c = ColorOp{ @@ -83,8 +83,8 @@ func (c *ColorOp) Decode(data []byte, refs []interface{}) { } func (d DrawOp) Add(o *ui.Ops) { - data := make([]byte, ops.TypeDrawLen) - data[0] = byte(ops.TypeDraw) + data := make([]byte, opconst.TypeDrawLen) + data[0] = byte(opconst.TypeDraw) bo := binary.LittleEndian bo.PutUint32(data[1:], math.Float32bits(d.Rect.Min.X)) bo.PutUint32(data[5:], math.Float32bits(d.Rect.Min.Y)) @@ -95,7 +95,7 @@ func (d DrawOp) Add(o *ui.Ops) { func (d *DrawOp) Decode(data []byte, refs []interface{}) { bo := binary.LittleEndian - if ops.OpType(data[0]) != ops.TypeDraw { + if opconst.OpType(data[0]) != opconst.TypeDraw { panic("invalid op") } r := f32.Rectangle{ diff --git a/ui/draw/path.go b/ui/draw/path.go index df6a3456..d2fa7f40 100644 --- a/ui/draw/path.go +++ b/ui/draw/path.go @@ -9,7 +9,7 @@ import ( "gioui.org/ui" "gioui.org/ui/f32" - "gioui.org/ui/internal/ops" + "gioui.org/ui/internal/opconst" "gioui.org/ui/internal/path" ) @@ -30,8 +30,8 @@ type ClipOp struct { } func (p ClipOp) Add(o *ui.Ops) { - data := make([]byte, ops.TypeClipLen) - data[0] = byte(ops.TypeClip) + data := make([]byte, opconst.TypeClipLen) + data[0] = byte(opconst.TypeClip) bo := binary.LittleEndian bo.PutUint32(data[1:], math.Float32bits(p.bounds.Min.X)) bo.PutUint32(data[5:], math.Float32bits(p.bounds.Min.Y)) @@ -239,7 +239,7 @@ func (p *PathBuilder) vertex(cornerx, cornery int16, ctrl, to f32.Point) { ToY: to.Y, } data := make([]byte, path.VertStride+1) - data[0] = byte(ops.TypeAux) + data[0] = byte(opconst.TypeAux) bo := binary.LittleEndian data[1] = byte(uint16(v.CornerX)) data[2] = byte(uint16(v.CornerX) >> 8) diff --git a/ui/internal/ops/ops.go b/ui/internal/opconst/ops.go similarity index 98% rename from ui/internal/ops/ops.go rename to ui/internal/opconst/ops.go index 0cb6fe02..c848cc9c 100644 --- a/ui/internal/ops/ops.go +++ b/ui/internal/opconst/ops.go @@ -1,4 +1,4 @@ -package ops +package opconst type OpType byte diff --git a/ui/internal/ops/reader.go b/ui/internal/ops/reader.go new file mode 100644 index 00000000..859d67e9 --- /dev/null +++ b/ui/internal/ops/reader.go @@ -0,0 +1,177 @@ +package ops + +import ( + "encoding/binary" + + "gioui.org/ui" + "gioui.org/ui/internal/opconst" +) + +// Reader parses an ops list. +type Reader struct { + pc pc + stack []macro + ops *ui.Ops +} + +// EncodedOp represents an encoded op returned by +// Reader. +type EncodedOp struct { + Key Key + Data []byte + Refs []interface{} +} + +// Key is a unique key for a given op. +type Key struct { + ops *ui.Ops + pc int + version int +} + +// Shadow of ui.MacroOp. +type macroOp struct { + recording bool + ops *ui.Ops + version int + pc pc +} + +type pc struct { + data int + refs int +} + +type macro struct { + ops *ui.Ops + retPC pc + endPC pc +} + +type opMacroDef struct { + endpc pc +} + +type opAux struct { + len int +} + +// Reset start reading from the op list. +func (r *Reader) Reset(ops *ui.Ops) { + r.stack = r.stack[:0] + r.pc = pc{} + r.ops = nil + if ops == nil { + return + } + r.ops = ops +} + +func (r *Reader) Decode() (EncodedOp, bool) { + if r.ops == nil { + return EncodedOp{}, false + } + for { + if len(r.stack) > 0 { + b := r.stack[len(r.stack)-1] + if r.pc == b.endPC { + r.ops = b.ops + r.pc = b.retPC + r.stack = r.stack[:len(r.stack)-1] + continue + } + } + if r.pc.data == len(r.ops.Data) { + return EncodedOp{}, false + } + key := Key{ops: r.ops, pc: r.pc.data, version: r.ops.Version} + t := opconst.OpType(r.ops.Data[r.pc.data]) + n := t.Size() + nrefs := t.NumRefs() + data := r.ops.Data[r.pc.data : r.pc.data+n] + refs := r.ops.Refs[r.pc.refs : r.pc.refs+nrefs] + switch t { + case opconst.TypeAux: + var op opAux + op.decode(data) + n += op.len + data = r.ops.Data[r.pc.data : r.pc.data+n] + case opconst.TypeMacro: + var op macroOp + op.decode(data, refs) + macroOps := op.ops + if opconst.OpType(macroOps.Data[op.pc.data]) != opconst.TypeMacroDef { + panic("invalid macro reference") + } + if op.version != op.ops.Version { + panic("invalid MacroOp reference to reset Ops") + } + var opDef opMacroDef + opDef.decode(macroOps.Data[op.pc.data : op.pc.data+opconst.TypeMacroDef.Size()]) + retPC := r.pc + retPC.data += n + retPC.refs += nrefs + r.stack = append(r.stack, macro{ + ops: r.ops, + retPC: retPC, + endPC: opDef.endpc, + }) + r.ops = macroOps + r.pc = op.pc + r.pc.data += opconst.TypeMacroDef.Size() + r.pc.refs += opconst.TypeMacroDef.NumRefs() + continue + case opconst.TypeMacroDef: + var op opMacroDef + op.decode(data) + r.pc = op.endpc + continue + } + r.pc.data += n + r.pc.refs += nrefs + return EncodedOp{Key: key, Data: data, Refs: refs}, true + } +} + +func (op *opMacroDef) decode(data []byte) { + if opconst.OpType(data[0]) != opconst.TypeMacroDef { + panic("invalid op") + } + bo := binary.LittleEndian + dataIdx := int(int32(bo.Uint32(data[1:]))) + refsIdx := int(int32(bo.Uint32(data[5:]))) + *op = opMacroDef{ + endpc: pc{ + data: dataIdx, + refs: refsIdx, + }, + } +} + +func (op *opAux) decode(data []byte) { + if opconst.OpType(data[0]) != opconst.TypeAux { + panic("invalid op") + } + bo := binary.LittleEndian + *op = opAux{ + len: int(int32(bo.Uint32(data[1:]))), + } +} + +func (m *macroOp) decode(data []byte, refs []interface{}) { + 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:]))) + version := int(int32(bo.Uint32(data[9:]))) + *m = macroOp{ + ops: refs[0].(*ui.Ops), + pc: pc{ + data: dataIdx, + refs: refsIdx, + }, + version: version, + } +} diff --git a/ui/key/key.go b/ui/key/key.go index 5c009a26..34c58cd4 100644 --- a/ui/key/key.go +++ b/ui/key/key.go @@ -5,7 +5,7 @@ package key import ( "gioui.org/ui" "gioui.org/ui/input" - "gioui.org/ui/internal/ops" + "gioui.org/ui/internal/opconst" ) type HandlerOp struct { @@ -56,8 +56,8 @@ func (m Modifiers) Contain(m2 Modifiers) bool { } func (h HandlerOp) Add(o *ui.Ops) { - data := make([]byte, ops.TypeKeyHandlerLen) - data[0] = byte(ops.TypeKeyHandler) + data := make([]byte, opconst.TypeKeyHandlerLen) + data[0] = byte(opconst.TypeKeyHandler) if h.Focus { data[1] = 1 } @@ -65,7 +65,7 @@ func (h HandlerOp) Add(o *ui.Ops) { } func (h *HandlerOp) Decode(d []byte, refs []interface{}) { - if ops.OpType(d[0]) != ops.TypeKeyHandler { + if opconst.OpType(d[0]) != opconst.TypeKeyHandler { panic("invalid op") } *h = HandlerOp{ @@ -75,8 +75,8 @@ func (h *HandlerOp) Decode(d []byte, refs []interface{}) { } func (h HideInputOp) Add(o *ui.Ops) { - data := make([]byte, ops.TypeHideInputLen) - data[0] = byte(ops.TypeHideInput) + data := make([]byte, opconst.TypeHideInputLen) + data[0] = byte(opconst.TypeHideInput) o.Write(data) } diff --git a/ui/ops.go b/ui/ops.go index 1f5eda0a..a00abf99 100644 --- a/ui/ops.go +++ b/ui/ops.go @@ -3,16 +3,16 @@ package ui import ( "encoding/binary" - "gioui.org/ui/internal/ops" + "gioui.org/ui/internal/opconst" ) // Ops holds a list of serialized Ops. type Ops struct { - version int + Version int // Serialized ops. - data []byte + Data []byte // Op references. - refs []interface{} + Refs []interface{} stackDepth int @@ -21,39 +21,6 @@ type Ops struct { auxLen int } -// OpsReader parses an ops list. Internal use only. -type OpsReader struct { - pc pc - stack []macro - ops *Ops -} - -// EncodedOp represents an encoded op returned by -// OpsReader. Internal use only. -type EncodedOp struct { - Key OpKey - Data []byte - Refs []interface{} -} - -// OpKey is a unique key for a given op. Internal use only. -type OpKey struct { - ops *Ops - pc int - version int -} - -type macro struct { - ops *Ops - retPC pc - endPC pc -} - -type pc struct { - data int - refs int -} - type StackOp struct { depth int active bool @@ -67,12 +34,9 @@ type MacroOp struct { pc pc } -type opMacroDef struct { - endpc pc -} - -type opAux struct { - len int +type pc struct { + data int + refs int } func (s *StackOp) Push(o *Ops) { @@ -83,7 +47,7 @@ func (s *StackOp) Push(o *Ops) { s.ops = o o.stackDepth++ s.depth = o.stackDepth - o.Write([]byte{byte(ops.TypePush)}) + o.Write([]byte{byte(opconst.TypePush)}) } func (s *StackOp) Pop() { @@ -96,32 +60,7 @@ func (s *StackOp) Pop() { } s.active = false s.ops.stackDepth-- - s.ops.Write([]byte{byte(ops.TypePop)}) -} - -func (op *opAux) decode(data []byte) { - if ops.OpType(data[0]) != ops.TypeAux { - panic("invalid op") - } - bo := binary.LittleEndian - *op = opAux{ - len: int(int32(bo.Uint32(data[1:]))), - } -} - -func (op *opMacroDef) decode(data []byte) { - if ops.OpType(data[0]) != ops.TypeMacroDef { - panic("invalid op") - } - bo := binary.LittleEndian - dataIdx := int(int32(bo.Uint32(data[1:]))) - refsIdx := int(int32(bo.Uint32(data[5:]))) - *op = opMacroDef{ - endpc: pc{ - data: dataIdx, - refs: refsIdx, - }, - } + s.ops.Write([]byte{byte(opconst.TypePop)}) } // Reset the Ops, preparing it for re-use. @@ -129,12 +68,12 @@ func (o *Ops) Reset() { o.inAux = false o.stackDepth = 0 // Leave references to the GC. - for i := range o.refs { - o.refs[i] = nil + for i := range o.Refs { + o.Refs[i] = nil } - o.data = o.data[:0] - o.refs = o.refs[:0] - o.version++ + o.Data = o.Data[:0] + o.Refs = o.Refs[:0] + o.Version++ } // Internal use only. @@ -142,29 +81,29 @@ func (o *Ops) Aux() []byte { if !o.inAux { return nil } - return o.data[o.auxOff+ops.TypeAuxLen : o.auxOff+ops.TypeAuxLen+o.auxLen] + return o.Data[o.auxOff+opconst.TypeAuxLen : o.auxOff+opconst.TypeAuxLen+o.auxLen] } func (d *Ops) write(op []byte, refs ...interface{}) { - d.data = append(d.data, op...) - d.refs = append(d.refs, refs...) + d.Data = append(d.Data, op...) + d.Refs = append(d.Refs, refs...) } func (o *Ops) Write(op []byte, refs ...interface{}) { - t := ops.OpType(op[0]) + t := opconst.OpType(op[0]) if len(refs) != t.NumRefs() { panic("invalid ref count") } switch t { - case ops.TypeAux: + case opconst.TypeAux: // Write only the data. op = op[1:] if !o.inAux { o.inAux = true o.auxOff = o.pc().data o.auxLen = 0 - header := make([]byte, ops.TypeAuxLen) - header[0] = byte(ops.TypeAux) + header := make([]byte, opconst.TypeAuxLen) + header[0] = byte(opconst.TypeAux) o.write(header) } o.auxLen += len(op) @@ -172,14 +111,14 @@ func (o *Ops) Write(op []byte, refs ...interface{}) { if o.inAux { o.inAux = false bo := binary.LittleEndian - bo.PutUint32(o.data[o.auxOff+1:], uint32(o.auxLen)) + bo.PutUint32(o.Data[o.auxOff+1:], uint32(o.auxLen)) } } o.write(op, refs...) } func (d *Ops) pc() pc { - return pc{data: len(d.data), refs: len(d.refs)} + return pc{data: len(d.Data), refs: len(d.Refs)} } // Record a macro of operations. @@ -191,7 +130,7 @@ func (m *MacroOp) Record(o *Ops) { m.ops = o m.pc = o.pc() // Make room for a macro definition. Filled out in Stop. - m.ops.Write(make([]byte, ops.TypeMacroDefLen)) + m.ops.Write(make([]byte, opconst.TypeMacroDefLen)) } // Stop recording the macro. @@ -202,30 +141,12 @@ func (m *MacroOp) Stop() { m.recording = false pc := m.ops.pc() // Fill out the macro definition reserved in Record. - data := m.ops.data[m.pc.data : m.pc.data+ops.TypeMacroDefLen] - data[0] = byte(ops.TypeMacroDef) + data := m.ops.Data[m.pc.data : m.pc.data+opconst.TypeMacroDefLen] + data[0] = byte(opconst.TypeMacroDef) bo := binary.LittleEndian bo.PutUint32(data[1:], uint32(pc.data)) bo.PutUint32(data[5:], uint32(pc.refs)) - m.version = m.ops.version -} - -func (m *MacroOp) decode(data []byte, refs []interface{}) { - if ops.OpType(data[0]) != ops.TypeMacro { - panic("invalid op") - } - bo := binary.LittleEndian - dataIdx := int(int32(bo.Uint32(data[1:]))) - refsIdx := int(int32(bo.Uint32(data[5:]))) - version := int(int32(bo.Uint32(data[9:]))) - *m = MacroOp{ - ops: refs[0].(*Ops), - pc: pc{ - data: dataIdx, - refs: refsIdx, - }, - version: version, - } + m.version = m.ops.Version } func (m MacroOp) Add(o *Ops) { @@ -235,88 +156,11 @@ func (m MacroOp) Add(o *Ops) { if m.ops == nil { return } - data := make([]byte, ops.TypeMacroLen) - data[0] = byte(ops.TypeMacro) + data := make([]byte, opconst.TypeMacroLen) + data[0] = byte(opconst.TypeMacro) bo := binary.LittleEndian bo.PutUint32(data[1:], uint32(m.pc.data)) bo.PutUint32(data[5:], uint32(m.pc.refs)) bo.PutUint32(data[9:], uint32(m.version)) o.Write(data, m.ops) } - -// Reset start reading from the op list. -func (r *OpsReader) Reset(ops *Ops) { - r.stack = r.stack[:0] - r.pc = pc{} - r.ops = nil - if ops == nil { - return - } - r.ops = ops -} - -func (r *OpsReader) Decode() (EncodedOp, bool) { - if r.ops == nil { - return EncodedOp{}, false - } - for { - if len(r.stack) > 0 { - b := r.stack[len(r.stack)-1] - if r.pc == b.endPC { - r.ops = b.ops - r.pc = b.retPC - r.stack = r.stack[:len(r.stack)-1] - continue - } - } - if r.pc.data == len(r.ops.data) { - return EncodedOp{}, false - } - key := OpKey{ops: r.ops, pc: r.pc.data, version: r.ops.version} - t := ops.OpType(r.ops.data[r.pc.data]) - n := t.Size() - nrefs := t.NumRefs() - data := r.ops.data[r.pc.data : r.pc.data+n] - refs := r.ops.refs[r.pc.refs : r.pc.refs+nrefs] - switch t { - case ops.TypeAux: - var op opAux - op.decode(data) - n += op.len - data = r.ops.data[r.pc.data : r.pc.data+n] - case ops.TypeMacro: - var op MacroOp - op.decode(data, refs) - macroOps := op.ops - if ops.OpType(macroOps.data[op.pc.data]) != ops.TypeMacroDef { - panic("invalid macro reference") - } - if op.version != op.ops.version { - panic("invalid MacroOp reference to reset Ops") - } - var opDef opMacroDef - opDef.decode(macroOps.data[op.pc.data : op.pc.data+ops.TypeMacroDef.Size()]) - retPC := r.pc - retPC.data += n - retPC.refs += nrefs - r.stack = append(r.stack, macro{ - ops: r.ops, - retPC: retPC, - endPC: opDef.endpc, - }) - r.ops = macroOps - r.pc = op.pc - r.pc.data += ops.TypeMacroDef.Size() - r.pc.refs += ops.TypeMacroDef.NumRefs() - continue - case ops.TypeMacroDef: - var op opMacroDef - op.decode(data) - r.pc = op.endpc - continue - } - r.pc.data += n - r.pc.refs += nrefs - return EncodedOp{Key: key, Data: data, Refs: refs}, true - } -} diff --git a/ui/pointer/pointer.go b/ui/pointer/pointer.go index 922a9588..2753dad7 100644 --- a/ui/pointer/pointer.go +++ b/ui/pointer/pointer.go @@ -10,7 +10,7 @@ import ( "gioui.org/ui" "gioui.org/ui/f32" "gioui.org/ui/input" - "gioui.org/ui/internal/ops" + "gioui.org/ui/internal/opconst" ) type Event struct { @@ -95,8 +95,8 @@ func (op EllipseAreaOp) Add(ops *ui.Ops) { } func (op areaOp) add(o *ui.Ops) { - data := make([]byte, ops.TypeAreaLen) - data[0] = byte(ops.TypeArea) + data := make([]byte, opconst.TypeAreaLen) + data[0] = byte(opconst.TypeArea) data[1] = byte(op.kind) bo := binary.LittleEndian bo.PutUint32(data[2:], uint32(op.rect.Min.X)) @@ -107,8 +107,8 @@ func (op areaOp) add(o *ui.Ops) { } func (h HandlerOp) Add(o *ui.Ops) { - data := make([]byte, ops.TypePointerHandlerLen) - data[0] = byte(ops.TypePointerHandler) + data := make([]byte, opconst.TypePointerHandlerLen) + data[0] = byte(opconst.TypePointerHandler) if h.Grab { data[1] = 1 } @@ -116,7 +116,7 @@ func (h HandlerOp) Add(o *ui.Ops) { } func (h *HandlerOp) Decode(d []byte, refs []interface{}) { - if ops.OpType(d[0]) != ops.TypePointerHandler { + if opconst.OpType(d[0]) != opconst.TypePointerHandler { panic("invalid op") } *h = HandlerOp{ @@ -126,8 +126,8 @@ func (h *HandlerOp) Decode(d []byte, refs []interface{}) { } func (op PassOp) Add(o *ui.Ops) { - data := make([]byte, ops.TypePassLen) - data[0] = byte(ops.TypePass) + data := make([]byte, opconst.TypePassLen) + data[0] = byte(opconst.TypePass) if op.Pass { data[1] = 1 } @@ -135,7 +135,7 @@ func (op PassOp) Add(o *ui.Ops) { } func (op *PassOp) Decode(d []byte) { - if ops.OpType(d[0]) != ops.TypePass { + if opconst.OpType(d[0]) != opconst.TypePass { panic("invalid op") } *op = PassOp{ diff --git a/ui/system/system.go b/ui/system/system.go index 51c22766..71c5615e 100644 --- a/ui/system/system.go +++ b/ui/system/system.go @@ -7,7 +7,7 @@ package system import ( "gioui.org/ui" "gioui.org/ui/input" - "gioui.org/ui/internal/ops" + "gioui.org/ui/internal/opconst" ) // ProfileOp registers a handler for receiving @@ -24,13 +24,13 @@ type ProfileEvent struct { } func (p ProfileOp) Add(o *ui.Ops) { - data := make([]byte, ops.TypeProfileLen) - data[0] = byte(ops.TypeProfile) + data := make([]byte, opconst.TypeProfileLen) + data[0] = byte(opconst.TypeProfile) o.Write(data, p.Key) } func (p *ProfileOp) Decode(d []byte, refs []interface{}) { - if ops.OpType(d[0]) != ops.TypeProfile { + if opconst.OpType(d[0]) != opconst.TypeProfile { panic("invalid op") } *p = ProfileOp{ diff --git a/ui/ui.go b/ui/ui.go index f743e075..92174097 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -8,7 +8,7 @@ import ( "time" "gioui.org/ui/f32" - "gioui.org/ui/internal/ops" + "gioui.org/ui/internal/opconst" ) // Config represents the essential configuration for @@ -33,8 +33,8 @@ type TransformOp struct { } func (r InvalidateOp) Add(o *Ops) { - data := make([]byte, ops.TypeRedrawLen) - data[0] = byte(ops.TypeInvalidate) + data := make([]byte, opconst.TypeRedrawLen) + data[0] = byte(opconst.TypeInvalidate) bo := binary.LittleEndian // UnixNano cannot represent the zero time. if t := r.At; !t.IsZero() { @@ -48,7 +48,7 @@ func (r InvalidateOp) Add(o *Ops) { func (r *InvalidateOp) Decode(d []byte) { bo := binary.LittleEndian - if ops.OpType(d[0]) != ops.TypeInvalidate { + if opconst.OpType(d[0]) != opconst.TypeInvalidate { panic("invalid op") } if nanos := bo.Uint64(d[1:]); nanos > 0 { @@ -79,8 +79,8 @@ func (t TransformOp) Multiply(t2 TransformOp) TransformOp { } func (t TransformOp) Add(o *Ops) { - data := make([]byte, ops.TypeTransformLen) - data[0] = byte(ops.TypeTransform) + data := make([]byte, opconst.TypeTransformLen) + data[0] = byte(opconst.TypeTransform) bo := binary.LittleEndian bo.PutUint32(data[1:], math.Float32bits(t.offset.X)) bo.PutUint32(data[5:], math.Float32bits(t.offset.Y)) @@ -89,7 +89,7 @@ func (t TransformOp) Add(o *Ops) { func (t *TransformOp) Decode(d []byte) { bo := binary.LittleEndian - if ops.OpType(d[0]) != ops.TypeTransform { + if opconst.OpType(d[0]) != opconst.TypeTransform { panic("invalid op") } *t = TransformOp{f32.Point{