fix(text input): put the caret after pre-filled text on focus without a press (#15258)

* fix(text input): put the caret after pre-filled text on focus without a press

Text set from outside (the file's own value, a data bind) leaves the caret
at the start, and focus only moved it for Tab or selectAllOnFocus. A field
focused on a state's entry, from code or by accessibility showed the caret
before its text, so typing went in front of it.

Focus now puts the caret after the text unless the user placed it since the
text was last set from outside: a press places it before focusing, and keys,
typing and earlier focus keep it, so refocusing finds it where the user left
it. Tab and selectAllOnFocus still select all.

Adds RawTextInput::moveCursorToEnd, exported to Dart (rawTextMoveCursorToEnd)
so the editor's TextInput behaves the same.

* fix(text input): place the caret at the end before the font arrives

A focus on a state's entry can land before the field's font is available,
and moveCursorToEnd shaped the text to resolve the caret's line, which
dereferences the missing font. Without a font, store the end position with
its line unresolved and let update() resolve it once the font arrives.

* fix(text input): select all before the font arrives

Tab or selectAllOnFocus can focus a field before its font is available, and
selectAll shaped the text to resolve the selection's lines, dereferencing
the missing font. selectAll and moveCursorToEnd now share positionAtIndex,
which leaves the line for update() to resolve when there is no font yet.

Also puts a test case header on one line, as clang-format 19 wants it.

* test(capture): let the user place the caret the claimed press must keep

The nested capture test set the caret through the raw input, which no longer
counts as placed, so the claim's focus action moved it after the text. Place
it with a key while focused instead: focus coming back keeps it, so the
caret still shows the input's press handling never ran.

Rive-Mono-Commit: 8199ff51213dda03caf4427c394ddcce0856db41
7 files changed
tree: 5a198b276f5105decfb3333092df39b9d7f2ec5a
  1. .github/
  2. .vscode/
  3. build/
  4. decoders/
  5. dependencies/
  6. dev/
  7. include/
  8. renderer/
  9. rivinfo/
  10. scripting/
  11. skia/
  12. src/
  13. tests/
  14. utils/
  15. .dockerignore
  16. .gitattributes
  17. .gitignore
  18. .lua-format
  19. .rive_head
  20. .version
  21. Dockerfile
  22. Doxyfile
  23. dummy.cpp
  24. LICENSE
  25. premake5_v2.lua
  26. README.md
  27. runtime.natvis
README.md

Build Status Discord badge Twitter handle

rive-runtime

Rive hero image

Rive's C++ runtime — the lowest-level Rive runtime. Loads .riv files, advances state machines and animations, and draws via the abstract Renderer interface. The built-in GPU renderer (RiveRenderer) has RenderContextImpl backends for Metal, Vulkan, D3D11, D3D12, and OpenGL/WebGL.

Rive's Apple, Android, Flutter, Unity, Unreal, and web runtimes all wrap this library.

Features:

  • Loading artboards and their contents from .riv files.
  • Querying state machines from artboards.
  • Mutating the artboard hierarchy (the same mechanism used by state machines) and efficiently solving those changes via Artboard::advance.
  • A state-of-the-art vector renderer for Metal, Vulkan, D3D12, D3D11, and OpenGL/WebGL.
  • An abstract Renderer interface for hooking up an external vector renderer.

Prerequisites

  • A C++17 toolchain:
    • macOS: clang from Xcode Command Line Tools (xcode-select --install).
    • Linux: clang from your distro (e.g. apt install clang).
    • Windows: Visual Studio 2022 with the C++ Clang Compiler for Windows and MSBuild support for LLVM (clang-cl) toolset individual components.
  • git — the build script clones a pinned premake5 on first run. On Windows, install Git for Windows and during setup pick “Use Git and optional Unix tools from the Command Prompt” so that sh.exe ends up on PATH.
  • Platform SDK for the renderer you're targeting:
    • macOS / iOS: Xcode.
    • Windows: Windows SDK (for D3D).
    • Linux: a Vulkan or OpenGL development environment.
    • Vulkan: the Vulkan SDK.

Build

The build is driven by premake5 wrapped by a helper script:

  • build/build_rive.sh — macOS / Linux (bash) / Windows (MinGW).
  • build/build_rive.ps1 — a PowerShell convenience wrapper for Windows; it shells out to the bash script, so a bash environment (Git for Windows / MinGW, see Prerequisites) must still be on PATH.

The helper self-installs the pinned premake version on first run and dispatches to the right build system for your platform (gmake2 on macOS/Linux, MSBuild on Windows). It must be run from a directory that contains a premake5.lua — typically tests/, which builds the core library, the GPU renderer, and the player sample app.

macOS / Linux

git clone https://github.com/rive-app/rive-runtime.git
cd rive-runtime/tests
../build/build_rive.sh release

Windows

git clone https://github.com/rive-app/rive-runtime.git
cd rive-runtime\tests
..\build\build_rive.ps1 release

Common variants

(On Windows, substitute build_rive.ps1 for build_rive.sh.)

  • build_rive.sh (no args) — debug build for the host.
  • build_rive.sh release clean — clean then build release.
  • build_rive.sh ninja release — use Ninja instead of make/MSBuild.
  • build_rive.sh ios release — cross-compile for iOS.
  • build_rive.sh android release — cross-compile for Android (defaults to arm64).
  • build_rive.sh ninja release wasm — cross-compile for WebAssembly.
  • build_rive.sh --toolset=msc release (Windows) — build with MSVC's cl.exe instead of clang-cl. The build supports both toolchains; the lua warning suppressions cover MSVC too.

See the comment header at the top of build/build_rive.sh for the complete flag reference.

Build outputs

Artifacts land in out/<config>/ relative to the directory you built from (typically tests/). The config directory encodes any OS/arch flags you passed:

  • out/release, out/debug — host build.
  • out/ios_release, out/android_arm64_release, out/wasm_release — cross-compile builds.
ArtifactDescription
librive.a / rive.libCore runtime library.
librive_pls_renderer.a / rive_pls_renderer.libGPU renderer.
player / player.exeSample app — loads and renders a .riv file.
out/<config>/goldens, out/<config>/gms, out/<config>/benchTest harness binaries (regression, golden-image, benchmarking).
librive_decoders.a, librive_harfbuzz.a, …Supporting libraries.

Testing

The runtime's primary form of testing is golden testing — rendering known scenes and diffing the output against checked-in reference images via the goldens and gms test harness binaries (built into out/<config>/goldens and out/<config>/gms). See tests/ for how to run and rebaseline goldens.

Unit tests are secondary and use the Catch2 framework. From the repo root:

cd tests/unit_tests
./test.sh

Unit tests live in tests/unit_tests/runtime/ (core runtime) and tests/unit_tests/renderer/ (renderer). To add a test, create an xxx_test.cpp file in the appropriate directory — the harness picks it up automatically.

Code formatting

rive-runtime uses clang-format.

  • macOS: brew install clang-format.
  • Windows: already installed if you have the prerequisites — VS 2022's C++ Clang Compiler component ships clang-format.exe alongside clang-cl.exe at C:\Program Files\Microsoft Visual Studio\2022\<edition>\VC\Tools\Llvm\x64\bin\. You can also install LLVM standalone from llvm.org or via winget install LLVM.LLVM.
  • Linux: install via your distro's package manager (e.g. apt install clang-format).

Memory checks (macOS only)

To run the tests under macOS's built-in leaks tool:

cd tests/unit_tests
./test.sh memory

This wraps the test binary with leaks --atExit, which ships with macOS — no install required. The memory flag is ignored on Linux and Windows.

Disassembly explorer (macOS / Linux)

To inspect generated assembly per cpp file, install the Disassembly Explorer VSCode extension. A disassemble task is provided in .vscode/tasks.json. The underlying gen assembly task invokes clang++ directly, so it needs clang++ on PATH — works out of the box on macOS (Xcode CLI tools) and most Linux distros, but not on a default Windows + VS install (which provides clang-cl.exe, not clang++.exe).

Reach the task from Tasks: Run Task, or bind a key in keybindings.json:

[
    {
        "key": "cmd+d",
        "command": "workbench.action.tasks.runTask",
        "args": "disassemble"
    }
]