~eliasnaur/gio

5966aab77e87d1d1b46f7fd21830511face44859 — Elias Naur 2 years ago 528a588
ui: move ops reader to ui package

To prepare support for cached OpBlock to refer to other Ops lists.

The exposure of OpsReader is alleviated by the removal of the Refs
and Data accessors for Ops.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
M ui/app/internal/gpu/gpu.go => ui/app/internal/gpu/gpu.go +3 -3
@@ 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()

M ui/app/window.go => ui/app/window.go +3 -3
@@ 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 {

M ui/internal/ops/ops.go => ui/internal/ops/ops.go +0 -81
@@ 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
	}
}

M ui/key/queue.go => ui/key/queue.go +3 -3
@@ 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

M ui/ops.go => ui/ops.go +78 -9
@@ 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
	}
}

M ui/pointer/queue.go => ui/pointer/queue.go +3 -3
@@ 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)
}