| #ifndef _RIVE_SCRIPT_BACKEND_HPP_ |
| #define _RIVE_SCRIPT_BACKEND_HPP_ |
| |
| #include <stdint.h> |
| |
| #include "rive/hit_result.hpp" |
| #include "rive/input/focusable.hpp" |
| #include "rive/math/vec2d.hpp" |
| |
| #include <string> |
| #include <unordered_set> |
| |
| namespace rive |
| { |
| class Artboard; |
| class DataValue; |
| class ListenerInvocation; |
| class RawPath; |
| class Renderer; |
| class ScriptedContext; |
| class ScriptedObject; |
| class ShapePaint; |
| class ViewModelInstanceValue; |
| |
| /// The narrow waist between scripted core objects and a script execution |
| /// backend. Script values are held as opaque int refs minted and released by |
| /// the backend; ScriptedObject and friends never touch the engine directly. |
| /// Implementations: ScriptingVM (Luau) and, per the WAMR swap plan, |
| /// WasmScriptingVM. |
| class ScriptBackend |
| { |
| private: |
| float m_displayScale = 1.0f; |
| |
| public: |
| virtual ~ScriptBackend(); |
| |
| /// ScriptedObject holds a non-owning ScriptBackend*. The backend tracks |
| /// which objects point at it so teardown can null those pointers before |
| /// cascading destruction reaches them. |
| void registerScriptedObject(ScriptedObject* object); |
| void unregisterScriptedObject(ScriptedObject* object); |
| |
| virtual bool valid() const = 0; |
| virtual void releaseRef(int ref) = 0; |
| |
| /// Device pixels per layout point of the presenting surface; the |
| /// embedder reports it and layout resize callbacks pass it through so |
| /// scripts can size render targets in pixels. A changed value |
| /// re-announces every scripted layout's size, since a display hop |
| /// changes scale without reflowing anything. |
| void displayScale(float scale); |
| float displayScale() const { return m_displayScale; } |
| |
| /// The editor stores generator refs per context; backends without that |
| /// remap return the ref unchanged. |
| virtual int resolveGeneratorRef(int ref) const { return ref; } |
| |
| /// Runs the script's generator: creates the object's Context, calls |
| /// generator(context), refs the returned table. Returns the self ref or 0 |
| /// on failure; outContextRef/outContextPtr carry the created Context. |
| virtual int instantiate(int generatorRef, |
| ScriptedObject* object, |
| int* outContextRef, |
| ScriptedContext** outContextPtr) = 0; |
| |
| enum class InitResult : uint8_t |
| { |
| /// init is optional and absent; the object counts as initialized. |
| notImplemented, |
| succeeded, |
| /// init errored or returned false / requested missing data; the |
| /// caller tears the instance down. |
| failed, |
| }; |
| virtual InitResult callUserInit(ScriptedObject* object, |
| int selfRef, |
| int contextRef) = 0; |
| |
| /// self:advance(elapsedSeconds) -> bool; false when not implemented or on |
| /// error. |
| virtual bool callAdvance(ScriptedObject* object, |
| int selfRef, |
| float elapsedSeconds) = 0; |
| virtual void callUpdate(ScriptedObject* object, int selfRef) = 0; |
| /// self[name](self), for triggers. |
| virtual void callTrigger(ScriptedObject* object, |
| int selfRef, |
| const char* name) = 0; |
| /// self[name](self, args...) -> number. Returns false when the method is |
| /// not implemented or errors, leaving outResult untouched so the caller's |
| /// fallback stands. |
| virtual bool callNumberMethod(ScriptedObject* object, |
| int selfRef, |
| const char* name, |
| const float* args, |
| size_t argCount, |
| float* outResult) = 0; |
| /// self[name](self) -> bool; false unless the call succeeds and returns |
| /// an actual boolean true. |
| virtual bool callBooleanMethod(ScriptedObject* object, |
| int selfRef, |
| const char* name) = 0; |
| /// Path effect protocol: self.update(self, pathData(source), |
| /// node(shapePaint)) -> pathData appended into outPath. False on error. |
| virtual bool callPathEffectUpdate(ScriptedObject* object, |
| int selfRef, |
| const RawPath& sourcePath, |
| const ShapePaint* shapePaint, |
| RawPath* outPath) = 0; |
| |
| /// A script data value copied out of the engine before its holder can be |
| /// collected; kind none when the call produced nothing usable. |
| struct ScriptDataResult |
| { |
| enum class Kind : uint8_t |
| { |
| none, |
| number, |
| string, |
| boolean, |
| color, |
| }; |
| Kind kind = Kind::none; |
| float number = 0.0f; |
| std::string string; |
| bool boolean = false; |
| int color = 0; |
| }; |
| /// Data converter protocol: self[method](self, dataValue(input)). |
| /// Returns false when the method is not implemented, meaning the input |
| /// passes through unchanged. |
| virtual bool callDataConvert(ScriptedObject* object, |
| int selfRef, |
| const char* method, |
| DataValue* input, |
| ScriptDataResult* outResult) = 0; |
| |
| /// Listener protocol: self.performAction(self, invocation) when defined, |
| /// else legacy self.perform(self, pointerEvent). |
| virtual void callListenerPerform(ScriptedObject* object, |
| int selfRef, |
| const ListenerInvocation& invocation) = 0; |
| |
| /// Drawable protocol: self.draw(self, renderer(renderer)); the renderer |
| /// wrapper is scoped to this call. The caller owns save/transform/restore. |
| virtual void callDraw(ScriptedObject* object, |
| int selfRef, |
| Renderer* renderer) = 0; |
| /// Drawable protocol: gamepad connected/event/disconnected dispatch by |
| /// invocation kind; false when the method isn't implemented or the kind |
| /// carries no gamepad payload. |
| virtual bool callGamepadEvent(ScriptedObject* object, |
| int selfRef, |
| const char* method, |
| const ListenerInvocation& invocation) = 0; |
| /// Drawable protocol: self[method](self, pointerEvent(pointerId, local)). |
| /// False when not implemented; outResult carries the event's hit result. |
| virtual bool callPointerEvent(ScriptedObject* object, |
| int selfRef, |
| const char* method, |
| int pointerId, |
| Vec2D localPosition, |
| HitResult* outResult) = 0; |
| /// Drawable protocol: self.keyboardEvent(self, invocation) -> stop |
| /// propagation. |
| virtual bool callKeyboardEvent(ScriptedObject* object, |
| int selfRef, |
| Key key, |
| KeyModifiers modifiers, |
| bool isPressed, |
| bool isRepeat) = 0; |
| /// Drawable protocol: self.textEvent(self, invocation) -> stop |
| /// propagation. |
| virtual bool callTextEvent(ScriptedObject* object, |
| int selfRef, |
| const std::string& text) = 0; |
| |
| /// Layout protocol: self.resize(self, size). |
| virtual void callLayoutResize(ScriptedObject* object, |
| int selfRef, |
| Vec2D size) = 0; |
| /// Layout protocol: self.measure(self) -> vector. False only when the |
| /// method is not implemented; outSize is written only when the call |
| /// returns an actual vector. |
| virtual bool callLayoutMeasure(ScriptedObject* object, |
| int selfRef, |
| Vec2D* outSize) = 0; |
| |
| virtual void setInputBoolean(int selfRef, const char* name, bool value) = 0; |
| virtual void setInputNumber(int selfRef, const char* name, float value) = 0; |
| virtual void setInputUnsigned(int selfRef, |
| const char* name, |
| uint32_t value) = 0; |
| virtual void setInputString(int selfRef, |
| const char* name, |
| const char* value) = 0; |
| virtual void setInputArtboard(int selfRef, |
| const char* name, |
| ScriptedObject* object, |
| Artboard* artboard) = 0; |
| virtual void setInputViewModel(int selfRef, |
| const char* name, |
| ViewModelInstanceValue* value) = 0; |
| |
| protected: |
| /// Nulls every registered object's backend pointer, ahead of engine |
| /// teardown cascades that would otherwise reach a freed backend. |
| void detachScriptedObjects(); |
| |
| private: |
| std::unordered_set<ScriptedObject*> m_scriptedObjects; |
| }; |
| |
| } // namespace rive |
| |
| #endif |