aboutsummaryrefslogtreecommitdiff
path: root/vendor/gioui.org/internal/ops/ops.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gioui.org/internal/ops/ops.go')
-rw-r--r--vendor/gioui.org/internal/ops/ops.go471
1 files changed, 439 insertions, 32 deletions
diff --git a/vendor/gioui.org/internal/ops/ops.go b/vendor/gioui.org/internal/ops/ops.go
index c56b9d6..fece6d6 100644
--- a/vendor/gioui.org/internal/ops/ops.go
+++ b/vendor/gioui.org/internal/ops/ops.go
@@ -4,57 +4,321 @@ package ops
import (
"encoding/binary"
+ "image"
"math"
"gioui.org/f32"
- "gioui.org/internal/opconst"
+ "gioui.org/internal/byteslice"
+ "gioui.org/internal/scene"
)
-const QuadSize = 4 * 2 * 3
+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
-type Quad struct {
- From, Ctrl, To f32.Point
+ macroStack stack
+ stacks [5]stack
}
-func (q Quad) Transform(t f32.Affine2D) Quad {
- q.From = t.Transform(q.From)
- q.Ctrl = t.Transform(q.Ctrl)
- q.To = t.Transform(q.To)
- return q
+type OpType byte
+
+type Shape 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
+ TypePass
+ TypePopPass
+ TypePointerInput
+ TypeClipboardRead
+ TypeClipboardWrite
+ TypeSource
+ TypeTarget
+ TypeOffer
+ TypeKeyInput
+ TypeKeyFocus
+ TypeKeySoftKeyboard
+ TypeSave
+ TypeLoad
+ TypeAux
+ TypeClip
+ TypePopClip
+ TypeProfile
+ TypeCursor
+ TypePath
+ TypeStroke
+ TypeSemanticLabel
+ TypeSemanticDesc
+ TypeSemanticClass
+ TypeSemanticSelected
+ TypeSemanticDisabled
+)
+
+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
+
+// ClipOp is the shadow of clip.Op.
+type ClipOp struct {
+ Bounds image.Rectangle
+ Outline bool
+ Shape Shape
}
-func EncodeQuad(d []byte, q Quad) {
+const (
+ ClipStack StackKind = iota
+ TransStack
+ PassStack
+ MetaStack
+)
+
+const (
+ Path Shape = iota
+ Ellipse
+ Rect
+)
+
+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
+ TypePassLen = 1
+ TypePopPassLen = 1
+ TypePointerInputLen = 1 + 1 + 1*2 + 2*4 + 2*4
+ TypeClipboardReadLen = 1
+ TypeClipboardWriteLen = 1
+ TypeSourceLen = 1
+ TypeTargetLen = 1
+ TypeOfferLen = 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
+ TypeSemanticLabelLen = 1
+ TypeSemanticDescLen = 1
+ TypeSemanticClassLen = 2
+ TypeSemanticSelectedLen = 2
+ TypeSemanticDisabledLen = 2
+)
+
+func (op *ClipOp) Decode(data []byte) {
+ if OpType(data[0]) != TypeClip {
+ panic("invalid op")
+ }
bo := binary.LittleEndian
- bo.PutUint32(d[0:], math.Float32bits(q.From.X))
- bo.PutUint32(d[4:], math.Float32bits(q.From.Y))
- bo.PutUint32(d[8:], math.Float32bits(q.Ctrl.X))
- bo.PutUint32(d[12:], math.Float32bits(q.Ctrl.Y))
- bo.PutUint32(d[16:], math.Float32bits(q.To.X))
- bo.PutUint32(d[20:], math.Float32bits(q.To.Y))
+ r := image.Rectangle{
+ Min: image.Point{
+ X: int(int32(bo.Uint32(data[1:]))),
+ Y: int(int32(bo.Uint32(data[5:]))),
+ },
+ Max: image.Point{
+ X: int(int32(bo.Uint32(data[9:]))),
+ Y: int(int32(bo.Uint32(data[13:]))),
+ },
+ }
+ *op = ClipOp{
+ Bounds: r,
+ Outline: data[17] == 1,
+ Shape: Shape(data[18]),
+ }
}
-func DecodeQuad(d []byte) (q Quad) {
+func Reset(o *Ops) {
+ 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 Write(o *Ops, n int) []byte {
+ o.data = append(o.data, make([]byte, n)...)
+ return o.data[len(o.data)-n:]
+}
+
+func PushMacro(o *Ops) StackID {
+ return o.macroStack.push()
+}
+
+func PopMacro(o *Ops, id StackID) {
+ o.macroStack.pop(id)
+}
+
+func FillMacro(o *Ops, startPC PC) {
+ pc := PCFor(o)
+ // Fill out the macro definition reserved in Record.
+ data := o.data[startPC.data:]
+ data = data[:TypeMacroLen]
+ data[0] = byte(TypeMacro)
bo := binary.LittleEndian
- q.From.X = math.Float32frombits(bo.Uint32(d[0:]))
- q.From.Y = math.Float32frombits(bo.Uint32(d[4:]))
- q.Ctrl.X = math.Float32frombits(bo.Uint32(d[8:]))
- q.Ctrl.Y = math.Float32frombits(bo.Uint32(d[12:]))
- q.To.X = math.Float32frombits(bo.Uint32(d[16:]))
- q.To.Y = math.Float32frombits(bo.Uint32(d[20:]))
- return
+ bo.PutUint32(data[1:], uint32(pc.data))
+ bo.PutUint32(data[5:], uint32(pc.refs))
}
-func DecodeTransform(d []byte) (t f32.Affine2D) {
- if opconst.OpType(d[0]) != opconst.TypeTransform {
- panic("invalid op")
+func AddCall(o *Ops, callOps *Ops, pc PC) {
+ data := Write1(o, TypeCallLen, callOps)
+ data[0] = byte(TypeCall)
+ bo := binary.LittleEndian
+ bo.PutUint32(data[1:], uint32(pc.data))
+ bo.PutUint32(data[5:], uint32(pc.refs))
+}
+
+func PushOp(o *Ops, kind StackKind) (StackID, int) {
+ return o.stacks[kind].push(), o.macroStack.currentID
+}
+
+func PopOp(o *Ops, kind StackKind, sid StackID, macroID int) {
+ if o.macroStack.currentID != macroID {
+ panic("stack push and pop must not cross macro boundary")
}
- if len(d) < 1+6*4 {
- panic("too short buffer")
+ o.stacks[kind].pop(sid)
+}
+
+func Write1(o *Ops, 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 Write2(o *Ops, 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 Write3(o *Ops, n int, ref1, ref2, ref3 interface{}) []byte {
+ o.data = append(o.data, make([]byte, n)...)
+ o.refs = append(o.refs, ref1, ref2, ref3)
+ return o.data[len(o.data)-n:]
+}
+
+func PCFor(o *Ops) 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,
}
- return decodeAffine2D(d[1:])
+ 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 Save(o *Ops) StateOp {
+ o.nextStateID++
+ s := StateOp{
+ ops: o,
+ id: o.nextStateID,
+ macroID: o.macroStack.currentID,
+ }
+ bo := binary.LittleEndian
+ data := Write(o, 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 := Write(s.ops, 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)
+ return cmd
+}
+
+func EncodeCommand(out []byte, cmd scene.Command) {
+ copy(out, byteslice.Uint32(cmd[:]))
}
-func decodeAffine2D(data []byte) f32.Affine2D {
+func DecodeTransform(data []byte) (t f32.Affine2D, push bool) {
+ if OpType(data[0]) != TypeTransform {
+ panic("invalid op")
+ }
+ push = data[1] != 0
+ data = data[2:]
+ data = data[:4*6]
+
bo := binary.LittleEndian
a := math.Float32frombits(bo.Uint32(data))
b := math.Float32frombits(bo.Uint32(data[4*1:]))
@@ -62,5 +326,148 @@ func decodeAffine2D(data []byte) f32.Affine2D {
d := math.Float32frombits(bo.Uint32(data[4*3:]))
e := math.Float32frombits(bo.Uint32(data[4*4:]))
f := math.Float32frombits(bo.Uint32(data[4*5:]))
- return f32.NewAffine2D(a, b, c, d, e, f)
+ return f32.NewAffine2D(a, b, c, d, e, f), push
+}
+
+// DecodeSave decodes the state id of a save op.
+func DecodeSave(data []byte) int {
+ if OpType(data[0]) != TypeSave {
+ panic("invalid op")
+ }
+ bo := binary.LittleEndian
+ return int(bo.Uint32(data[1:]))
+}
+
+// DecodeLoad decodes the state id of a load op.
+func DecodeLoad(data []byte) int {
+ 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,
+ TypePassLen,
+ TypePopPassLen,
+ TypePointerInputLen,
+ TypeClipboardReadLen,
+ TypeClipboardWriteLen,
+ TypeSourceLen,
+ TypeTargetLen,
+ TypeOfferLen,
+ TypeKeyInputLen,
+ TypeKeyFocusLen,
+ TypeKeySoftKeyboardLen,
+ TypeSaveLen,
+ TypeLoadLen,
+ TypeAuxLen,
+ TypeClipLen,
+ TypePopClipLen,
+ TypeProfileLen,
+ TypeCursorLen,
+ TypePathLen,
+ TypeStrokeLen,
+ TypeSemanticLabelLen,
+ TypeSemanticDescLen,
+ TypeSemanticClassLen,
+ TypeSemanticSelectedLen,
+ TypeSemanticDisabledLen,
+ }[t-firstOpIndex]
+}
+
+func (t OpType) NumRefs() int {
+ switch t {
+ case TypeKeyInput, TypeKeyFocus, TypePointerInput, TypeProfile, TypeCall, TypeClipboardRead, TypeClipboardWrite, TypeCursor, TypeSemanticLabel, TypeSemanticDesc:
+ return 1
+ case TypeImage, TypeSource, TypeTarget:
+ return 2
+ case TypeOffer:
+ return 3
+ 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 TypePass:
+ return "Pass"
+ case TypePopPass:
+ return "PopPass"
+ case TypePointerInput:
+ return "PointerInput"
+ case TypeClipboardRead:
+ return "ClipboardRead"
+ case TypeClipboardWrite:
+ return "ClipboardWrite"
+ case TypeSource:
+ return "Source"
+ case TypeTarget:
+ return "Target"
+ case TypeOffer:
+ return "Offer"
+ 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"
+ case TypeSemanticLabel:
+ return "SemanticDescription"
+ default:
+ panic("unknown OpType")
+ }
}