op: move Ops internal methods and state to internal package ops

Merge package opconsts into ops as well; it only existed to break
import cycles.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-10-04 15:44:48 +02:00
parent 936c266b03
commit 391725b9d0
18 changed files with 558 additions and 561 deletions
+2 -2
View File
@@ -192,8 +192,8 @@ func areShapesEqual(shape1, shape2 clip.Op) bool {
shape1.Push(&ops1).Pop()
shape2.Push(&ops2).Pop()
var r1, r2 ops.Reader
r1.Reset(&ops1)
r2.Reset(&ops2)
r1.Reset(&ops1.Internal)
r2.Reset(&ops2.Internal)
for {
encOp1, ok1 := r1.Decode()
encOp2, ok2 := r2.Decode()
+16 -17
View File
@@ -24,7 +24,6 @@ import (
"gioui.org/gpu/internal/driver"
"gioui.org/internal/byteslice"
"gioui.org/internal/f32color"
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/internal/scene"
"gioui.org/layout"
@@ -1726,7 +1725,7 @@ func (c *collector) addClip(state *encoderState, viewport, bounds f32.Rectangle,
func (c *collector) collect(root *op.Ops, viewport image.Point, texOps *[]textureOp) {
fview := f32.Rectangle{Max: layout.FPt(viewport)}
c.reader.Reset(root)
c.reader.Reset(&root.Internal)
var state encoderState
reset := func() {
state = encoderState{
@@ -1747,40 +1746,40 @@ func (c *collector) collect(root *op.Ops, viewport image.Point, texOps *[]textur
)
c.addClip(&state, fview, fview, nil, ops.Key{}, 0, clip.StrokeStyle{}, false)
for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() {
switch opconst.OpType(encOp.Data[0]) {
case opconst.TypeProfile:
switch ops.OpType(encOp.Data[0]) {
case ops.TypeProfile:
c.profile = true
case opconst.TypeTransform:
case ops.TypeTransform:
dop, push := ops.DecodeTransform(encOp.Data)
if push {
c.transStack = append(c.transStack, transEntry{t: state.t, relTrans: state.relTrans})
}
state.t = state.t.Mul(dop)
state.relTrans = state.relTrans.Mul(dop)
case opconst.TypePopTransform:
case ops.TypePopTransform:
n := len(c.transStack)
st := c.transStack[n-1]
c.transStack = c.transStack[:n-1]
state.t = st.t
state.relTrans = st.relTrans
case opconst.TypeStroke:
case ops.TypeStroke:
str = decodeStrokeOp(encOp.Data)
case opconst.TypePath:
case ops.TypePath:
hash := bo.Uint64(encOp.Data[1:])
encOp, ok = r.Decode()
if !ok {
panic("unexpected end of path operation")
}
pathData.data = encOp.Data[opconst.TypeAuxLen:]
pathData.data = encOp.Data[ops.TypeAuxLen:]
pathData.key = encOp.Key
pathData.hash = hash
case opconst.TypeClip:
case ops.TypeClip:
var op clipOp
op.decode(encOp.Data)
c.addClip(&state, fview, op.bounds, pathData.data, pathData.key, pathData.hash, str, op.push)
pathData.data = nil
str = clip.StrokeStyle{}
case opconst.TypePopClip:
case ops.TypePopClip:
for {
push := state.clip.push
state.relTrans = state.clip.relTrans.Mul(state.relTrans)
@@ -1789,20 +1788,20 @@ func (c *collector) collect(root *op.Ops, viewport image.Point, texOps *[]textur
break
}
}
case opconst.TypeColor:
case ops.TypeColor:
state.matType = materialColor
state.color = decodeColorOp(encOp.Data)
case opconst.TypeLinearGradient:
case ops.TypeLinearGradient:
state.matType = materialLinearGradient
op := decodeLinearGradientOp(encOp.Data)
state.stop1 = op.stop1
state.stop2 = op.stop2
state.color1 = op.color1
state.color2 = op.color2
case opconst.TypeImage:
case ops.TypeImage:
state.matType = materialTexture
state.image = decodeImageOp(encOp.Data, encOp.Refs)
case opconst.TypePaint:
case ops.TypePaint:
paintState := state
if paintState.matType == materialTexture {
// Clip to the bounds of the image, to hide other images in the atlas.
@@ -1846,10 +1845,10 @@ func (c *collector) collect(root *op.Ops, viewport image.Point, texOps *[]textur
state: paintState.paintKey,
intersect: intersect,
})
case opconst.TypeSave:
case ops.TypeSave:
id := ops.DecodeSave(encOp.Data)
c.save(id, state.t)
case opconst.TypeLoad:
case ops.TypeLoad:
reset()
id := ops.DecodeLoad(encOp.Data)
state.t = c.states[id]
+21 -22
View File
@@ -22,7 +22,6 @@ import (
"gioui.org/gpu/internal/driver"
"gioui.org/internal/byteslice"
"gioui.org/internal/f32color"
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/internal/scene"
"gioui.org/internal/stroke"
@@ -138,7 +137,7 @@ type imageOp struct {
func decodeStrokeOp(data []byte) clip.StrokeStyle {
_ = data[4]
if opconst.OpType(data[0]) != opconst.TypeStroke {
if ops.OpType(data[0]) != ops.TypeStroke {
panic("invalid op")
}
bo := binary.LittleEndian
@@ -192,7 +191,7 @@ type linearGradientOpData struct {
}
func (op *clipOp) decode(data []byte) {
if opconst.OpType(data[0]) != opconst.TypeClip {
if ops.OpType(data[0]) != ops.TypeClip {
panic("invalid op")
}
bo := binary.LittleEndian
@@ -214,7 +213,7 @@ func (op *clipOp) decode(data []byte) {
}
func decodeImageOp(data []byte, refs []interface{}) imageOpData {
if opconst.OpType(data[0]) != opconst.TypeImage {
if ops.OpType(data[0]) != ops.TypeImage {
panic("invalid op")
}
handle := refs[1]
@@ -228,7 +227,7 @@ func decodeImageOp(data []byte, refs []interface{}) imageOpData {
}
func decodeColorOp(data []byte) color.NRGBA {
if opconst.OpType(data[0]) != opconst.TypeColor {
if ops.OpType(data[0]) != ops.TypeColor {
panic("invalid op")
}
return color.NRGBA{
@@ -240,7 +239,7 @@ func decodeColorOp(data []byte) color.NRGBA {
}
func decodeLinearGradientOp(data []byte) linearGradientOpData {
if opconst.OpType(data[0]) != opconst.TypeLinearGradient {
if ops.OpType(data[0]) != ops.TypeLinearGradient {
panic("invalid op")
}
bo := binary.LittleEndian
@@ -835,7 +834,7 @@ func (d *drawOps) collect(root *op.Ops, viewport image.Point) {
viewf := f32.Rectangle{
Max: f32.Point{X: float32(viewport.X), Y: float32(viewport.Y)},
}
d.reader.Reset(root)
d.reader.Reset(&root.Internal)
d.collectOps(&d.reader, viewf)
}
@@ -920,32 +919,32 @@ func (d *drawOps) collectOps(r *ops.Reader, viewport f32.Rectangle) {
reset()
loop:
for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() {
switch opconst.OpType(encOp.Data[0]) {
case opconst.TypeProfile:
switch ops.OpType(encOp.Data[0]) {
case ops.TypeProfile:
d.profile = true
case opconst.TypeTransform:
case ops.TypeTransform:
dop, push := ops.DecodeTransform(encOp.Data)
if push {
d.transStack = append(d.transStack, state.t)
}
state.t = state.t.Mul(dop)
case opconst.TypePopTransform:
case ops.TypePopTransform:
n := len(d.transStack)
state.t = d.transStack[n-1]
d.transStack = d.transStack[:n-1]
case opconst.TypeStroke:
case ops.TypeStroke:
str = decodeStrokeOp(encOp.Data)
case opconst.TypePath:
case ops.TypePath:
encOp, ok = r.Decode()
if !ok {
break loop
}
quads.aux = encOp.Data[opconst.TypeAuxLen:]
quads.aux = encOp.Data[ops.TypeAuxLen:]
quads.key = opKey{Key: encOp.Key}
case opconst.TypeClip:
case ops.TypeClip:
var op clipOp
op.decode(encOp.Data)
bounds := op.bounds
@@ -976,7 +975,7 @@ loop:
d.addClipPath(&state, quads.aux, quads.key, op.bounds, off, op.push)
quads = quadsOp{}
str = clip.StrokeStyle{}
case opconst.TypePopClip:
case ops.TypePopClip:
for {
push := state.cpath.push
state.cpath = state.cpath.parent
@@ -985,20 +984,20 @@ loop:
}
}
case opconst.TypeColor:
case ops.TypeColor:
state.matType = materialColor
state.color = decodeColorOp(encOp.Data)
case opconst.TypeLinearGradient:
case ops.TypeLinearGradient:
state.matType = materialLinearGradient
op := decodeLinearGradientOp(encOp.Data)
state.stop1 = op.stop1
state.stop2 = op.stop2
state.color1 = op.color1
state.color2 = op.color2
case opconst.TypeImage:
case ops.TypeImage:
state.matType = materialTexture
state.image = decodeImageOp(encOp.Data, encOp.Refs)
case opconst.TypePaint:
case ops.TypePaint:
// Transform (if needed) the painting rectangle and if so generate a clip path,
// for those cases also compute a partialTrans that maps texture coordinates between
// the new bounding rectangle and the transformed original paint rectangle.
@@ -1050,10 +1049,10 @@ loop:
// we added a clip path that should not remain
state.cpath = state.cpath.parent
}
case opconst.TypeSave:
case ops.TypeSave:
id := ops.DecodeSave(encOp.Data)
d.save(id, state.t)
case opconst.TypeLoad:
case ops.TypeLoad:
reset()
id := ops.DecodeLoad(encOp.Data)
state.t = d.states[id]
-172
View File
@@ -1,172 +0,0 @@
// SPDX-License-Identifier: Unlicense OR MIT
package opconst
type OpType byte
// Start at a high number for easier debugging.
const firstOpIndex = 200
const (
TypeMacro OpType = iota + firstOpIndex
TypeCall
TypeDefer
TypeTransform
TypePopTransform
TypeInvalidate
TypeImage
TypePaint
TypeColor
TypeLinearGradient
TypeArea
TypePopArea
TypePointerInput
TypeClipboardRead
TypeClipboardWrite
TypeKeyInput
TypeKeyFocus
TypeKeySoftKeyboard
TypeSave
TypeLoad
TypeAux
TypeClip
TypePopClip
TypeProfile
TypeCursor
TypePath
TypeStroke
)
const (
TypeMacroLen = 1 + 4 + 4
TypeCallLen = 1 + 4 + 4
TypeDeferLen = 1
TypeTransformLen = 1 + 1 + 4*6
TypePopTransformLen = 1
TypeRedrawLen = 1 + 8
TypeImageLen = 1
TypePaintLen = 1
TypeColorLen = 1 + 4
TypeLinearGradientLen = 1 + 8*2 + 4*2
TypeAreaLen = 1 + 1 + 1 + 4*4
TypePopAreaLen = 1
TypePointerInputLen = 1 + 1 + 1 + 2*4 + 2*4
TypeClipboardReadLen = 1
TypeClipboardWriteLen = 1
TypeKeyInputLen = 1 + 1
TypeKeyFocusLen = 1 + 1
TypeKeySoftKeyboardLen = 1 + 1
TypeSaveLen = 1 + 4
TypeLoadLen = 1 + 4
TypeAuxLen = 1
TypeClipLen = 1 + 4*4 + 1 + 1
TypePopClipLen = 1
TypeProfileLen = 1
TypeCursorLen = 1 + 1
TypePathLen = 8 + 1
TypeStrokeLen = 1 + 4
)
func (t OpType) Size() int {
return [...]int{
TypeMacroLen,
TypeCallLen,
TypeDeferLen,
TypeTransformLen,
TypePopTransformLen,
TypeRedrawLen,
TypeImageLen,
TypePaintLen,
TypeColorLen,
TypeLinearGradientLen,
TypeAreaLen,
TypePopAreaLen,
TypePointerInputLen,
TypeClipboardReadLen,
TypeClipboardWriteLen,
TypeKeyInputLen,
TypeKeyFocusLen,
TypeKeySoftKeyboardLen,
TypeSaveLen,
TypeLoadLen,
TypeAuxLen,
TypeClipLen,
TypePopClipLen,
TypeProfileLen,
TypeCursorLen,
TypePathLen,
TypeStrokeLen,
}[t-firstOpIndex]
}
func (t OpType) NumRefs() int {
switch t {
case TypeKeyInput, TypeKeyFocus, TypePointerInput, TypeProfile, TypeCall, TypeClipboardRead, TypeClipboardWrite, TypeCursor:
return 1
case TypeImage:
return 2
default:
return 0
}
}
func (t OpType) String() string {
switch t {
case TypeMacro:
return "Macro"
case TypeCall:
return "Call"
case TypeDefer:
return "Defer"
case TypeTransform:
return "Transform"
case TypePopTransform:
return "PopTransform"
case TypeInvalidate:
return "Invalidate"
case TypeImage:
return "Image"
case TypePaint:
return "Paint"
case TypeColor:
return "Color"
case TypeLinearGradient:
return "LinearGradient"
case TypeArea:
return "Area"
case TypePopArea:
return "PopArea"
case TypePointerInput:
return "PointerInput"
case TypeClipboardRead:
return "ClipboardRead"
case TypeClipboardWrite:
return "ClipboardWrite"
case TypeKeyInput:
return "KeyInput"
case TypeKeyFocus:
return "KeyFocus"
case TypeKeySoftKeyboard:
return "KeySoftKeyboard"
case TypeSave:
return "Save"
case TypeLoad:
return "Load"
case TypeAux:
return "Aux"
case TypeClip:
return "Clip"
case TypePopClip:
return "PopClip"
case TypeProfile:
return "Profile"
case TypeCursor:
return "Cursor"
case TypePath:
return "Path"
case TypeStroke:
return "Stroke"
default:
panic("unnkown OpType")
}
}
+351 -4
View File
@@ -8,10 +8,250 @@ import (
"gioui.org/f32"
"gioui.org/internal/byteslice"
"gioui.org/internal/opconst"
"gioui.org/internal/scene"
)
type Ops struct {
// version is incremented at each Reset.
version int
// data contains the serialized operations.
data []byte
// refs hold external references for operations.
refs []interface{}
// nextStateID is the id allocated for the next
// StateOp.
nextStateID int
macroStack stack
stacks [3]stack
}
type OpType byte
// Start at a high number for easier debugging.
const firstOpIndex = 200
const (
TypeMacro OpType = iota + firstOpIndex
TypeCall
TypeDefer
TypePushTransform
TypeTransform
TypePopTransform
TypeInvalidate
TypeImage
TypePaint
TypeColor
TypeLinearGradient
TypeArea
TypePopArea
TypePointerInput
TypeClipboardRead
TypeClipboardWrite
TypeKeyInput
TypeKeyFocus
TypeKeySoftKeyboard
TypeSave
TypeLoad
TypeAux
TypeClip
TypePopClip
TypeProfile
TypeCursor
TypePath
TypeStroke
)
type StackID struct {
id int
prev int
}
// StateOp represents a saved operation snapshop to be restored
// later.
type StateOP struct {
id int
macroID int
ops *Ops
}
// stack tracks the integer identities of stack operations to ensure correct
// pairing of their push and pop methods.
type stack struct {
currentID int
nextID int
}
type StackKind uint8
const (
ClipStack StackKind = iota
AreaStack
TransStack
)
const (
TypeMacroLen = 1 + 4 + 4
TypeCallLen = 1 + 4 + 4
TypeDeferLen = 1
TypePushTransformLen = 1 + 4*6
TypeTransformLen = 1 + 1 + 4*6
TypePopTransformLen = 1
TypeRedrawLen = 1 + 8
TypeImageLen = 1
TypePaintLen = 1
TypeColorLen = 1 + 4
TypeLinearGradientLen = 1 + 8*2 + 4*2
TypeAreaLen = 1 + 1 + 1 + 4*4
TypePopAreaLen = 1
TypePointerInputLen = 1 + 1 + 1 + 2*4 + 2*4
TypeClipboardReadLen = 1
TypeClipboardWriteLen = 1
TypeKeyInputLen = 1 + 1
TypeKeyFocusLen = 1 + 1
TypeKeySoftKeyboardLen = 1 + 1
TypeSaveLen = 1 + 4
TypeLoadLen = 1 + 4
TypeAuxLen = 1
TypeClipLen = 1 + 4*4 + 1 + 1
TypePopClipLen = 1
TypeProfileLen = 1
TypeCursorLen = 1 + 1
TypePathLen = 8 + 1
TypeStrokeLen = 1 + 4
)
func (o *Ops) Reset() {
o.macroStack = stack{}
for i := range o.stacks {
o.stacks[i] = stack{}
}
// Leave references to the GC.
for i := range o.refs {
o.refs[i] = nil
}
o.data = o.data[:0]
o.refs = o.refs[:0]
o.nextStateID = 0
o.version++
}
func (o *Ops) Data() []byte {
return o.data
}
func (o *Ops) Refs() []interface{} {
return o.refs
}
func (o *Ops) Version() int {
return o.version
}
func (o *Ops) Write(n int) []byte {
o.data = append(o.data, make([]byte, n)...)
return o.data[len(o.data)-n:]
}
func (o *Ops) PushMacro() StackID {
return o.macroStack.push()
}
func (o *Ops) PopMacro(id StackID) {
o.macroStack.pop(id)
}
func (o *Ops) FillMacro(startPC PC) {
pc := o.PC()
// Fill out the macro definition reserved in Record.
data := o.data[startPC.data:]
data = data[:TypeMacroLen]
data[0] = byte(TypeMacro)
bo := binary.LittleEndian
bo.PutUint32(data[1:], uint32(pc.data))
bo.PutUint32(data[5:], uint32(pc.refs))
}
func (o *Ops) AddCall(callOps *Ops, pc PC) {
data := o.Write1(TypeCallLen, callOps)
data[0] = byte(TypeCall)
bo := binary.LittleEndian
bo.PutUint32(data[1:], uint32(pc.data))
bo.PutUint32(data[5:], uint32(pc.refs))
}
func (o *Ops) PushOp(kind StackKind) (StackID, int) {
return o.stacks[kind].push(), o.macroStack.currentID
}
func (o *Ops) PopOp(kind StackKind, sid StackID, macroID int) {
if o.macroStack.currentID != macroID {
panic("stack push and pop must not cross macro boundary")
}
o.stacks[kind].pop(sid)
}
func (o *Ops) Write1(n int, ref1 interface{}) []byte {
o.data = append(o.data, make([]byte, n)...)
o.refs = append(o.refs, ref1)
return o.data[len(o.data)-n:]
}
func (o *Ops) Write2(n int, ref1, ref2 interface{}) []byte {
o.data = append(o.data, make([]byte, n)...)
o.refs = append(o.refs, ref1, ref2)
return o.data[len(o.data)-n:]
}
func (o *Ops) PC() PC {
return PC{data: len(o.data), refs: len(o.refs)}
}
func (s *stack) push() StackID {
s.nextID++
sid := StackID{
id: s.nextID,
prev: s.currentID,
}
s.currentID = s.nextID
return sid
}
func (s *stack) check(sid StackID) {
if s.currentID != sid.id {
panic("unbalanced operation")
}
}
func (s *stack) pop(sid StackID) {
s.check(sid)
s.currentID = sid.prev
}
// Save the effective transformation.
func (o *Ops) Save() StateOP {
o.nextStateID++
s := StateOP{
ops: o,
id: o.nextStateID,
macroID: o.macroStack.currentID,
}
bo := binary.LittleEndian
data := o.Write(TypeSaveLen)
data[0] = byte(TypeSave)
bo.PutUint32(data[1:], uint32(s.id))
return s
}
// load a previously saved operations state given
// its ID.
func (s StateOP) Load() {
bo := binary.LittleEndian
data := s.ops.Write(TypeLoadLen)
data[0] = byte(TypeLoad)
bo.PutUint32(data[1:], uint32(s.id))
}
func DecodeCommand(d []byte) scene.Command {
var cmd scene.Command
copy(byteslice.Uint32(cmd[:]), d)
@@ -23,7 +263,7 @@ func EncodeCommand(out []byte, cmd scene.Command) {
}
func DecodeTransform(data []byte) (t f32.Affine2D, push bool) {
if opconst.OpType(data[0]) != opconst.TypeTransform {
if OpType(data[0]) != TypeTransform {
panic("invalid op")
}
push = data[1] != 0
@@ -42,7 +282,7 @@ func DecodeTransform(data []byte) (t f32.Affine2D, push bool) {
// DecodeSave decodes the state id of a save op.
func DecodeSave(data []byte) int {
if opconst.OpType(data[0]) != opconst.TypeSave {
if OpType(data[0]) != TypeSave {
panic("invalid op")
}
bo := binary.LittleEndian
@@ -51,9 +291,116 @@ func DecodeSave(data []byte) int {
// DecodeLoad decodes the state id of a load op.
func DecodeLoad(data []byte) int {
if opconst.OpType(data[0]) != opconst.TypeLoad {
if OpType(data[0]) != TypeLoad {
panic("invalid op")
}
bo := binary.LittleEndian
return int(bo.Uint32(data[1:]))
}
func (t OpType) Size() int {
return [...]int{
TypeMacroLen,
TypeCallLen,
TypeDeferLen,
TypePushTransformLen,
TypeTransformLen,
TypePopTransformLen,
TypeRedrawLen,
TypeImageLen,
TypePaintLen,
TypeColorLen,
TypeLinearGradientLen,
TypeAreaLen,
TypePopAreaLen,
TypePointerInputLen,
TypeClipboardReadLen,
TypeClipboardWriteLen,
TypeKeyInputLen,
TypeKeyFocusLen,
TypeKeySoftKeyboardLen,
TypeSaveLen,
TypeLoadLen,
TypeAuxLen,
TypeClipLen,
TypePopClipLen,
TypeProfileLen,
TypeCursorLen,
TypePathLen,
TypeStrokeLen,
}[t-firstOpIndex]
}
func (t OpType) NumRefs() int {
switch t {
case TypeKeyInput, TypeKeyFocus, TypePointerInput, TypeProfile, TypeCall, TypeClipboardRead, TypeClipboardWrite, TypeCursor:
return 1
case TypeImage:
return 2
default:
return 0
}
}
func (t OpType) String() string {
switch t {
case TypeMacro:
return "Macro"
case TypeCall:
return "Call"
case TypeDefer:
return "Defer"
case TypePushTransform:
return "PushTransform"
case TypeTransform:
return "Transform"
case TypePopTransform:
return "PopTransform"
case TypeInvalidate:
return "Invalidate"
case TypeImage:
return "Image"
case TypePaint:
return "Paint"
case TypeColor:
return "Color"
case TypeLinearGradient:
return "LinearGradient"
case TypeArea:
return "Area"
case TypePopArea:
return "PopArea"
case TypePointerInput:
return "PointerInput"
case TypeClipboardRead:
return "ClipboardRead"
case TypeClipboardWrite:
return "ClipboardWrite"
case TypeKeyInput:
return "KeyInput"
case TypeKeyFocus:
return "KeyFocus"
case TypeKeySoftKeyboard:
return "KeySoftKeyboard"
case TypeSave:
return "Save"
case TypeLoad:
return "Load"
case TypeAux:
return "Aux"
case TypeClip:
return "Clip"
case TypePopClip:
return "PopClip"
case TypeProfile:
return "Profile"
case TypeCursor:
return "Cursor"
case TypePath:
return "Path"
case TypeStroke:
return "Stroke"
default:
panic("unnkown OpType")
}
}
+20 -32
View File
@@ -4,17 +4,14 @@ package ops
import (
"encoding/binary"
"gioui.org/internal/opconst"
"gioui.org/op"
)
// Reader parses an ops list.
type Reader struct {
pc PC
stack []macro
ops *op.Ops
deferOps op.Ops
ops *Ops
deferOps Ops
deferDone bool
}
@@ -28,14 +25,14 @@ type EncodedOp struct {
// Key is a unique key for a given op.
type Key struct {
ops *op.Ops
ops *Ops
pc int
version int
}
// Shadow of op.MacroOp.
type macroOp struct {
ops *op.Ops
ops *Ops
pc PC
}
@@ -46,7 +43,7 @@ type PC struct {
}
type macro struct {
ops *op.Ops
ops *Ops
retPC PC
endPC PC
}
@@ -56,12 +53,12 @@ type opMacroDef struct {
}
// Reset start reading from the beginning of ops.
func (r *Reader) Reset(ops *op.Ops) {
func (r *Reader) Reset(ops *Ops) {
r.ResetAt(ops, PC{})
}
// ResetAt is like Reset, except it starts reading from pc.
func (r *Reader) ResetAt(ops *op.Ops, pc PC) {
func (r *Reader) ResetAt(ops *Ops, pc PC) {
r.stack = r.stack[:0]
r.deferOps.Reset()
r.deferDone = false
@@ -69,15 +66,6 @@ func (r *Reader) ResetAt(ops *op.Ops, pc PC) {
r.ops = ops
}
// NewPC returns a PC representing the current instruction counter of
// ops.
func NewPC(ops *op.Ops) PC {
return PC{
data: len(ops.Data()),
refs: len(ops.Refs()),
}
}
func (r *Reader) Decode() (EncodedOp, bool) {
if r.ops == nil {
return EncodedOp{}, false
@@ -107,25 +95,25 @@ func (r *Reader) Decode() (EncodedOp, bool) {
continue
}
key := Key{ops: r.ops, pc: r.pc.data, version: r.ops.Version()}
t := opconst.OpType(data[0])
t := OpType(data[0])
n := t.Size()
nrefs := t.NumRefs()
data = data[:n]
refs = refs[r.pc.refs:]
refs = refs[:nrefs]
switch t {
case opconst.TypeDefer:
case TypeDefer:
deferring = true
r.pc.data += n
r.pc.refs += nrefs
continue
case opconst.TypeAux:
case TypeAux:
// An Aux operations is always wrapped in a macro, and
// its length is the remaining space.
block := r.stack[len(r.stack)-1]
n += block.endPC.data - r.pc.data - opconst.TypeAuxLen
n += block.endPC.data - r.pc.data - TypeAuxLen
data = data[:n]
case opconst.TypeCall:
case TypeCall:
if deferring {
deferring = false
// Copy macro for deferred execution.
@@ -141,11 +129,11 @@ func (r *Reader) Decode() (EncodedOp, bool) {
var op macroOp
op.decode(data, refs)
macroData := op.ops.Data()[op.pc.data:]
if opconst.OpType(macroData[0]) != opconst.TypeMacro {
if OpType(macroData[0]) != TypeMacro {
panic("invalid macro reference")
}
var opDef opMacroDef
opDef.decode(macroData[:opconst.TypeMacro.Size()])
opDef.decode(macroData[:TypeMacro.Size()])
retPC := r.pc
retPC.data += n
retPC.refs += nrefs
@@ -156,10 +144,10 @@ func (r *Reader) Decode() (EncodedOp, bool) {
})
r.ops = op.ops
r.pc = op.pc
r.pc.data += opconst.TypeMacro.Size()
r.pc.refs += opconst.TypeMacro.NumRefs()
r.pc.data += TypeMacro.Size()
r.pc.refs += TypeMacro.NumRefs()
continue
case opconst.TypeMacro:
case TypeMacro:
var op opMacroDef
op.decode(data)
r.pc = op.endpc
@@ -172,7 +160,7 @@ func (r *Reader) Decode() (EncodedOp, bool) {
}
func (op *opMacroDef) decode(data []byte) {
if opconst.OpType(data[0]) != opconst.TypeMacro {
if OpType(data[0]) != TypeMacro {
panic("invalid op")
}
bo := binary.LittleEndian
@@ -188,7 +176,7 @@ func (op *opMacroDef) decode(data []byte) {
}
func (m *macroOp) decode(data []byte, refs []interface{}) {
if opconst.OpType(data[0]) != opconst.TypeCall {
if OpType(data[0]) != TypeCall {
panic("invalid op")
}
data = data[:9]
@@ -196,7 +184,7 @@ func (m *macroOp) decode(data []byte, refs []interface{}) {
dataIdx := int(int32(bo.Uint32(data[1:])))
refsIdx := int(int32(bo.Uint32(data[5:])))
*m = macroOp{
ops: refs[0].(*op.Ops),
ops: refs[0].(*Ops),
pc: PC{
data: dataIdx,
refs: refsIdx,
+5 -5
View File
@@ -3,7 +3,7 @@
package clipboard
import (
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/io/event"
"gioui.org/op"
)
@@ -25,13 +25,13 @@ type WriteOp struct {
}
func (h ReadOp) Add(o *op.Ops) {
data := o.Write1(opconst.TypeClipboardReadLen, h.Tag)
data[0] = byte(opconst.TypeClipboardRead)
data := o.Internal.Write1(ops.TypeClipboardReadLen, h.Tag)
data[0] = byte(ops.TypeClipboardRead)
}
func (h WriteOp) Add(o *op.Ops) {
data := o.Write1(opconst.TypeClipboardWriteLen, &h.Text)
data[0] = byte(opconst.TypeClipboardWrite)
data := o.Internal.Write1(ops.TypeClipboardWriteLen, &h.Text)
data[0] = byte(ops.TypeClipboardWrite)
}
func (Event) ImplementsEvent() {}
+7 -7
View File
@@ -13,7 +13,7 @@ import (
"fmt"
"strings"
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/io/event"
"gioui.org/op"
)
@@ -145,22 +145,22 @@ func (h InputOp) Add(o *op.Ops) {
if h.Tag == nil {
panic("Tag must be non-nil")
}
data := o.Write1(opconst.TypeKeyInputLen, h.Tag)
data[0] = byte(opconst.TypeKeyInput)
data := o.Internal.Write1(ops.TypeKeyInputLen, h.Tag)
data[0] = byte(ops.TypeKeyInput)
data[1] = byte(h.Hint)
}
func (h SoftKeyboardOp) Add(o *op.Ops) {
data := o.Write(opconst.TypeKeySoftKeyboardLen)
data[0] = byte(opconst.TypeKeySoftKeyboard)
data := o.Internal.Write(ops.TypeKeySoftKeyboardLen)
data[0] = byte(ops.TypeKeySoftKeyboard)
if h.Show {
data[1] = 1
}
}
func (h FocusOp) Add(o *op.Ops) {
data := o.Write1(opconst.TypeKeyFocusLen, h.Tag)
data[0] = byte(opconst.TypeKeyFocus)
data := o.Internal.Write1(ops.TypeKeyFocusLen, h.Tag)
data[0] = byte(ops.TypeKeyFocus)
}
func (EditEvent) ImplementsEvent() {}
+23 -23
View File
@@ -10,7 +10,7 @@ import (
"time"
"gioui.org/f32"
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/io/event"
"gioui.org/io/key"
"gioui.org/op"
@@ -56,8 +56,8 @@ type AreaOp struct {
// AreaStack represents an AreaOp on the stack of areas.
type AreaStack struct {
ops *op.Ops
id op.StackID
ops *ops.Ops
id ops.StackID
macroID int
}
@@ -194,35 +194,35 @@ func Ellipse(size image.Rectangle) AreaOp {
// Push the current area to the stack and intersects the current area with the
// area represented by o.
func (o AreaOp) Push(ops *op.Ops) AreaStack {
id, macroID := ops.PushOp(op.AreaStack)
o.add(ops, true)
return AreaStack{ops: ops, id: id, macroID: macroID}
func (a AreaOp) Push(o *op.Ops) AreaStack {
id, macroID := o.Internal.PushOp(ops.AreaStack)
a.add(o, true)
return AreaStack{ops: &o.Internal, id: id, macroID: macroID}
}
func (o AreaOp) add(ops *op.Ops, push bool) {
data := ops.Write(opconst.TypeAreaLen)
data[0] = byte(opconst.TypeArea)
data[1] = byte(o.kind)
if o.PassThrough {
func (a AreaOp) add(o *op.Ops, push bool) {
data := o.Internal.Write(ops.TypeAreaLen)
data[0] = byte(ops.TypeArea)
data[1] = byte(a.kind)
if a.PassThrough {
data[2] = 1
}
bo := binary.LittleEndian
bo.PutUint32(data[3:], uint32(o.rect.Min.X))
bo.PutUint32(data[7:], uint32(o.rect.Min.Y))
bo.PutUint32(data[11:], uint32(o.rect.Max.X))
bo.PutUint32(data[15:], uint32(o.rect.Max.Y))
bo.PutUint32(data[3:], uint32(a.rect.Min.X))
bo.PutUint32(data[7:], uint32(a.rect.Min.Y))
bo.PutUint32(data[11:], uint32(a.rect.Max.X))
bo.PutUint32(data[15:], uint32(a.rect.Max.Y))
}
func (o AreaStack) Pop() {
o.ops.PopOp(op.AreaStack, o.id, o.macroID)
data := o.ops.Write(opconst.TypePopAreaLen)
data[0] = byte(opconst.TypePopArea)
o.ops.PopOp(ops.AreaStack, o.id, o.macroID)
data := o.ops.Write(ops.TypePopAreaLen)
data[0] = byte(ops.TypePopArea)
}
func (op CursorNameOp) Add(o *op.Ops) {
data := o.Write1(opconst.TypeCursorLen, op.Name)
data[0] = byte(opconst.TypeCursor)
data := o.Internal.Write1(ops.TypeCursorLen, op.Name)
data[0] = byte(ops.TypeCursor)
}
// Add panics if the scroll range does not contain zero.
@@ -233,8 +233,8 @@ func (op InputOp) Add(o *op.Ops) {
if b := op.ScrollBounds; b.Min.X > 0 || b.Max.X < 0 || b.Min.Y > 0 || b.Max.Y < 0 {
panic(fmt.Errorf("invalid scroll range value %v", b))
}
data := o.Write1(opconst.TypePointerInputLen, op.Tag)
data[0] = byte(opconst.TypePointerInput)
data := o.Internal.Write1(ops.TypePointerInputLen, op.Tag)
data[0] = byte(ops.TypePointerInput)
if op.Grab {
data[1] = 1
}
+3 -3
View File
@@ -5,7 +5,7 @@
package profile
import (
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/io/event"
"gioui.org/op"
)
@@ -24,8 +24,8 @@ type Event struct {
}
func (p Op) Add(o *op.Ops) {
data := o.Write1(opconst.TypeProfileLen, p.Tag)
data[0] = byte(opconst.TypeProfile)
data := o.Internal.Write1(ops.TypeProfileLen, p.Tag)
data[0] = byte(ops.TypeProfile)
}
func (p Event) ImplementsEvent() {}
+8 -9
View File
@@ -3,7 +3,6 @@
package router
import (
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/io/event"
"gioui.org/io/key"
@@ -61,7 +60,7 @@ func (q *keyQueue) Frame(root *op.Ops, events *handlerEvents) {
for _, h := range q.handlers {
h.visible, h.new = false, false
}
q.reader.Reset(root)
q.reader.Reset(&root.Internal)
focus, changed, state := q.resolveFocus(events)
for k, h := range q.handlers {
@@ -104,19 +103,19 @@ func (q *keyQueue) Push(e event.Event, events *handlerEvents) {
func (q *keyQueue) resolveFocus(events *handlerEvents) (focus event.Tag, changed bool, state TextInputState) {
for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() {
switch opconst.OpType(encOp.Data[0]) {
case opconst.TypeKeyFocus:
switch ops.OpType(encOp.Data[0]) {
case ops.TypeKeyFocus:
op := decodeFocusOp(encOp.Data, encOp.Refs)
changed = true
focus = op.Tag
case opconst.TypeKeySoftKeyboard:
case ops.TypeKeySoftKeyboard:
op := decodeSoftKeyboardOp(encOp.Data, encOp.Refs)
if op.Show {
state = TextInputOpen
} else {
state = TextInputClose
}
case opconst.TypeKeyInput:
case ops.TypeKeyInput:
op := decodeKeyInputOp(encOp.Data, encOp.Refs)
h, ok := q.handlers[op.Tag]
if !ok {
@@ -131,7 +130,7 @@ func (q *keyQueue) resolveFocus(events *handlerEvents) (focus event.Tag, changed
}
func decodeKeyInputOp(d []byte, refs []interface{}) key.InputOp {
if opconst.OpType(d[0]) != opconst.TypeKeyInput {
if ops.OpType(d[0]) != ops.TypeKeyInput {
panic("invalid op")
}
return key.InputOp{
@@ -141,7 +140,7 @@ func decodeKeyInputOp(d []byte, refs []interface{}) key.InputOp {
}
func decodeSoftKeyboardOp(d []byte, refs []interface{}) key.SoftKeyboardOp {
if opconst.OpType(d[0]) != opconst.TypeKeySoftKeyboard {
if ops.OpType(d[0]) != ops.TypeKeySoftKeyboard {
panic("invalid op")
}
return key.SoftKeyboardOp{
@@ -150,7 +149,7 @@ func decodeSoftKeyboardOp(d []byte, refs []interface{}) key.SoftKeyboardOp {
}
func decodeFocusOp(d []byte, refs []interface{}) key.FocusOp {
if opconst.OpType(d[0]) != opconst.TypeKeyFocus {
if ops.OpType(d[0]) != ops.TypeKeyFocus {
panic("invalid op")
}
return key.FocusOp{
+11 -12
View File
@@ -7,7 +7,6 @@ import (
"image"
"gioui.org/f32"
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/io/event"
"gioui.org/io/pointer"
@@ -107,15 +106,15 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents) {
}
reset()
for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() {
switch opconst.OpType(encOp.Data[0]) {
case opconst.TypeSave:
switch ops.OpType(encOp.Data[0]) {
case ops.TypeSave:
id := ops.DecodeSave(encOp.Data)
q.save(id, state.t)
case opconst.TypeLoad:
case ops.TypeLoad:
reset()
id := ops.DecodeLoad(encOp.Data)
state.t = q.states[id]
case opconst.TypeArea:
case ops.TypeArea:
var op areaOp
op.Decode(encOp.Data)
area := -1
@@ -130,21 +129,21 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents) {
area: len(q.areas) - 1,
})
state.node = len(q.hitTree) - 1
case opconst.TypePopArea:
case ops.TypePopArea:
n := len(q.nodeStack)
state.node = q.nodeStack[n-1]
q.nodeStack = q.nodeStack[:n-1]
case opconst.TypeTransform:
case ops.TypeTransform:
dop, push := ops.DecodeTransform(encOp.Data)
if push {
q.transStack = append(q.transStack, state.t)
}
state.t = state.t.Mul(dop)
case opconst.TypePopTransform:
case ops.TypePopTransform:
n := len(q.transStack)
state.t = q.transStack[n-1]
q.transStack = q.transStack[:n-1]
case opconst.TypePointerInput:
case ops.TypePointerInput:
op := pointer.InputOp{
Tag: encOp.Refs[0].(event.Tag),
Grab: encOp.Data[1] != 0,
@@ -184,7 +183,7 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents) {
Y: int(int32(bo(encOp.Data[15:]))),
},
}
case opconst.TypeCursor:
case ops.TypeCursor:
q.cursors = append(q.cursors, cursorNode{
name: encOp.Refs[0].(pointer.CursorName),
area: len(q.areas) - 1,
@@ -258,7 +257,7 @@ func (q *pointerQueue) Frame(root *op.Ops, events *handlerEvents) {
q.nodeStack = q.nodeStack[:0]
q.transStack = q.transStack[:0]
q.cursors = q.cursors[:0]
q.reader.Reset(root)
q.reader.Reset(&root.Internal)
q.collectHandlers(&q.reader, events)
for k, h := range q.handlers {
if !h.active {
@@ -476,7 +475,7 @@ func opDecodeFloat32(d []byte) float32 {
}
func (op *areaOp) Decode(d []byte) {
if opconst.OpType(d[0]) != opconst.TypeArea {
if ops.OpType(d[0]) != ops.TypeArea {
panic("invalid op")
}
rect := f32.Rectangle{
+2 -2
View File
@@ -761,14 +761,14 @@ func BenchmarkAreaOp_Decode(b *testing.B) {
ops := new(op.Ops)
pointer.Rect(image.Rectangle{Max: image.Pt(100, 100)}).Push(ops).Pop()
for i := 0; i < b.N; i++ {
benchAreaOp.Decode(ops.Data())
benchAreaOp.Decode(ops.Internal.Data())
}
}
func BenchmarkAreaOp_Hit(b *testing.B) {
ops := new(op.Ops)
pointer.Rect(image.Rectangle{Max: image.Pt(100, 100)}).Push(ops).Pop()
benchAreaOp.Decode(ops.Data())
benchAreaOp.Decode(ops.Internal.Data())
for i := 0; i < b.N; i++ {
benchAreaOp.Hit(f32.Pt(50, 50))
}
+8 -9
View File
@@ -14,7 +14,6 @@ import (
"encoding/binary"
"time"
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/io/clipboard"
"gioui.org/io/event"
@@ -68,7 +67,7 @@ func (q *Router) Frame(ops *op.Ops) {
for k := range q.profHandlers {
delete(q.profHandlers, k)
}
q.reader.Reset(ops)
q.reader.Reset(&ops.Internal)
q.collect()
q.pqueue.Frame(ops, &q.handlers)
@@ -126,22 +125,22 @@ func (q *Router) Cursor() pointer.CursorName {
func (q *Router) collect() {
for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() {
switch opconst.OpType(encOp.Data[0]) {
case opconst.TypeInvalidate:
switch ops.OpType(encOp.Data[0]) {
case ops.TypeInvalidate:
op := decodeInvalidateOp(encOp.Data)
if !q.wakeup || op.At.Before(q.wakeupTime) {
q.wakeup = true
q.wakeupTime = op.At
}
case opconst.TypeProfile:
case ops.TypeProfile:
op := decodeProfileOp(encOp.Data, encOp.Refs)
if q.profHandlers == nil {
q.profHandlers = make(map[event.Tag]struct{})
}
q.profHandlers[op.Tag] = struct{}{}
case opconst.TypeClipboardRead:
case ops.TypeClipboardRead:
q.cqueue.ProcessReadClipboard(encOp.Refs)
case opconst.TypeClipboardWrite:
case ops.TypeClipboardWrite:
q.cqueue.ProcessWriteClipboard(encOp.Refs)
}
}
@@ -206,7 +205,7 @@ func (h *handlerEvents) Clear() {
}
func decodeProfileOp(d []byte, refs []interface{}) profile.Op {
if opconst.OpType(d[0]) != opconst.TypeProfile {
if ops.OpType(d[0]) != ops.TypeProfile {
panic("invalid op")
}
return profile.Op{
@@ -216,7 +215,7 @@ func decodeProfileOp(d []byte, refs []interface{}) profile.Op {
func decodeInvalidateOp(d []byte) op.InvalidateOp {
bo := binary.LittleEndian
if opconst.OpType(d[0]) != opconst.TypeInvalidate {
if ops.OpType(d[0]) != ops.TypeInvalidate {
panic("invalid op")
}
var o op.InvalidateOp
+25 -26
View File
@@ -9,7 +9,6 @@ import (
"math"
"gioui.org/f32"
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/internal/scene"
"gioui.org/internal/stroke"
@@ -28,8 +27,8 @@ type Op struct {
// Stack represents an Op pushed on the clip stack.
type Stack struct {
ops *op.Ops
id op.StackID
ops *ops.Ops
id ops.StackID
macroID int
}
@@ -42,9 +41,9 @@ func init() {
// Push saves the current clip state on the stack and updates the current
// state to the intersection of the current p.
func (p Op) Push(o *op.Ops) Stack {
id, macroID := o.PushOp(op.ClipStack)
id, macroID := o.Internal.PushOp(ops.ClipStack)
p.add(o, true)
return Stack{ops: o, id: id, macroID: macroID}
return Stack{ops: &o.Internal, id: id, macroID: macroID}
}
// Add is like Push except it doesn't save the current state on the stack.
@@ -69,8 +68,8 @@ func (p Op) add(o *op.Ops, push bool) {
bo := binary.LittleEndian
if path.hasSegments {
data := o.Write(opconst.TypePathLen)
data[0] = byte(opconst.TypePath)
data := o.Internal.Write(ops.TypePathLen)
data[0] = byte(ops.TypePath)
bo.PutUint64(data[1:], path.hash)
path.spec.Add(o)
}
@@ -83,14 +82,14 @@ func (p Op) add(o *op.Ops, push bool) {
bounds.Min.Y -= half
bounds.Max.X += half
bounds.Max.Y += half
data := o.Write(opconst.TypeStrokeLen)
data[0] = byte(opconst.TypeStroke)
data := o.Internal.Write(ops.TypeStrokeLen)
data[0] = byte(ops.TypeStroke)
bo := binary.LittleEndian
bo.PutUint32(data[1:], math.Float32bits(str.Width))
}
data := o.Write(opconst.TypeClipLen)
data[0] = byte(opconst.TypeClip)
data := o.Internal.Write(ops.TypeClipLen)
data[0] = byte(ops.TypeClip)
bo.PutUint32(data[1:], uint32(bounds.Min.X))
bo.PutUint32(data[5:], uint32(bounds.Min.Y))
bo.PutUint32(data[9:], uint32(bounds.Max.X))
@@ -104,9 +103,9 @@ func (p Op) add(o *op.Ops, push bool) {
}
func (s Stack) Pop() {
s.ops.PopOp(op.ClipStack, s.id, s.macroID)
data := s.ops.Write(opconst.TypePopClipLen)
data[0] = byte(opconst.TypePopClip)
s.ops.PopOp(ops.ClipStack, s.id, s.macroID)
data := s.ops.Write(ops.TypePopClipLen)
data[0] = byte(ops.TypePopClip)
}
func (p Op) approximateStroke(o *op.Ops) PathSpec {
@@ -117,28 +116,28 @@ func (p Op) approximateStroke(o *op.Ops) PathSpec {
var r ops.Reader
// Add path op for us to decode. Use a macro to omit it from later decodes.
ignore := op.Record(o)
r.ResetAt(o, ops.NewPC(o))
r.ResetAt(&o.Internal, o.Internal.PC())
p.path.spec.Add(o)
ignore.Stop()
encOp, ok := r.Decode()
if !ok || opconst.OpType(encOp.Data[0]) != opconst.TypeAux {
if !ok || ops.OpType(encOp.Data[0]) != ops.TypeAux {
panic("corrupt path data")
}
pathData := encOp.Data[opconst.TypeAuxLen:]
pathData := encOp.Data[ops.TypeAuxLen:]
// Decode dashes in a similar way.
var dashes stroke.DashOp
if p.dashes.phase != 0 || p.dashes.size > 0 {
ignore := op.Record(o)
r.ResetAt(o, ops.NewPC(o))
r.ResetAt(&o.Internal, o.Internal.PC())
p.dashes.spec.Add(o)
ignore.Stop()
encOp, ok := r.Decode()
if !ok || opconst.OpType(encOp.Data[0]) != opconst.TypeAux {
if !ok || ops.OpType(encOp.Data[0]) != ops.TypeAux {
panic("corrupt dash data")
}
dashes.Dashes = make([]float32, p.dashes.size)
dashData := encOp.Data[opconst.TypeAuxLen:]
dashData := encOp.Data[ops.TypeAuxLen:]
bo := binary.LittleEndian
for i := range dashes.Dashes {
dashes.Dashes[i] = math.Float32frombits(bo.Uint32(dashData[i*4:]))
@@ -188,7 +187,7 @@ type PathSpec struct {
// Path generates no garbage and can be used for dynamic paths; path
// data is stored directly in the Ops list supplied to Begin.
type Path struct {
ops *op.Ops
ops *ops.Ops
open bool
contour int
pen f32.Point
@@ -203,13 +202,13 @@ type Path struct {
func (p *Path) Pos() f32.Point { return p.pen }
// Begin the path, storing the path data and final Op into ops.
func (p *Path) Begin(ops *op.Ops) {
func (p *Path) Begin(o *op.Ops) {
p.hash.SetSeed(pathSeed)
p.ops = ops
p.macro = op.Record(ops)
p.ops = &o.Internal
p.macro = op.Record(o)
// Write the TypeAux opcode
data := ops.Write(opconst.TypeAuxLen)
data[0] = byte(opconst.TypeAux)
data := p.ops.Write(ops.TypeAuxLen)
data[0] = byte(ops.TypeAux)
}
// End returns a PathSpec ready to use in clipping operations.
+7 -7
View File
@@ -6,7 +6,7 @@ import (
"encoding/binary"
"math"
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/op"
)
@@ -73,18 +73,18 @@ const (
// Dash records dashes' lengths and phase for a stroked path.
type Dash struct {
ops *op.Ops
ops *ops.Ops
macro op.MacroOp
phase float32
size uint8 // size of the pattern
}
func (d *Dash) Begin(ops *op.Ops) {
d.ops = ops
d.macro = op.Record(ops)
func (d *Dash) Begin(o *op.Ops) {
d.ops = &o.Internal
d.macro = op.Record(o)
// Write the TypeAux opcode
data := ops.Write(opconst.TypeAuxLen)
data[0] = byte(opconst.TypeAux)
data := d.ops.Write(ops.TypeAuxLen)
data[0] = byte(ops.TypeAux)
}
func (d *Dash) Phase(v float32) {
+40 -200
View File
@@ -72,55 +72,29 @@ import (
"time"
"gioui.org/f32"
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
)
// Ops holds a list of operations. Operations are stored in
// serialized form to avoid garbage during construction of
// the ops list.
type Ops struct {
// version is incremented at each Reset.
version int
// data contains the serialized operations.
data []byte
// refs hold external references for operations.
refs []interface{}
// nextStateID is the id allocated for the next
// StateOp.
nextStateID int
macroStack stack
stacks [3]stack
}
type StackKind uint8
const (
ClipStack StackKind = iota
AreaStack
TransStack
)
// stateOp represents a saved operation snapshop to be restored
// later.
type stateOp struct {
id int
macroID int
ops *Ops
// Internal is for internal use, despite being exported.
Internal ops.Ops
}
// MacroOp records a list of operations for later use.
type MacroOp struct {
ops *Ops
id StackID
pc pc
ops *ops.Ops
id ops.StackID
pc ops.PC
}
// CallOp invokes the operations recorded by Record.
type CallOp struct {
// Ops is the list of operations to invoke.
ops *Ops
pc pc
ops *ops.Ops
pc ops.PC
}
// InvalidateOp requests a redraw at the given time. Use
@@ -137,26 +111,9 @@ type TransformOp struct {
// TransformStack represents a TransformOp pushed on the transformation stack.
type TransformStack struct {
id StackID
id ops.StackID
macroID int
ops *Ops
}
// stack tracks the integer identities of stack operations to ensure correct
// pairing of their push and pop methods.
type stack struct {
currentID int
nextID int
}
type StackID struct {
id int
prev int
}
type pc struct {
data int
refs int
ops *ops.Ops
}
// Defer executes c after all other operations have completed, including
@@ -170,23 +127,23 @@ func Defer(o *Ops, c CallOp) {
if c.ops == nil {
return
}
state := save(o)
state := o.Internal.Save()
// Wrap c in a macro that loads the saved state before execution.
m := Record(o)
state.load()
state.Load()
c.Add(o)
c = m.Stop()
// A Defer is recorded as a TypeDefer followed by the
// wrapped macro.
data := o.Write(opconst.TypeDeferLen)
data[0] = byte(opconst.TypeDefer)
data := o.Internal.Write(ops.TypeDeferLen)
data[0] = byte(ops.TypeDefer)
c.Add(o)
}
type SaveStack struct {
ops *Ops
ops *ops.Ops
clip struct {
id StackID
id ops.StackID
macroID int
}
trans TransformStack
@@ -196,17 +153,17 @@ type SaveStack struct {
// etc.).
func Save(o *Ops) SaveStack {
st := SaveStack{
ops: o,
ops: &o.Internal,
trans: Offset(f32.Point{}).Push(o),
}
const inf = 1e6
bounds := image.Rectangle{Min: image.Pt(-inf, -inf), Max: image.Pt(inf, inf)}
{
st.clip.id, st.clip.macroID = o.PushOp(ClipStack)
st.clip.id, st.clip.macroID = o.Internal.PushOp(ops.ClipStack)
// Push clip stack with no-op (infinite) clipping rect. Copied from clip.Op.Push.
bo := binary.LittleEndian
data := o.Write(opconst.TypeClipLen)
data[0] = byte(opconst.TypeClip)
data := o.Internal.Write(ops.TypeClipLen)
data[0] = byte(ops.TypeClip)
bo.PutUint32(data[1:], uint32(bounds.Min.X))
bo.PutUint32(data[5:], uint32(bounds.Min.Y))
bo.PutUint32(data[9:], uint32(bounds.Max.X))
@@ -219,113 +176,28 @@ func Save(o *Ops) SaveStack {
func (s SaveStack) Load() {
// Pop clip.
s.ops.PopOp(ClipStack, s.clip.id, s.clip.macroID)
data := s.ops.Write(opconst.TypePopClipLen)
data[0] = byte(opconst.TypePopClip)
s.ops.PopOp(ops.ClipStack, s.clip.id, s.clip.macroID)
data := s.ops.Write(ops.TypePopClipLen)
data[0] = byte(ops.TypePopClip)
s.trans.Pop()
}
// save the effective transformation.
func save(o *Ops) stateOp {
o.nextStateID++
s := stateOp{
ops: o,
id: o.nextStateID,
macroID: o.macroStack.currentID,
}
bo := binary.LittleEndian
data := o.Write(opconst.TypeSaveLen)
data[0] = byte(opconst.TypeSave)
bo.PutUint32(data[1:], uint32(s.id))
return s
}
// load a previously saved operations state given
// its ID.
func (s stateOp) load() {
bo := binary.LittleEndian
data := s.ops.Write(opconst.TypeLoadLen)
data[0] = byte(opconst.TypeLoad)
bo.PutUint32(data[1:], uint32(s.id))
}
// Reset the Ops, preparing it for re-use. Reset invalidates
// any recorded macros.
func (o *Ops) Reset() {
o.macroStack = stack{}
for i := range o.stacks {
o.stacks[i] = stack{}
}
// Leave references to the GC.
for i := range o.refs {
o.refs[i] = nil
}
o.data = o.data[:0]
o.refs = o.refs[:0]
o.nextStateID = 0
o.version++
}
// Data is for internal use only.
func (o *Ops) Data() []byte {
return o.data
}
// Refs is for internal use only.
func (o *Ops) Refs() []interface{} {
return o.refs
}
// Version is for internal use only.
func (o *Ops) Version() int {
return o.version
}
// Write is for internal use only.
func (o *Ops) Write(n int) []byte {
o.data = append(o.data, make([]byte, n)...)
return o.data[len(o.data)-n:]
}
func (o *Ops) PushOp(kind StackKind) (StackID, int) {
return o.stacks[kind].push(), o.macroStack.currentID
}
func (o *Ops) PopOp(kind StackKind, sid StackID, macroID int) {
if o.macroStack.currentID != macroID {
panic("stack push and pop must not cross macro boundary")
}
o.stacks[kind].pop(sid)
}
// Write1 is for internal use only.
func (o *Ops) Write1(n int, ref1 interface{}) []byte {
o.data = append(o.data, make([]byte, n)...)
o.refs = append(o.refs, ref1)
return o.data[len(o.data)-n:]
}
// Write2 is for internal use only.
func (o *Ops) Write2(n int, ref1, ref2 interface{}) []byte {
o.data = append(o.data, make([]byte, n)...)
o.refs = append(o.refs, ref1, ref2)
return o.data[len(o.data)-n:]
}
func (o *Ops) pc() pc {
return pc{data: len(o.data), refs: len(o.refs)}
o.Internal.Reset()
}
// Record a macro of operations.
func Record(o *Ops) MacroOp {
m := MacroOp{
ops: o,
id: o.macroStack.push(),
pc: o.pc(),
ops: &o.Internal,
id: o.Internal.PushMacro(),
pc: o.Internal.PC(),
}
// Reserve room for a macro definition. Updated in Stop.
m.ops.Write(opconst.TypeMacroLen)
m.ops.Write(ops.TypeMacroLen)
m.fill()
return m
}
@@ -333,7 +205,7 @@ func Record(o *Ops) MacroOp {
// Stop ends a previously started recording and returns an
// operation for replaying it.
func (m MacroOp) Stop() CallOp {
m.ops.macroStack.pop(m.id)
m.ops.PopMacro(m.id)
m.fill()
return CallOp{
ops: m.ops,
@@ -342,14 +214,7 @@ func (m MacroOp) Stop() CallOp {
}
func (m MacroOp) fill() {
pc := m.ops.pc()
// Fill out the macro definition reserved in Record.
data := m.ops.data[m.pc.data:]
data = data[:opconst.TypeMacroLen]
data[0] = byte(opconst.TypeMacro)
bo := binary.LittleEndian
bo.PutUint32(data[1:], uint32(pc.data))
bo.PutUint32(data[5:], uint32(pc.refs))
m.ops.FillMacro(m.pc)
}
// Add the recorded list of operations. Add
@@ -359,16 +224,12 @@ func (c CallOp) Add(o *Ops) {
if c.ops == nil {
return
}
data := o.Write1(opconst.TypeCallLen, c.ops)
data[0] = byte(opconst.TypeCall)
bo := binary.LittleEndian
bo.PutUint32(data[1:], uint32(c.pc.data))
bo.PutUint32(data[5:], uint32(c.pc.refs))
o.Internal.AddCall(c.ops, c.pc)
}
func (r InvalidateOp) Add(o *Ops) {
data := o.Write(opconst.TypeRedrawLen)
data[0] = byte(opconst.TypeInvalidate)
data := o.Internal.Write(ops.TypeRedrawLen)
data[0] = byte(ops.TypeInvalidate)
bo := binary.LittleEndian
// UnixNano cannot represent the zero time.
if t := r.At; !t.IsZero() {
@@ -392,9 +253,9 @@ func Affine(a f32.Affine2D) TransformOp {
// Push the current transformation to the stack and then multiply the
// current transformation with t.
func (t TransformOp) Push(o *Ops) TransformStack {
id, macroID := o.PushOp(TransStack)
id, macroID := o.Internal.PushOp(ops.TransStack)
t.add(o, true)
return TransformStack{ops: o, id: id, macroID: macroID}
return TransformStack{ops: &o.Internal, id: id, macroID: macroID}
}
// Add is like Push except it doesn't push the current transformation to the
@@ -404,8 +265,8 @@ func (t TransformOp) Add(o *Ops) {
}
func (t TransformOp) add(o *Ops, push bool) {
data := o.Write(opconst.TypeTransformLen)
data[0] = byte(opconst.TypeTransform)
data := o.Internal.Write(ops.TypeTransformLen)
data[0] = byte(ops.TypeTransform)
if push {
data[1] = 1
}
@@ -420,28 +281,7 @@ func (t TransformOp) add(o *Ops, push bool) {
}
func (t TransformStack) Pop() {
t.ops.PopOp(TransStack, t.id, t.macroID)
data := t.ops.Write(opconst.TypePopTransformLen)
data[0] = byte(opconst.TypePopTransform)
}
func (s *stack) push() StackID {
s.nextID++
sid := StackID{
id: s.nextID,
prev: s.currentID,
}
s.currentID = s.nextID
return sid
}
func (s *stack) check(sid StackID) {
if s.currentID != sid.id {
panic("unbalanced operation")
}
}
func (s *stack) pop(sid StackID) {
s.check(sid)
s.currentID = sid.prev
t.ops.PopOp(ops.TransStack, t.id, t.macroID)
data := t.ops.Write(ops.TypePopTransformLen)
data[0] = byte(ops.TypePopTransform)
}
+9 -9
View File
@@ -10,7 +10,7 @@ import (
"math"
"gioui.org/f32"
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/op"
"gioui.org/op/clip"
)
@@ -96,13 +96,13 @@ func (i ImageOp) Add(o *op.Ops) {
} else if i.src == nil || i.src.Bounds().Empty() {
return
}
data := o.Write2(opconst.TypeImageLen, i.src, i.handle)
data[0] = byte(opconst.TypeImage)
data := o.Internal.Write2(ops.TypeImageLen, i.src, i.handle)
data[0] = byte(ops.TypeImage)
}
func (c ColorOp) Add(o *op.Ops) {
data := o.Write(opconst.TypeColorLen)
data[0] = byte(opconst.TypeColor)
data := o.Internal.Write(ops.TypeColorLen)
data[0] = byte(ops.TypeColor)
data[1] = c.Color.R
data[2] = c.Color.G
data[3] = c.Color.B
@@ -110,8 +110,8 @@ func (c ColorOp) Add(o *op.Ops) {
}
func (c LinearGradientOp) Add(o *op.Ops) {
data := o.Write(opconst.TypeLinearGradientLen)
data[0] = byte(opconst.TypeLinearGradient)
data := o.Internal.Write(ops.TypeLinearGradientLen)
data[0] = byte(ops.TypeLinearGradient)
bo := binary.LittleEndian
bo.PutUint32(data[1:], math.Float32bits(c.Stop1.X))
@@ -130,8 +130,8 @@ func (c LinearGradientOp) Add(o *op.Ops) {
}
func (d PaintOp) Add(o *op.Ops) {
data := o.Write(opconst.TypePaintLen)
data[0] = byte(opconst.TypePaint)
data := o.Internal.Write(ops.TypePaintLen)
data[0] = byte(ops.TypePaint)
}
// FillShape fills the clip shape with a color.