~eliasnaur/gio

0d2cffe1968819bf84e3f3c88464e3e4d011ef7a — Elias Naur 2 years ago 5966aab
ui: let OpsReader keep track of references

Instead of exposing the entire reference slice, return the relevant
references from Next.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
M ui/app/internal/gpu/gpu.go => ui/app/internal/gpu/gpu.go +5 -5
@@ 667,7 667,7 @@ func (d *drawOps) newPathOp() *pathOp {
func (d *drawOps) collectOps(r *ui.OpsReader, state drawState) int {
loop:
	for {
		data, ok := r.Decode()
		data, refs, ok := r.Decode()
		if !ok {
			break
		}


@@ 678,7 678,7 @@ loop:
			state.t = state.t.Mul(op.Transform)
		case ops.TypeClip:
			var op gdraw.OpClip
			op.Decode(data, r.Refs)
			op.Decode(data, refs)
			if op.Path == nil {
				state.clip = f32.Rectangle{}
				continue


@@ 702,17 702,17 @@ loop:
			}
		case ops.TypeColor:
			var op gdraw.OpColor
			op.Decode(data, r.Refs)
			op.Decode(data, refs)
			state.img = nil
			state.color = op.Col
		case ops.TypeImage:
			var op gdraw.OpImage
			op.Decode(data, r.Refs)
			op.Decode(data, refs)
			state.img = op.Img
			state.imgRect = op.Rect
		case ops.TypeDraw:
			var op gdraw.OpDraw
			op.Decode(data, r.Refs)
			op.Decode(data, refs)
			off := state.t.Transform(f32.Point{})
			clip := state.clip.Intersect(op.Rect.Add(off))
			if clip.Empty() {

M ui/app/window.go => ui/app/window.go +1 -1
@@ 156,7 156,7 @@ func collectRedraws(r *ui.OpsReader) (time.Time, bool) {
	var t time.Time
	redraw := false
	for {
		data, ok := r.Decode()
		data, _, ok := r.Decode()
		if !ok {
			break
		}

M ui/draw/draw.go => ui/draw/draw.go +12 -15
@@ 31,13 31,11 @@ func (i OpImage) Add(o *ui.Ops) {
	data := make([]byte, ops.TypeImageLen)
	data[0] = byte(ops.TypeImage)
	bo := binary.LittleEndian
	ref := o.Ref(i.Img)
	bo.PutUint32(data[1:], uint32(ref))
	bo.PutUint32(data[5:], uint32(i.Rect.Min.X))
	bo.PutUint32(data[9:], uint32(i.Rect.Min.Y))
	bo.PutUint32(data[13:], uint32(i.Rect.Max.X))
	bo.PutUint32(data[17:], uint32(i.Rect.Max.Y))
	o.Write(data)
	bo.PutUint32(data[1:], uint32(i.Rect.Min.X))
	bo.PutUint32(data[5:], uint32(i.Rect.Min.Y))
	bo.PutUint32(data[9:], uint32(i.Rect.Max.X))
	bo.PutUint32(data[13:], uint32(i.Rect.Max.Y))
	o.Write(data, []interface{}{i.Img})
}

func (i *OpImage) Decode(data []byte, refs []interface{}) {


@@ 45,19 43,18 @@ func (i *OpImage) Decode(data []byte, refs []interface{}) {
	if ops.OpType(data[0]) != ops.TypeImage {
		panic("invalid op")
	}
	ref := int(bo.Uint32(data[1:]))
	sr := image.Rectangle{
		Min: image.Point{
			X: int(bo.Uint32(data[5:])),
			Y: int(bo.Uint32(data[9:])),
			X: int(bo.Uint32(data[1:])),
			Y: int(bo.Uint32(data[5:])),
		},
		Max: image.Point{
			X: int(bo.Uint32(data[13:])),
			Y: int(bo.Uint32(data[17:])),
			X: int(bo.Uint32(data[9:])),
			Y: int(bo.Uint32(data[13:])),
		},
	}
	*i = OpImage{
		Img:  refs[ref].(image.Image),
		Img:  refs[0].(image.Image),
		Rect: sr,
	}
}


@@ 69,7 66,7 @@ func (c OpColor) Add(o *ui.Ops) {
	data[2] = c.Col.G
	data[3] = c.Col.B
	data[4] = c.Col.A
	o.Write(data)
	o.Write(data, nil)
}

func (c *OpColor) Decode(data []byte, refs []interface{}) {


@@ 94,7 91,7 @@ func (d OpDraw) Add(o *ui.Ops) {
	bo.PutUint32(data[5:], math.Float32bits(d.Rect.Min.Y))
	bo.PutUint32(data[9:], math.Float32bits(d.Rect.Max.X))
	bo.PutUint32(data[13:], math.Float32bits(d.Rect.Max.Y))
	o.Write(data)
	o.Write(data, nil)
}

func (d *OpDraw) Decode(data []byte, refs []interface{}) {

M ui/draw/path.go => ui/draw/path.go +2 -8
@@ 3,7 3,6 @@
package draw

import (
	"encoding/binary"
	"math"

	"gioui.org/ui"


@@ 37,20 36,15 @@ func (p *Path) Data() interface{} {
func (c OpClip) Add(o *ui.Ops) {
	data := make([]byte, ops.TypeClipLen)
	data[0] = byte(ops.TypeClip)
	bo := binary.LittleEndian
	ref := o.Ref(c.Path)
	bo.PutUint32(data[1:], uint32(ref))
	o.Write(data)
	o.Write(data, []interface{}{c.Path})
}

func (c *OpClip) Decode(d []byte, refs []interface{}) {
	bo := binary.LittleEndian
	if ops.OpType(d[0]) != ops.TypeClip {
		panic("invalid op")
	}
	ref := int(bo.Uint32(d[1:]))
	*c = OpClip{
		Path: refs[ref].(*Path),
		Path: refs[0].(*Path),
	}
}


M ui/internal/ops/ops.go => ui/internal/ops/ops.go +25 -7
@@ 2,8 2,11 @@ package ops

type OpType byte

// Start at a high number for easier debugging.
const FirstOpIndex = 200

const (
	TypeBlockDef OpType = iota
	TypeBlockDef OpType = iota + FirstOpIndex
	TypeBlock
	TypeTransform
	TypeLayer


@@ 20,18 23,33 @@ const (
)

const (
	TypeBlockDefLen       = 1 + 4
	TypeBlockLen          = 1 + 4
	TypeBlockDefLen       = 1 + 4 + 4
	TypeBlockLen          = 1 + 4 + 4
	TypeTransformLen      = 1 + 4*2
	TypeLayerLen          = 1
	TypeRedrawLen         = 1 + 8
	TypeClipLen           = 1 + 4
	TypeImageLen          = 1 + 4 + 4*4
	TypeClipLen           = 1
	TypeImageLen          = 1 + 4*4
	TypeDrawLen           = 1 + 4*4
	TypeColorLen          = 1 + 4
	TypePointerHandlerLen = 1 + 4 + 4 + 1
	TypeKeyHandlerLen     = 1 + 4 + 1
	TypePointerHandlerLen = 1 + 1
	TypeKeyHandlerLen     = 1 + 1
	TypeHideInputLen      = 1
	TypePushLen           = 1
	TypePopLen            = 1

	TypeBlockDefRefs       = 0
	TypeBlockRefs          = 0
	TypeTransformRefs      = 0
	TypeLayerRefs          = 0
	TypeRedrawRefs         = 0
	TypeClipRefs           = 1
	TypeImageRefs          = 1
	TypeDrawRefs           = 0
	TypeColorRefs          = 0
	TypePointerHandlerRefs = 2
	TypeKeyHandlerRefs     = 1
	TypeHideInputRefs      = 0
	TypePushRefs           = 0
	TypePopRefs            = 0
)

M ui/key/key.go => ui/key/key.go +3 -9
@@ 3,8 3,6 @@
package key

import (
	"encoding/binary"

	"gioui.org/ui"
	"gioui.org/ui/internal/ops"
)


@@ 73,30 71,26 @@ const (
func (h OpHandler) Add(o *ui.Ops) {
	data := make([]byte, ops.TypeKeyHandlerLen)
	data[0] = byte(ops.TypeKeyHandler)
	bo := binary.LittleEndian
	if h.Focus {
		data[1] = 1
	}
	bo.PutUint32(data[2:], uint32(o.Ref(h.Key)))
	o.Write(data)
	o.Write(data, []interface{}{h.Key})
}

func (h *OpHandler) Decode(d []byte, refs []interface{}) {
	bo := binary.LittleEndian
	if ops.OpType(d[0]) != ops.TypeKeyHandler {
		panic("invalid op")
	}
	key := int(bo.Uint32(d[2:]))
	*h = OpHandler{
		Focus: d[1] != 0,
		Key:   refs[key].(Key),
		Key:   refs[0].(Key),
	}
}

func (h OpHideInput) Add(o *ui.Ops) {
	data := make([]byte, ops.TypeHideInputLen)
	data[0] = byte(ops.TypeHideInput)
	o.Write(data)
	o.Write(data, nil)
}

func (Edit) ImplementsEvent()  {}

M ui/key/queue.go => ui/key/queue.go +2 -2
@@ 80,14 80,14 @@ func resolveFocus(r *ui.OpsReader, focus Key) (Key, listenerPriority, bool) {
	var hide bool
loop:
	for {
		data, ok := r.Decode()
		data, refs, ok := r.Decode()
		if !ok {
			break
		}
		switch ops.OpType(data[0]) {
		case ops.TypeKeyHandler:
			var op OpHandler
			op.Decode(data, r.Refs)
			op.Decode(data, refs)
			var newPri listenerPriority
			switch {
			case op.Focus:

M ui/ops.go => ui/ops.go +107 -41
@@ 9,7 9,7 @@ import (
// Ops holds a list of serialized Ops.
type Ops struct {
	// Stack of block start indices.
	stack []int
	stack []pc
	// Serialized ops.
	data []byte
	// Op references.


@@ 17,17 17,22 @@ type Ops struct {
}

type OpsReader struct {
	pc    int
	pc    pc
	stack []block
	Refs  []interface{}
	refs  []interface{}
	data  []byte

	pseudoOp [1]byte
}

type block struct {
	retPC int
	endPC int
	retPC pc
	endPC pc
}

type pc struct {
	data int
	refs int
}

var typeLengths = [...]int{


@@ 47,16 52,51 @@ var typeLengths = [...]int{
	ops.TypePopLen,
}

var refLengths = [...]int{
	ops.TypeBlockDefRefs,
	ops.TypeBlockRefs,
	ops.TypeTransformRefs,
	ops.TypeLayerRefs,
	ops.TypeRedrawRefs,
	ops.TypeClipRefs,
	ops.TypeImageRefs,
	ops.TypeDrawRefs,
	ops.TypeColorRefs,
	ops.TypePointerHandlerRefs,
	ops.TypeKeyHandlerRefs,
	ops.TypeHideInputRefs,
	ops.TypePushRefs,
	ops.TypePopRefs,
}

type OpBlock struct {
	idx int
	pc pc
}

type opBlockDef struct {
	endpc pc
}

// Begin a block of ops.
func (o *Ops) Begin() {
	o.stack = append(o.stack, o.Size())
	data := make([]byte, ops.TypeBlockDefLen)
	data[0] = byte(ops.TypeBlockDef)
	o.Write(data)
	o.stack = append(o.stack, o.pc())
	// Make room for a block definition. Filled out in End.
	o.data = append(o.data, make([]byte, ops.TypeBlockDefLen)...)
}

func (op *opBlockDef) decode(data []byte) {
	if ops.OpType(data[0]) != ops.TypeBlockDef {
		panic("invalid op")
	}
	bo := binary.LittleEndian
	dataIdx := int(bo.Uint32(data[1:]))
	refsIdx := int(bo.Uint32(data[5:]))
	*op = opBlockDef{
		endpc: pc{
			data: dataIdx,
			refs: refsIdx,
		},
	}
}

// End the most recent block and return


@@ 64,9 104,13 @@ func (o *Ops) Begin() {
func (o *Ops) End() OpBlock {
	start := o.stack[len(o.stack)-1]
	o.stack = o.stack[:len(o.stack)-1]
	blockLen := o.Size() - start
	pc := o.pc()
	// Write the block header reserved in Begin.
	data := o.data[start.data : start.data+ops.TypeBlockDefLen]
	data[0] = byte(ops.TypeBlockDef)
	bo := binary.LittleEndian
	bo.PutUint32(o.data[start+1:], uint32(blockLen))
	bo.PutUint32(data[1:], uint32(pc.data))
	bo.PutUint32(data[5:], uint32(pc.refs))
	return OpBlock{start}
}



@@ 77,41 121,51 @@ func (o *Ops) Reset() {
	o.data = o.data[:0]
}

func (o *Ops) Ref(r interface{}) int {
	o.refs = append(o.refs, r)
	return len(o.refs) - 1
func (o *Ops) Write(op []byte, refs []interface{}) {
	o.data = append(o.data, op...)
	o.refs = append(o.refs, refs...)
}

func (o *Ops) Write(op []byte) {
	o.data = append(o.data, op...)
func (o *Ops) pc() pc {
	return pc{data: len(o.data), refs: len(o.refs)}
}

// Size returns the length of the serialized Op data.
func (o *Ops) Size() int {
	return len(o.data)
func (b *OpBlock) decode(data []byte) {
	if ops.OpType(data[0]) != ops.TypeBlock {
		panic("invalid op")
	}
	bo := binary.LittleEndian
	dataIdx := int(bo.Uint32(data[1:]))
	refsIdx := int(bo.Uint32(data[5:]))
	*b = OpBlock{
		pc: pc{
			data: dataIdx,
			refs: refsIdx,
		},
	}
}

func (b OpBlock) Add(o *Ops) {
	data := make([]byte, ops.TypeBlockLen)
	data[0] = byte(ops.TypeBlock)
	bo := binary.LittleEndian
	bo.PutUint32(data[1:], uint32(b.idx))
	o.Write(data)
	bo.PutUint32(data[1:], uint32(b.pc.data))
	bo.PutUint32(data[5:], uint32(b.pc.refs))
	o.Write(data, nil)
}

// Reset start reading from the op list.
func (r *OpsReader) Reset(ops *Ops) {
	r.Refs = ops.refs
	r.refs = ops.refs
	r.data = ops.data
	r.stack = r.stack[:0]
	r.pc = 0
	r.pc = pc{}
}

func (r *OpsReader) Decode() ([]byte, bool) {
	bo := binary.LittleEndian
func (r *OpsReader) Decode() ([]byte, []interface{}, bool) {
	for {
		if r.pc == len(r.data) {
			return nil, false
		if r.pc.data == len(r.data) {
			return nil, nil, false
		}
		if len(r.stack) > 0 {
			b := r.stack[len(r.stack)-1]


@@ 119,28 173,40 @@ func (r *OpsReader) Decode() ([]byte, bool) {
				r.pc = b.retPC
				r.stack = r.stack[:len(r.stack)-1]
				r.pseudoOp[0] = byte(ops.TypePop)
				return r.pseudoOp[:], true
				return r.pseudoOp[:], nil, true
			}
		}
		t := ops.OpType(r.data[r.pc])
		n := typeLengths[t]
		data := r.data[r.pc : r.pc+n]
		t := ops.OpType(r.data[r.pc.data])
		n := typeLengths[t-ops.FirstOpIndex]
		nrefs := refLengths[t-ops.FirstOpIndex]
		data := r.data[r.pc.data : r.pc.data+n]
		refs := r.refs[r.pc.refs : r.pc.refs+nrefs]
		switch t {
		case ops.TypeBlock:
			blockIdx := int(bo.Uint32(data[1:]))
			if ops.OpType(r.data[blockIdx]) != ops.TypeBlockDef {
			var op OpBlock
			op.decode(data)
			if ops.OpType(r.data[op.pc.data]) != 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
			var opDef opBlockDef
			opDef.decode(r.data[op.pc.data : op.pc.data+ops.TypeBlockDefLen])
			retPC := r.pc
			retPC.data += n
			retPC.refs += nrefs
			r.stack = append(r.stack, block{retPC: retPC, endPC: opDef.endpc})
			r.pc = op.pc
			r.pc.data += ops.TypeBlockDefLen
			r.pc.refs += ops.TypeBlockDefRefs
			r.pseudoOp[0] = byte(ops.TypePush)
			return r.pseudoOp[:], true
			return r.pseudoOp[:], nil, true
		case ops.TypeBlockDef:
			r.pc += int(bo.Uint32(data[1:]))
			var op opBlockDef
			op.decode(data)
			r.pc = op.endpc
			continue
		}
		r.pc += n
		return data, true
		r.pc.data += n
		r.pc.refs += nrefs
		return data, refs, true
	}
}

M ui/pointer/pointer.go => ui/pointer/pointer.go +3 -10
@@ 3,7 3,6 @@
package pointer

import (
	"encoding/binary"
	"time"

	"gioui.org/ui"


@@ 72,26 71,20 @@ const (
func (h OpHandler) Add(o *ui.Ops) {
	data := make([]byte, ops.TypePointerHandlerLen)
	data[0] = byte(ops.TypePointerHandler)
	bo := binary.LittleEndian
	if h.Grab {
		data[1] = 1
	}
	bo.PutUint32(data[2:], uint32(o.Ref(h.Key)))
	bo.PutUint32(data[6:], uint32(o.Ref(h.Area)))
	o.Write(data)
	o.Write(data, []interface{}{h.Key, h.Area})
}

func (h *OpHandler) Decode(d []byte, refs []interface{}) {
	bo := binary.LittleEndian
	if ops.OpType(d[0]) != ops.TypePointerHandler {
		panic("invalid op")
	}
	key := int(bo.Uint32(d[2:]))
	area := int(bo.Uint32(d[6:]))
	*h = OpHandler{
		Grab: d[1] != 0,
		Key:  refs[key].(Key),
		Area: refs[area].(Area),
		Key:  refs[0].(Key),
		Area: refs[1].(Area),
	}
}


M ui/pointer/queue.go => ui/pointer/queue.go +2 -2
@@ 39,7 39,7 @@ type handler struct {

func (q *Queue) collectHandlers(r *ui.OpsReader, t ui.Transform, layer int) {
	for {
		data, ok := r.Decode()
		data, refs, ok := r.Decode()
		if !ok {
			return
		}


@@ 57,7 57,7 @@ func (q *Queue) collectHandlers(r *ui.OpsReader, t ui.Transform, layer int) {
			t = t.Mul(op.Transform)
		case ops.TypePointerHandler:
			var op OpHandler
			op.Decode(data, r.Refs)
			op.Decode(data, refs)
			q.hitTree = append(q.hitTree, hitNode{level: layer, key: op.Key})
			h, ok := q.handlers[op.Key]
			if !ok {

M ui/ui.go => ui/ui.go +3 -3
@@ 77,7 77,7 @@ func (r OpRedraw) Add(o *Ops) {
			bo.PutUint64(data[1:], uint64(nanos))
		}
	}
	o.Write(data)
	o.Write(data, nil)
}

func (r *OpRedraw) Decode(d []byte) {


@@ 110,7 110,7 @@ func (t OpTransform) Add(o *Ops) {
	bo := binary.LittleEndian
	bo.PutUint32(data[1:], math.Float32bits(t.Transform.offset.X))
	bo.PutUint32(data[5:], math.Float32bits(t.Transform.offset.Y))
	o.Write(data)
	o.Write(data, nil)
}

func (t *OpTransform) Decode(d []byte) {


@@ 129,7 129,7 @@ func (t *OpTransform) Decode(d []byte) {
func (l OpLayer) Add(o *Ops) {
	data := make([]byte, ops.TypeLayerLen)
	data[0] = byte(ops.TypeLayer)
	o.Write(data)
	o.Write(data, nil)
}

func (l *OpLayer) Decode(d []byte) {