diff --git a/ui/app/internal/gpu/gpu.go b/ui/app/internal/gpu/gpu.go index 58693eb3..9f9f6bd0 100644 --- a/ui/app/internal/gpu/gpu.go +++ b/ui/app/internal/gpu/gpu.go @@ -56,7 +56,7 @@ type renderer struct { } type drawOps struct { - reader ops.Reader + reader ui.OpsReader cache *resourceCache viewport image.Point clearColor [3]float32 @@ -651,7 +651,7 @@ func (d *drawOps) collect(cache *resourceCache, root *ui.Ops, viewport image.Poi clip := f32.Rectangle{ Max: f32.Point{X: float32(viewport.X), Y: float32(viewport.Y)}, } - d.reader.Reset(root.Data(), root.Refs()) + d.reader.Reset(root) state := drawState{ clip: clip, rect: true, @@ -664,7 +664,7 @@ func (d *drawOps) newPathOp() *pathOp { return &d.pathOpCache[len(d.pathOpCache)-1] } -func (d *drawOps) collectOps(r *ops.Reader, state drawState) int { +func (d *drawOps) collectOps(r *ui.OpsReader, state drawState) int { loop: for { data, ok := r.Decode() diff --git a/ui/app/window.go b/ui/app/window.go index 71533ee3..60365c52 100644 --- a/ui/app/window.go +++ b/ui/app/window.go @@ -46,7 +46,7 @@ type Window struct { nextFrame time.Time delayedDraw *time.Timer - reader ops.Reader + reader ui.OpsReader } // driver is the interface for the platform implementation @@ -144,7 +144,7 @@ func (w *Window) Draw(root *ui.Ops) { w.timings = fmt.Sprintf("tot:%7s cpu:%7s %s", frameDur.Round(q), drawDur.Round(q), w.gpu.Timings()) w.setNextFrame(time.Time{}) } - w.reader.Reset(root.Data(), root.Refs()) + w.reader.Reset(root) if t, ok := collectRedraws(&w.reader); ok { w.setNextFrame(t) } @@ -152,7 +152,7 @@ func (w *Window) Draw(root *ui.Ops) { w.gpu.Draw(w.Profiling, size, root) } -func collectRedraws(r *ops.Reader) (time.Time, bool) { +func collectRedraws(r *ui.OpsReader) (time.Time, bool) { var t time.Time redraw := false for { diff --git a/ui/internal/ops/ops.go b/ui/internal/ops/ops.go index 8f0cff96..481f81aa 100644 --- a/ui/internal/ops/ops.go +++ b/ui/internal/ops/ops.go @@ -1,23 +1,5 @@ package ops -import ( - "encoding/binary" -) - -type Reader struct { - pc int - stack []block - Refs []interface{} - data []byte - - pseudoOp [1]byte -} - -type block struct { - retPC int - endPC int -} - type OpType byte const ( @@ -53,66 +35,3 @@ const ( TypePushLen = 1 TypePopLen = 1 ) - -var typeLengths = [...]int{ - TypeBlockDefLen, - TypeBlockLen, - TypeTransformLen, - TypeLayerLen, - TypeRedrawLen, - TypeClipLen, - TypeImageLen, - TypeDrawLen, - TypeColorLen, - TypePointerHandlerLen, - TypeKeyHandlerLen, - TypeHideInputLen, - TypePushLen, - TypePopLen, -} - -// Reset start reading from the op list. -func (r *Reader) Reset(data []byte, refs []interface{}) { - r.Refs = refs - r.data = data - r.stack = r.stack[:0] - r.pc = 0 -} - -func (r *Reader) Decode() ([]byte, bool) { - bo := binary.LittleEndian - for { - if r.pc == len(r.data) { - return nil, false - } - if len(r.stack) > 0 { - b := r.stack[len(r.stack)-1] - if r.pc == b.endPC { - r.pc = b.retPC - r.stack = r.stack[:len(r.stack)-1] - r.pseudoOp[0] = byte(TypePop) - return r.pseudoOp[:], true - } - } - t := OpType(r.data[r.pc]) - n := typeLengths[t] - data := r.data[r.pc : r.pc+n] - switch t { - case TypeBlock: - blockIdx := int(bo.Uint32(data[1:])) - if OpType(r.data[blockIdx]) != TypeBlockDef { - panic("invalid block reference") - } - blockLen := int(bo.Uint32(r.data[blockIdx+1:])) - r.stack = append(r.stack, block{r.pc + n, blockIdx + blockLen}) - r.pc = blockIdx + TypeBlockDefLen - r.pseudoOp[0] = byte(TypePush) - return r.pseudoOp[:], true - case TypeBlockDef: - r.pc += int(bo.Uint32(data[1:])) - continue - } - r.pc += n - return data, true - } -} diff --git a/ui/key/queue.go b/ui/key/queue.go index 0ed02817..2727b3eb 100644 --- a/ui/key/queue.go +++ b/ui/key/queue.go @@ -11,7 +11,7 @@ type Queue struct { focus Key events []Event handlers map[Key]bool - reader ops.Reader + reader ui.OpsReader } type listenerPriority uint8 @@ -25,7 +25,7 @@ const ( func (q *Queue) Frame(root *ui.Ops) TextInputState { q.events = q.events[:0] - q.reader.Reset(root.Data(), root.Refs()) + q.reader.Reset(root) f, pri, hide := resolveFocus(&q.reader, q.focus) changed := f != nil && f != q.focus for k, active := range q.handlers { @@ -74,7 +74,7 @@ func (q *Queue) For(k Key) []Event { return q.events } -func resolveFocus(r *ops.Reader, focus Key) (Key, listenerPriority, bool) { +func resolveFocus(r *ui.OpsReader, focus Key) (Key, listenerPriority, bool) { var k Key var pri listenerPriority var hide bool diff --git a/ui/ops.go b/ui/ops.go index fac6cf3c..3c2ec380 100644 --- a/ui/ops.go +++ b/ui/ops.go @@ -6,7 +6,7 @@ import ( "gioui.org/ui/internal/ops" ) -// Ops hold a list of serialized Ops. +// Ops holds a list of serialized Ops. type Ops struct { // Stack of block start indices. stack []int @@ -16,6 +16,37 @@ type Ops struct { refs []interface{} } +type OpsReader struct { + pc int + stack []block + Refs []interface{} + data []byte + + pseudoOp [1]byte +} + +type block struct { + retPC int + endPC int +} + +var typeLengths = [...]int{ + ops.TypeBlockDefLen, + ops.TypeBlockLen, + ops.TypeTransformLen, + ops.TypeLayerLen, + ops.TypeRedrawLen, + ops.TypeClipLen, + ops.TypeImageLen, + ops.TypeDrawLen, + ops.TypeColorLen, + ops.TypePointerHandlerLen, + ops.TypeKeyHandlerLen, + ops.TypeHideInputLen, + ops.TypePushLen, + ops.TypePopLen, +} + type OpBlock struct { idx int } @@ -46,14 +77,6 @@ func (o *Ops) Reset() { o.data = o.data[:0] } -func (o *Ops) Refs() []interface{} { - return o.refs -} - -func (o *Ops) Data() []byte { - return o.data -} - func (o *Ops) Ref(r interface{}) int { o.refs = append(o.refs, r) return len(o.refs) - 1 @@ -75,3 +98,49 @@ func (b OpBlock) Add(o *Ops) { bo.PutUint32(data[1:], uint32(b.idx)) o.Write(data) } + +// Reset start reading from the op list. +func (r *OpsReader) Reset(ops *Ops) { + r.Refs = ops.refs + r.data = ops.data + r.stack = r.stack[:0] + r.pc = 0 +} + +func (r *OpsReader) Decode() ([]byte, bool) { + bo := binary.LittleEndian + for { + if r.pc == len(r.data) { + return nil, false + } + if len(r.stack) > 0 { + b := r.stack[len(r.stack)-1] + if r.pc == b.endPC { + r.pc = b.retPC + r.stack = r.stack[:len(r.stack)-1] + r.pseudoOp[0] = byte(ops.TypePop) + return r.pseudoOp[:], true + } + } + t := ops.OpType(r.data[r.pc]) + n := typeLengths[t] + data := r.data[r.pc : r.pc+n] + switch t { + case ops.TypeBlock: + blockIdx := int(bo.Uint32(data[1:])) + if ops.OpType(r.data[blockIdx]) != ops.TypeBlockDef { + panic("invalid block reference") + } + blockLen := int(bo.Uint32(r.data[blockIdx+1:])) + r.stack = append(r.stack, block{r.pc + n, blockIdx + blockLen}) + r.pc = blockIdx + ops.TypeBlockDefLen + r.pseudoOp[0] = byte(ops.TypePush) + return r.pseudoOp[:], true + case ops.TypeBlockDef: + r.pc += int(bo.Uint32(data[1:])) + continue + } + r.pc += n + return data, true + } +} diff --git a/ui/pointer/queue.go b/ui/pointer/queue.go index 28f0bc0c..ef22218a 100644 --- a/ui/pointer/queue.go +++ b/ui/pointer/queue.go @@ -12,7 +12,7 @@ type Queue struct { hitTree []hitNode handlers map[Key]*handler pointers []pointerInfo - reader ops.Reader + reader ui.OpsReader scratch []Key } @@ -37,7 +37,7 @@ type handler struct { wantsGrab bool } -func (q *Queue) collectHandlers(r *ops.Reader, t ui.Transform, layer int) { +func (q *Queue) collectHandlers(r *ui.OpsReader, t ui.Transform, layer int) { for { data, ok := r.Decode() if !ok { @@ -116,7 +116,7 @@ func (q *Queue) Frame(root *ui.Ops) { } } q.hitTree = q.hitTree[:0] - q.reader.Reset(root.Data(), root.Refs()) + q.reader.Reset(root) q.collectHandlers(&q.reader, ui.Transform{}, 0) }