diff options
Diffstat (limited to 'vendor/gioui.org/internal/ops/ops.go')
-rw-r--r-- | vendor/gioui.org/internal/ops/ops.go | 471 |
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") + } } |