ui,internal/ops,internal/opconst: move OpsReader to internal ops package

To avoid import cycles, move the op constants to its own package,
internal/opconst.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-08-07 14:55:20 +02:00
parent fe20cde393
commit b3517a365e
14 changed files with 295 additions and 270 deletions
+8 -8
View File
@@ -3,7 +3,7 @@ package gpu
import ( import (
"fmt" "fmt"
"gioui.org/ui" "gioui.org/ui/internal/ops"
) )
type resourceCache struct { type resourceCache struct {
@@ -11,11 +11,11 @@ type resourceCache struct {
newRes map[interface{}]resource 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. // key type to avoid allocations.
type opCache struct { type opCache struct {
res map[ui.OpKey]resource res map[ops.Key]resource
newRes map[ui.OpKey]resource newRes map[ops.Key]resource
} }
func newResourceCache() *resourceCache { func newResourceCache() *resourceCache {
@@ -64,12 +64,12 @@ func (r *resourceCache) release(ctx *context) {
func newOpCache() *opCache { func newOpCache() *opCache {
return &opCache{ return &opCache{
res: make(map[ui.OpKey]resource), res: make(map[ops.Key]resource),
newRes: make(map[ui.OpKey]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] v, exists := r.res[key]
if exists { if exists {
r.newRes[key] = v r.newRes[key] = v
@@ -77,7 +77,7 @@ func (r *opCache) get(key ui.OpKey) (resource, bool) {
return v, exists 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 { if _, exists := r.newRes[key]; exists {
panic(fmt.Errorf("key exists, %p", key)) panic(fmt.Errorf("key exists, %p", key))
} }
+17 -16
View File
@@ -16,6 +16,7 @@ import (
"gioui.org/ui/app/internal/gl" "gioui.org/ui/app/internal/gl"
gdraw "gioui.org/ui/draw" gdraw "gioui.org/ui/draw"
"gioui.org/ui/f32" "gioui.org/ui/f32"
"gioui.org/ui/internal/opconst"
"gioui.org/ui/internal/ops" "gioui.org/ui/internal/ops"
"golang.org/x/image/draw" "golang.org/x/image/draw"
) )
@@ -58,7 +59,7 @@ type renderer struct {
} }
type drawOps struct { type drawOps struct {
reader ui.OpsReader reader ops.Reader
cache *resourceCache cache *resourceCache
viewport image.Point viewport image.Point
clearColor [3]float32 clearColor [3]float32
@@ -90,7 +91,7 @@ type pathOp struct {
// clip is the union of all // clip is the union of all
// later clip rectangles. // later clip rectangles.
clip image.Rectangle clip image.Rectangle
pathKey ui.OpKey pathKey ops.Key
path bool path bool
pathVerts []byte pathVerts []byte
parent *pathOp parent *pathOp
@@ -124,7 +125,7 @@ type opClip struct {
} }
func (op *opClip) decode(data []byte) { func (op *opClip) decode(data []byte) {
if ops.OpType(data[0]) != ops.TypeClip { if opconst.OpType(data[0]) != opconst.TypeClip {
panic("invalid op") panic("invalid op")
} }
bo := binary.LittleEndian bo := binary.LittleEndian
@@ -641,20 +642,20 @@ func (d *drawOps) newPathOp() *pathOp {
return &d.pathOpCache[len(d.pathOpCache)-1] 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 aux []byte
var auxKey ui.OpKey var auxKey ops.Key
loop: loop:
for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() { for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() {
switch ops.OpType(encOp.Data[0]) { switch opconst.OpType(encOp.Data[0]) {
case ops.TypeTransform: case opconst.TypeTransform:
var op ui.TransformOp var op ui.TransformOp
op.Decode(encOp.Data) op.Decode(encOp.Data)
state.t = state.t.Multiply(op) state.t = state.t.Multiply(op)
case ops.TypeAux: case opconst.TypeAux:
aux = encOp.Data[ops.TypeAuxLen:] aux = encOp.Data[opconst.TypeAuxLen:]
auxKey = encOp.Key auxKey = encOp.Key
case ops.TypeClip: case opconst.TypeClip:
var op opClip var op opClip
op.decode(encOp.Data) op.decode(encOp.Data)
off := state.t.Transform(f32.Point{}) off := state.t.Transform(f32.Point{})
@@ -676,18 +677,18 @@ loop:
d.pathOps = append(d.pathOps, state.cpath) d.pathOps = append(d.pathOps, state.cpath)
} }
aux = nil aux = nil
auxKey = ui.OpKey{} auxKey = ops.Key{}
case ops.TypeColor: case opconst.TypeColor:
var op gdraw.ColorOp var op gdraw.ColorOp
op.Decode(encOp.Data, encOp.Refs) op.Decode(encOp.Data, encOp.Refs)
state.img = nil state.img = nil
state.color = op.Color state.color = op.Color
case ops.TypeImage: case opconst.TypeImage:
var op gdraw.ImageOp var op gdraw.ImageOp
op.Decode(encOp.Data, encOp.Refs) op.Decode(encOp.Data, encOp.Refs)
state.img = op.Src state.img = op.Src
state.imgRect = op.Rect state.imgRect = op.Rect
case ops.TypeDraw: case opconst.TypeDraw:
var op gdraw.DrawOp var op gdraw.DrawOp
op.Decode(encOp.Data, encOp.Refs) op.Decode(encOp.Data, encOp.Refs)
off := state.t.Transform(f32.Point{}) off := state.t.Transform(f32.Point{})
@@ -723,9 +724,9 @@ loop:
} else { } else {
d.imageOps = append(d.imageOps, img) d.imageOps = append(d.imageOps, img)
} }
case ops.TypePush: case opconst.TypePush:
state.z = d.collectOps(r, state) state.z = d.collectOps(r, state)
case ops.TypePop: case opconst.TypePop:
break loop break loop
} }
} }
+7 -6
View File
@@ -5,6 +5,7 @@ package input
import ( import (
"gioui.org/ui" "gioui.org/ui"
"gioui.org/ui/input" "gioui.org/ui/input"
"gioui.org/ui/internal/opconst"
"gioui.org/ui/internal/ops" "gioui.org/ui/internal/ops"
"gioui.org/ui/key" "gioui.org/ui/key"
) )
@@ -14,7 +15,7 @@ type TextInputState uint8
type keyQueue struct { type keyQueue struct {
focus input.Key focus input.Key
handlers map[input.Key]*keyHandler handlers map[input.Key]*keyHandler
reader ui.OpsReader reader ops.Reader
state TextInputState state TextInputState
} }
@@ -94,8 +95,8 @@ func (q *keyQueue) resolveFocus(events *handlerEvents) (input.Key, listenerPrior
var hide bool var hide bool
loop: loop:
for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() { for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() {
switch ops.OpType(encOp.Data[0]) { switch opconst.OpType(encOp.Data[0]) {
case ops.TypeKeyHandler: case opconst.TypeKeyHandler:
var op key.HandlerOp var op key.HandlerOp
op.Decode(encOp.Data, encOp.Refs) op.Decode(encOp.Data, encOp.Refs)
var newPri listenerPriority var newPri listenerPriority
@@ -119,15 +120,15 @@ loop:
events.Set(op.Key, []input.Event{key.FocusEvent{Focus: false}}) events.Set(op.Key, []input.Event{key.FocusEvent{Focus: false}})
} }
h.active = true h.active = true
case ops.TypeHideInput: case opconst.TypeHideInput:
hide = true hide = true
case ops.TypePush: case opconst.TypePush:
newK, newPri, h := q.resolveFocus(events) newK, newPri, h := q.resolveFocus(events)
hide = hide || h hide = hide || h
if newPri.replaces(pri) { if newPri.replaces(pri) {
k, pri = newK, newPri k, pri = newK, newPri
} }
case ops.TypePop: case opconst.TypePop:
break loop break loop
} }
} }
+11 -10
View File
@@ -9,6 +9,7 @@ import (
"gioui.org/ui" "gioui.org/ui"
"gioui.org/ui/f32" "gioui.org/ui/f32"
"gioui.org/ui/input" "gioui.org/ui/input"
"gioui.org/ui/internal/opconst"
"gioui.org/ui/internal/ops" "gioui.org/ui/internal/ops"
"gioui.org/ui/pointer" "gioui.org/ui/pointer"
) )
@@ -18,7 +19,7 @@ type pointerQueue struct {
areas []areaNode areas []areaNode
handlers map[input.Key]*pointerHandler handlers map[input.Key]*pointerHandler
pointers []pointerInfo pointers []pointerInfo
reader ui.OpsReader reader ops.Reader
scratch []input.Key scratch []input.Key
} }
@@ -63,18 +64,18 @@ const (
areaEllipse 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() { for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() {
switch ops.OpType(encOp.Data[0]) { switch opconst.OpType(encOp.Data[0]) {
case ops.TypePush: case opconst.TypePush:
q.collectHandlers(r, events, t, area, node, pass) q.collectHandlers(r, events, t, area, node, pass)
case ops.TypePop: case opconst.TypePop:
return return
case ops.TypePass: case opconst.TypePass:
var op pointer.PassOp var op pointer.PassOp
op.Decode(encOp.Data) op.Decode(encOp.Data)
pass = op.Pass pass = op.Pass
case ops.TypeArea: case opconst.TypeArea:
var op areaOp var op areaOp
op.Decode(encOp.Data) op.Decode(encOp.Data)
q.areas = append(q.areas, areaNode{trans: t, next: area, area: op}) 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, pass: pass,
}) })
node = len(q.hitTree) - 1 node = len(q.hitTree) - 1
case ops.TypeTransform: case opconst.TypeTransform:
var op ui.TransformOp var op ui.TransformOp
op.Decode(encOp.Data) op.Decode(encOp.Data)
t = t.Multiply(op) t = t.Multiply(op)
case ops.TypePointerHandler: case opconst.TypePointerHandler:
var op pointer.HandlerOp var op pointer.HandlerOp
op.Decode(encOp.Data, encOp.Refs) op.Decode(encOp.Data, encOp.Refs)
q.hitTree = append(q.hitTree, hitNode{ 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) { func (op *areaOp) Decode(d []byte) {
if ops.OpType(d[0]) != ops.TypeArea { if opconst.OpType(d[0]) != opconst.TypeArea {
panic("invalid op") panic("invalid op")
} }
bo := binary.LittleEndian bo := binary.LittleEndian
+5 -4
View File
@@ -7,6 +7,7 @@ import (
"gioui.org/ui" "gioui.org/ui"
"gioui.org/ui/input" "gioui.org/ui/input"
"gioui.org/ui/internal/opconst"
"gioui.org/ui/internal/ops" "gioui.org/ui/internal/ops"
"gioui.org/ui/key" "gioui.org/ui/key"
"gioui.org/ui/pointer" "gioui.org/ui/pointer"
@@ -21,7 +22,7 @@ type Router struct {
handlers handlerEvents handlers handlerEvents
reader ui.OpsReader reader ops.Reader
// InvalidateOp summary. // InvalidateOp summary.
wakeup bool wakeup bool
@@ -71,15 +72,15 @@ func (q *Router) TextInputState() TextInputState {
func (q *Router) collect() { func (q *Router) collect() {
for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() { for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() {
switch ops.OpType(encOp.Data[0]) { switch opconst.OpType(encOp.Data[0]) {
case ops.TypeInvalidate: case opconst.TypeInvalidate:
var op ui.InvalidateOp var op ui.InvalidateOp
op.Decode(encOp.Data) op.Decode(encOp.Data)
if !q.wakeup || op.At.Before(q.wakeupTime) { if !q.wakeup || op.At.Before(q.wakeupTime) {
q.wakeup = true q.wakeup = true
q.wakeupTime = op.At q.wakeupTime = op.At
} }
case ops.TypeProfile: case opconst.TypeProfile:
var op system.ProfileOp var op system.ProfileOp
op.Decode(encOp.Data, encOp.Refs) op.Decode(encOp.Data, encOp.Refs)
q.profHandlers = append(q.profHandlers, op.Key) q.profHandlers = append(q.profHandlers, op.Key)
+10 -10
View File
@@ -10,7 +10,7 @@ import (
"gioui.org/ui" "gioui.org/ui"
"gioui.org/ui/f32" "gioui.org/ui/f32"
"gioui.org/ui/internal/ops" "gioui.org/ui/internal/opconst"
) )
type ImageOp struct { type ImageOp struct {
@@ -27,8 +27,8 @@ type DrawOp struct {
} }
func (i ImageOp) Add(o *ui.Ops) { func (i ImageOp) Add(o *ui.Ops) {
data := make([]byte, ops.TypeImageLen) data := make([]byte, opconst.TypeImageLen)
data[0] = byte(ops.TypeImage) data[0] = byte(opconst.TypeImage)
bo := binary.LittleEndian bo := binary.LittleEndian
bo.PutUint32(data[1:], uint32(i.Rect.Min.X)) bo.PutUint32(data[1:], uint32(i.Rect.Min.X))
bo.PutUint32(data[5:], uint32(i.Rect.Min.Y)) 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{}) { func (i *ImageOp) Decode(data []byte, refs []interface{}) {
bo := binary.LittleEndian bo := binary.LittleEndian
if ops.OpType(data[0]) != ops.TypeImage { if opconst.OpType(data[0]) != opconst.TypeImage {
panic("invalid op") panic("invalid op")
} }
sr := image.Rectangle{ sr := image.Rectangle{
@@ -59,8 +59,8 @@ func (i *ImageOp) Decode(data []byte, refs []interface{}) {
} }
func (c ColorOp) Add(o *ui.Ops) { func (c ColorOp) Add(o *ui.Ops) {
data := make([]byte, ops.TypeColorLen) data := make([]byte, opconst.TypeColorLen)
data[0] = byte(ops.TypeColor) data[0] = byte(opconst.TypeColor)
data[1] = c.Color.R data[1] = c.Color.R
data[2] = c.Color.G data[2] = c.Color.G
data[3] = c.Color.B data[3] = c.Color.B
@@ -69,7 +69,7 @@ func (c ColorOp) Add(o *ui.Ops) {
} }
func (c *ColorOp) Decode(data []byte, refs []interface{}) { 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") panic("invalid op")
} }
*c = ColorOp{ *c = ColorOp{
@@ -83,8 +83,8 @@ func (c *ColorOp) Decode(data []byte, refs []interface{}) {
} }
func (d DrawOp) Add(o *ui.Ops) { func (d DrawOp) Add(o *ui.Ops) {
data := make([]byte, ops.TypeDrawLen) data := make([]byte, opconst.TypeDrawLen)
data[0] = byte(ops.TypeDraw) data[0] = byte(opconst.TypeDraw)
bo := binary.LittleEndian bo := binary.LittleEndian
bo.PutUint32(data[1:], math.Float32bits(d.Rect.Min.X)) bo.PutUint32(data[1:], math.Float32bits(d.Rect.Min.X))
bo.PutUint32(data[5:], math.Float32bits(d.Rect.Min.Y)) 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{}) { func (d *DrawOp) Decode(data []byte, refs []interface{}) {
bo := binary.LittleEndian bo := binary.LittleEndian
if ops.OpType(data[0]) != ops.TypeDraw { if opconst.OpType(data[0]) != opconst.TypeDraw {
panic("invalid op") panic("invalid op")
} }
r := f32.Rectangle{ r := f32.Rectangle{
+4 -4
View File
@@ -9,7 +9,7 @@ import (
"gioui.org/ui" "gioui.org/ui"
"gioui.org/ui/f32" "gioui.org/ui/f32"
"gioui.org/ui/internal/ops" "gioui.org/ui/internal/opconst"
"gioui.org/ui/internal/path" "gioui.org/ui/internal/path"
) )
@@ -30,8 +30,8 @@ type ClipOp struct {
} }
func (p ClipOp) Add(o *ui.Ops) { func (p ClipOp) Add(o *ui.Ops) {
data := make([]byte, ops.TypeClipLen) data := make([]byte, opconst.TypeClipLen)
data[0] = byte(ops.TypeClip) data[0] = byte(opconst.TypeClip)
bo := binary.LittleEndian bo := binary.LittleEndian
bo.PutUint32(data[1:], math.Float32bits(p.bounds.Min.X)) bo.PutUint32(data[1:], math.Float32bits(p.bounds.Min.X))
bo.PutUint32(data[5:], math.Float32bits(p.bounds.Min.Y)) 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, ToY: to.Y,
} }
data := make([]byte, path.VertStride+1) data := make([]byte, path.VertStride+1)
data[0] = byte(ops.TypeAux) data[0] = byte(opconst.TypeAux)
bo := binary.LittleEndian bo := binary.LittleEndian
data[1] = byte(uint16(v.CornerX)) data[1] = byte(uint16(v.CornerX))
data[2] = byte(uint16(v.CornerX) >> 8) data[2] = byte(uint16(v.CornerX) >> 8)
@@ -1,4 +1,4 @@
package ops package opconst
type OpType byte type OpType byte
+177
View File
@@ -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,
}
}
+6 -6
View File
@@ -5,7 +5,7 @@ package key
import ( import (
"gioui.org/ui" "gioui.org/ui"
"gioui.org/ui/input" "gioui.org/ui/input"
"gioui.org/ui/internal/ops" "gioui.org/ui/internal/opconst"
) )
type HandlerOp struct { type HandlerOp struct {
@@ -56,8 +56,8 @@ func (m Modifiers) Contain(m2 Modifiers) bool {
} }
func (h HandlerOp) Add(o *ui.Ops) { func (h HandlerOp) Add(o *ui.Ops) {
data := make([]byte, ops.TypeKeyHandlerLen) data := make([]byte, opconst.TypeKeyHandlerLen)
data[0] = byte(ops.TypeKeyHandler) data[0] = byte(opconst.TypeKeyHandler)
if h.Focus { if h.Focus {
data[1] = 1 data[1] = 1
} }
@@ -65,7 +65,7 @@ func (h HandlerOp) Add(o *ui.Ops) {
} }
func (h *HandlerOp) Decode(d []byte, refs []interface{}) { 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") panic("invalid op")
} }
*h = HandlerOp{ *h = HandlerOp{
@@ -75,8 +75,8 @@ func (h *HandlerOp) Decode(d []byte, refs []interface{}) {
} }
func (h HideInputOp) Add(o *ui.Ops) { func (h HideInputOp) Add(o *ui.Ops) {
data := make([]byte, ops.TypeHideInputLen) data := make([]byte, opconst.TypeHideInputLen)
data[0] = byte(ops.TypeHideInput) data[0] = byte(opconst.TypeHideInput)
o.Write(data) o.Write(data)
} }
+29 -185
View File
@@ -3,16 +3,16 @@ package ui
import ( import (
"encoding/binary" "encoding/binary"
"gioui.org/ui/internal/ops" "gioui.org/ui/internal/opconst"
) )
// Ops holds a list of serialized Ops. // Ops holds a list of serialized Ops.
type Ops struct { type Ops struct {
version int Version int
// Serialized ops. // Serialized ops.
data []byte Data []byte
// Op references. // Op references.
refs []interface{} Refs []interface{}
stackDepth int stackDepth int
@@ -21,39 +21,6 @@ type Ops struct {
auxLen int 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 { type StackOp struct {
depth int depth int
active bool active bool
@@ -67,12 +34,9 @@ type MacroOp struct {
pc pc pc pc
} }
type opMacroDef struct { type pc struct {
endpc pc data int
} refs int
type opAux struct {
len int
} }
func (s *StackOp) Push(o *Ops) { func (s *StackOp) Push(o *Ops) {
@@ -83,7 +47,7 @@ func (s *StackOp) Push(o *Ops) {
s.ops = o s.ops = o
o.stackDepth++ o.stackDepth++
s.depth = o.stackDepth s.depth = o.stackDepth
o.Write([]byte{byte(ops.TypePush)}) o.Write([]byte{byte(opconst.TypePush)})
} }
func (s *StackOp) Pop() { func (s *StackOp) Pop() {
@@ -96,32 +60,7 @@ func (s *StackOp) Pop() {
} }
s.active = false s.active = false
s.ops.stackDepth-- s.ops.stackDepth--
s.ops.Write([]byte{byte(ops.TypePop)}) s.ops.Write([]byte{byte(opconst.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,
},
}
} }
// Reset the Ops, preparing it for re-use. // Reset the Ops, preparing it for re-use.
@@ -129,12 +68,12 @@ func (o *Ops) Reset() {
o.inAux = false o.inAux = false
o.stackDepth = 0 o.stackDepth = 0
// Leave references to the GC. // Leave references to the GC.
for i := range o.refs { for i := range o.Refs {
o.refs[i] = nil o.Refs[i] = nil
} }
o.data = o.data[:0] o.Data = o.Data[:0]
o.refs = o.refs[:0] o.Refs = o.Refs[:0]
o.version++ o.Version++
} }
// Internal use only. // Internal use only.
@@ -142,29 +81,29 @@ func (o *Ops) Aux() []byte {
if !o.inAux { if !o.inAux {
return nil 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{}) { func (d *Ops) write(op []byte, refs ...interface{}) {
d.data = append(d.data, op...) d.Data = append(d.Data, op...)
d.refs = append(d.refs, refs...) d.Refs = append(d.Refs, refs...)
} }
func (o *Ops) Write(op []byte, refs ...interface{}) { func (o *Ops) Write(op []byte, refs ...interface{}) {
t := ops.OpType(op[0]) t := opconst.OpType(op[0])
if len(refs) != t.NumRefs() { if len(refs) != t.NumRefs() {
panic("invalid ref count") panic("invalid ref count")
} }
switch t { switch t {
case ops.TypeAux: case opconst.TypeAux:
// Write only the data. // Write only the data.
op = op[1:] op = op[1:]
if !o.inAux { if !o.inAux {
o.inAux = true o.inAux = true
o.auxOff = o.pc().data o.auxOff = o.pc().data
o.auxLen = 0 o.auxLen = 0
header := make([]byte, ops.TypeAuxLen) header := make([]byte, opconst.TypeAuxLen)
header[0] = byte(ops.TypeAux) header[0] = byte(opconst.TypeAux)
o.write(header) o.write(header)
} }
o.auxLen += len(op) o.auxLen += len(op)
@@ -172,14 +111,14 @@ func (o *Ops) Write(op []byte, refs ...interface{}) {
if o.inAux { if o.inAux {
o.inAux = false o.inAux = false
bo := binary.LittleEndian 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...) o.write(op, refs...)
} }
func (d *Ops) pc() pc { 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. // Record a macro of operations.
@@ -191,7 +130,7 @@ func (m *MacroOp) Record(o *Ops) {
m.ops = o m.ops = o
m.pc = o.pc() m.pc = o.pc()
// Make room for a macro definition. Filled out in Stop. // 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. // Stop recording the macro.
@@ -202,30 +141,12 @@ func (m *MacroOp) Stop() {
m.recording = false m.recording = false
pc := m.ops.pc() pc := m.ops.pc()
// Fill out the macro definition reserved in Record. // Fill out the macro definition reserved in Record.
data := m.ops.data[m.pc.data : m.pc.data+ops.TypeMacroDefLen] data := m.ops.Data[m.pc.data : m.pc.data+opconst.TypeMacroDefLen]
data[0] = byte(ops.TypeMacroDef) data[0] = byte(opconst.TypeMacroDef)
bo := binary.LittleEndian bo := binary.LittleEndian
bo.PutUint32(data[1:], uint32(pc.data)) bo.PutUint32(data[1:], uint32(pc.data))
bo.PutUint32(data[5:], uint32(pc.refs)) bo.PutUint32(data[5:], uint32(pc.refs))
m.version = m.ops.version 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,
}
} }
func (m MacroOp) Add(o *Ops) { func (m MacroOp) Add(o *Ops) {
@@ -235,88 +156,11 @@ func (m MacroOp) Add(o *Ops) {
if m.ops == nil { if m.ops == nil {
return return
} }
data := make([]byte, ops.TypeMacroLen) data := make([]byte, opconst.TypeMacroLen)
data[0] = byte(ops.TypeMacro) data[0] = byte(opconst.TypeMacro)
bo := binary.LittleEndian bo := binary.LittleEndian
bo.PutUint32(data[1:], uint32(m.pc.data)) bo.PutUint32(data[1:], uint32(m.pc.data))
bo.PutUint32(data[5:], uint32(m.pc.refs)) bo.PutUint32(data[5:], uint32(m.pc.refs))
bo.PutUint32(data[9:], uint32(m.version)) bo.PutUint32(data[9:], uint32(m.version))
o.Write(data, m.ops) 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
}
}
+9 -9
View File
@@ -10,7 +10,7 @@ import (
"gioui.org/ui" "gioui.org/ui"
"gioui.org/ui/f32" "gioui.org/ui/f32"
"gioui.org/ui/input" "gioui.org/ui/input"
"gioui.org/ui/internal/ops" "gioui.org/ui/internal/opconst"
) )
type Event struct { type Event struct {
@@ -95,8 +95,8 @@ func (op EllipseAreaOp) Add(ops *ui.Ops) {
} }
func (op areaOp) add(o *ui.Ops) { func (op areaOp) add(o *ui.Ops) {
data := make([]byte, ops.TypeAreaLen) data := make([]byte, opconst.TypeAreaLen)
data[0] = byte(ops.TypeArea) data[0] = byte(opconst.TypeArea)
data[1] = byte(op.kind) data[1] = byte(op.kind)
bo := binary.LittleEndian bo := binary.LittleEndian
bo.PutUint32(data[2:], uint32(op.rect.Min.X)) 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) { func (h HandlerOp) Add(o *ui.Ops) {
data := make([]byte, ops.TypePointerHandlerLen) data := make([]byte, opconst.TypePointerHandlerLen)
data[0] = byte(ops.TypePointerHandler) data[0] = byte(opconst.TypePointerHandler)
if h.Grab { if h.Grab {
data[1] = 1 data[1] = 1
} }
@@ -116,7 +116,7 @@ func (h HandlerOp) Add(o *ui.Ops) {
} }
func (h *HandlerOp) Decode(d []byte, refs []interface{}) { 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") panic("invalid op")
} }
*h = HandlerOp{ *h = HandlerOp{
@@ -126,8 +126,8 @@ func (h *HandlerOp) Decode(d []byte, refs []interface{}) {
} }
func (op PassOp) Add(o *ui.Ops) { func (op PassOp) Add(o *ui.Ops) {
data := make([]byte, ops.TypePassLen) data := make([]byte, opconst.TypePassLen)
data[0] = byte(ops.TypePass) data[0] = byte(opconst.TypePass)
if op.Pass { if op.Pass {
data[1] = 1 data[1] = 1
} }
@@ -135,7 +135,7 @@ func (op PassOp) Add(o *ui.Ops) {
} }
func (op *PassOp) Decode(d []byte) { func (op *PassOp) Decode(d []byte) {
if ops.OpType(d[0]) != ops.TypePass { if opconst.OpType(d[0]) != opconst.TypePass {
panic("invalid op") panic("invalid op")
} }
*op = PassOp{ *op = PassOp{
+4 -4
View File
@@ -7,7 +7,7 @@ package system
import ( import (
"gioui.org/ui" "gioui.org/ui"
"gioui.org/ui/input" "gioui.org/ui/input"
"gioui.org/ui/internal/ops" "gioui.org/ui/internal/opconst"
) )
// ProfileOp registers a handler for receiving // ProfileOp registers a handler for receiving
@@ -24,13 +24,13 @@ type ProfileEvent struct {
} }
func (p ProfileOp) Add(o *ui.Ops) { func (p ProfileOp) Add(o *ui.Ops) {
data := make([]byte, ops.TypeProfileLen) data := make([]byte, opconst.TypeProfileLen)
data[0] = byte(ops.TypeProfile) data[0] = byte(opconst.TypeProfile)
o.Write(data, p.Key) o.Write(data, p.Key)
} }
func (p *ProfileOp) Decode(d []byte, refs []interface{}) { 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") panic("invalid op")
} }
*p = ProfileOp{ *p = ProfileOp{
+7 -7
View File
@@ -8,7 +8,7 @@ import (
"time" "time"
"gioui.org/ui/f32" "gioui.org/ui/f32"
"gioui.org/ui/internal/ops" "gioui.org/ui/internal/opconst"
) )
// Config represents the essential configuration for // Config represents the essential configuration for
@@ -33,8 +33,8 @@ type TransformOp struct {
} }
func (r InvalidateOp) Add(o *Ops) { func (r InvalidateOp) Add(o *Ops) {
data := make([]byte, ops.TypeRedrawLen) data := make([]byte, opconst.TypeRedrawLen)
data[0] = byte(ops.TypeInvalidate) data[0] = byte(opconst.TypeInvalidate)
bo := binary.LittleEndian bo := binary.LittleEndian
// UnixNano cannot represent the zero time. // UnixNano cannot represent the zero time.
if t := r.At; !t.IsZero() { if t := r.At; !t.IsZero() {
@@ -48,7 +48,7 @@ func (r InvalidateOp) Add(o *Ops) {
func (r *InvalidateOp) Decode(d []byte) { func (r *InvalidateOp) Decode(d []byte) {
bo := binary.LittleEndian bo := binary.LittleEndian
if ops.OpType(d[0]) != ops.TypeInvalidate { if opconst.OpType(d[0]) != opconst.TypeInvalidate {
panic("invalid op") panic("invalid op")
} }
if nanos := bo.Uint64(d[1:]); nanos > 0 { 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) { func (t TransformOp) Add(o *Ops) {
data := make([]byte, ops.TypeTransformLen) data := make([]byte, opconst.TypeTransformLen)
data[0] = byte(ops.TypeTransform) data[0] = byte(opconst.TypeTransform)
bo := binary.LittleEndian bo := binary.LittleEndian
bo.PutUint32(data[1:], math.Float32bits(t.offset.X)) bo.PutUint32(data[1:], math.Float32bits(t.offset.X))
bo.PutUint32(data[5:], math.Float32bits(t.offset.Y)) 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) { func (t *TransformOp) Decode(d []byte) {
bo := binary.LittleEndian bo := binary.LittleEndian
if ops.OpType(d[0]) != ops.TypeTransform { if opconst.OpType(d[0]) != opconst.TypeTransform {
panic("invalid op") panic("invalid op")
} }
*t = TransformOp{f32.Point{ *t = TransformOp{f32.Point{