* make file ref counted
* migrate File to refcnt
* add bindable artboard class to keep file reference
* feat(unity): support rcp file and BindableArtboard class (#10228)
* refactor(apple): use updated file bindable artboard apis (#10229)
* update command queue to support bindable artboards
* use bindable artboards on command queue
* self manage view model instances in js runtime
* change remaining viewModelInstanceRuntimes to rcp
* refactor(apple): update view model instances to use rcp (#10298)
* refactor(unity): support rcp ViewModelInstanceRuntime (#10309)
* rebase fix
* deprecate getArtboard in favor of getBindableArtboard
* fix merge
* remove unused lambda capture
* fix rive binding
* feat(Android): RCP File, VMI, and add bindable artboards (#10456)
* refactor: C++ refactors
- Import from long (incorrect) -> jlong
- Header clang-tidy fix
- Use reinterpret_cast instead of C-style cast
- Break out some variables instead of long one liners
- Use auto
- Remove unused env and thisObj
# Conflicts:
# packages/runtime_android/kotlin/src/main/cpp/src/helpers/general.cpp
* docs: Improve documentation on the File class
* feat: Support bindable artboard type and RCP VMIs
# Conflicts:
# packages/runtime_android/kotlin/src/androidTest/java/app/rive/runtime/kotlin/core/RiveDataBindingTest.kt
* feat: Support RCP files
* refactor: Change from +1/-1 ref to just release
* fix: Moved to the more appropriate null pointer for GetStringUTFChars
* replace unref with release
Co-authored-by: Adam <67035612+damzobridge@users.noreply.github.com>
Co-authored-by: David Skuza <david@rive.app>
Co-authored-by: Erik <erik@rive.app>
Co-authored-by: hernan <hernan@rive.app>
* fix(apple): remove #ifdef checks in public headers
Fixes an issue where framework consumers would also have to set
WITH_RIVE_TEXT or WITH_RIVE_AUDIO
* refactor(apple): remove #if(def) from public interfaces and no-op instead
* fix(apple): fix incorrect api usage
Co-authored-by: David Skuza <david@rive.app>
Adds support for data binding to the iOS runtime.
## Changes
### RiveFile
Updated to match c++ runtime support for getting view models by index, name, and default for an artboard.
### RiveArtboard
Updated to match c++ runtime support for binding a view model instance.
### RiveStateMachine
Updated to match c++ runtime support for binding a view model instance. Additionally, this holds a strong reference to the view model instance that is currently bound (which aids in knowing which state machine should have its property listeners called after advance).
### RiveModel
Adds support for enabling / disabling autoBind functionality. This has to be done _after_ initialization, since Swift default arguments don't bridge to ObjC, and I didn't want to add n number of new initializers. When enabled, a callback will be called with the bound instance.
## New Types
Currently, type names are similar to those found within the c++ runtime. They're kind of ugly when it comes to ObjC, but the Swift names are cleaned up (e.g `RiveViewModelRuntime.Instance` instead of `RiveViewModelInstanceRuntime`).
### RiveDataBindingViewModel
The bridging type between the c++ runtime equivalent (`rive::ViewModelRuntime`) and ObjC.
### RiveDataBindingViewModelInstance
Swift: `RiveDataBindingViewModel.Instance`
The bridging type between the c++ runtime equivalent (`rive::ViewModelInstanceRuntime`) and ObjC.
### RiveDataBindingViewModelInstanceProperty
Swift: `RiveDataBindingViewModel.Instance.Property`
The superclass bridging type between the c++ runtime equivalent (`rive::ViewModelInstanceValueRuntime`) and ObjC.
### Subclasses
- Strings: `RiveDataBindingViewModelInstanceStringProperty`
- Swift: `RiveDataBindingViewModel.Instance.StringProperty`
- Numbers: `RiveDataBindingViewModelInstanceNumberProperty`
- Swift: `RiveDataBindingViewModel.Instance.NumberProperty`
- Boolean: `RiveDataBindingViewModelInstanceBooleanProperty`
- Swift: `RiveDataBindingViewModel.Instance.BooleanProperty`
- Color: `RiveDataBindingViewModelInstanceColorProperty`
- Swift: `RiveDataBindingViewModel.Instance.ColorProperty`
- Enum: `RiveDataBindingViewModelInstanceEnumProperty`
- Swift: `RiveDataBindingViewModel.Instance.EnumProperty`
- Trigger: `RiveDataBindingViewModelInstanceTriggerProperty`
- Swift: `RiveDataBindingViewModel.Instance.TriggerProperty`
### Observability
KVO has (temporarily) been disabled, "forcing" observability to be done through the explicit `addListener` and `removeListener` functions of each property type. `removeListener` exists on the superclass, however the matching `addListener` functions exist on each property type, primarily due to the fact that there is no "pretty" way of handing these functions as generics (where only the value type of the property differs for each callback) other than utilizing `id`. Listeners exist within the context of a property; however, an instance will use its (cached) properties to request that it calls its listeners.
## Details
### Caching properties
When a property getter is called on a view model instance, a cache is first checked for the property, otherwise a new one is returned and cached. This helps with ensuring we are using the same pointer under-the-hood. This isn't strictly necessary (per testing) but does allow for some niceties, such as not having to explicitly maintain a strong reference to a property if you want to just observe: `instance.triggerProperty(from: "...").addListener { ... }`.
Properties are cached for the first component when parsing the path for the property. In the instance that a path with > 1 component is provided to a property (e.g `instance.triggerProperty(from: 'nested/trigger")`, then the appropriate nested view models are created, and the property is associated with the correct view model (e.g above, the view model `nested will be cached, and the trigger property will be cached within that view model).
### Caching nested view models
Similar to caching properties, when a (nested) view model getter is called on a view model instance, a cache is first checked for the view model, otherwise a new one is returned and cached. This helps ensure that when (re)binding an instance to a (new) state machine or artboard, that all properties within that view model still have its listeners attached, regardless of how nested a path goes. This will likely help with implementing replacing instance functionality in v2.
## Testing
Unit tests have been added for data binding, attempting to capture high-level expectations rather than totally verifying the c++ runtime expectations. This includes things like: all getters returning object-or-nil, listeners being called with the correct values, autoBinding, property and view model caching, etc. The `.riv` file for unit tests is the same one that is used within the Example app.
## Example
A new `.riv` file has been added that shows basic usage of each property type (including observability). The same `.riv` file is used in the unit tests.
Diffs=
b2f1db73d7 feat(ios): add support for data binding (#9227)
Co-authored-by: David Skuza <david@rive.app>
Adds support for the updated `CADisplayLink` API available on macOS 14+, which allows for setting preferred fps / frame rate range. This also moves the `DisplayLinkProxy` into a protocol with concrete types for all platforms.
## Changes
- [ ] Update `DisplayLinkProxy` to `RiveDisplayLink` protocol
- Replace usage of proxy with new protocol
- [ ] On macOS 14+, use `CADisplayLink`
- Additionally adds support for preferred fps / frame rate range
## Notes
While this is not "breaking", it appropriately changes the availability of some setters to match the API availability of the display link used. Some developers may find that there are errors - for example, setting FPS was unavailable on macOS, since `CVDisplayLink` didn't support it. Instead of no-oping, this function is now unavailable if the OS doesn't support it.
Diffs=
34820199f2 Use updated CADisplayLink API for macOS 14+ (#8899)
Co-authored-by: David Skuza <david@rive.app>
Addresses this issue: https://2dimensions.slack.com/archives/C07VD44ASE5/p1739456802968219
Rive's RenderPath steals the memory for the RawPath the runtime builds, which is usually fine apart from cases where we expect to use the RawPath after drawing with it. For example, with inner feather we want to be able to compute the bounds of the RawPath after it has been drawn. If during animation a user turns on inner feathering on a path which has not changed recently, which need to be able to compute its bounds, we can't if the RawPath is now gone.
This also can happen with trim paths and dash paths which are re-trimmed/dashed after having being rendered a few frames. Right now we force rebuild the whole path to re-trim it because we lose the RawPath.
This PR allows the ShapePaintPath to hold on to its RawPath by adding RenderPath::addRawPath. This is optimized memory usage but not having the runtime need to re-alloc the RawPath whenever it animates, but it means we're further from making RenderPaths immutable.
For the future: It'd be good to chat about a long term solution that can accommodate all goals of allocating less memory (prior to this change we were re-allocating RawPath memory every frame when animating), not rebuilding paths as often, and still allow for immutability.
Diffs=
9058a3fdad Add RenderPath::addRawPath (#9038)
Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
This pull request adds support for both visionOS and tvOS to the Apple (colloquially referred to as iOS) runtime.
It should _not_ be a breaking change, since the only major API change is an internal one (see `RenderContext` below). I believe we should be able to make this a minor release. Developers who have subclassed `RiveView` or `RiveRendererView` should not see any changes, unless they were explicitly expecting this view to be `MTKView`, which is fully unavailable on visionOS (hence our recreation - see `RiveMTKView` below.
## Premake Scripts
The premake scripts were updated to add a few new variants for iOS:
- xros (visionOS devices; named after the internal sdk)
- xrsimulator (visionOS simulator; named after the internal sdk)
- appletvos (tvOS devices; named after the internal sdk)
- appletvsimulator (tvOS simulators; named after the internal sdk)
The majority of the work here is copy/pasting existing code, and just adding additional filters when these new options are used, primarily used to target the new SDKs / minimums for those SDKs.
## Shaders
Shaders are pre-compiled for visionOS and tvOS separately, and the correct shaders are then used later-on at compile time.
## Build scripts
Build scripts were updated to support building the new libraries, targeting the new devices, using the new options above. Additionally, they have to point to new output files.
The `build_framework` script has been updated to build the new libraries to add to the final output `xcframework`.
## Project
Example targets for both visionOS and tvOS, since these truly are the "native" apps, rather than just iPad-on-your-device. These use a new `streaming` riv by the creative team.
The tvOS example app adds additional support for remote control, since that behavior can be utilized in multiple ways during development; that is, we don't add any "default" behavior for remote controls. The visionOS app, on the other hand, works out-of-the-box with no additional changes.
## RenderContext
`RenderContext` is an internal type; it's forward-declared, so it's unusable outside of the scope of internal development. There have been some "breaking" changes here - the API has been updated to, instead of passing in `MTKView` around, using `id<RiveMetalDrawableView>`. This had to be changed, regardless, since visionOS does not have `MTKView`. The choice to use a protocol was because it forces a little more explicit initialization across platforms, rather than having a parent class that acts as an abstract class, but isn't abstract because it still needs some default values, but those values are different based on device and API availability, etc. We could've passed around `RiveMTKView` as the type, but with a protocol, there's a possibility of being able to use a type that isn't exactly a view, but might want to still act against the drawing process. Personal choice, really.
## RiveRendererView
`RiveRendererView` is now a subclass of `RiveMTKView`. `RiveMTKView`'s superclass depends on the device:
- On visionOS, this is a `UIView` with an underlying `CAMetalLayer`
- On all other platforms, `MTKView`
This new class conforms to `RiveMetalDrawableView`, which allows it to be passed to `RenderContext` types.
### RiveMTKView (visionOS)
`RiveMTKView` on visionOS is a subclass of `UIView` that is backed by a `CAMetalLayer`, providing the necessary properties of `RiveMetalDrawableView` (compile-time safety here, baby). This is quite a simple recreation of the default `MTKView`, since that type is not available on visionOS (thanks, Apple).
## Other things
Additional compile-time checks for platform OS have been added to make sure each new platform compiles with the correct APIs that can be shared, or otherwise newly implemented.
Diffs=
6f70a0e803 Add visionOS and tvOS support to Apple runtime (#8107)
Co-authored-by: David Skuza <david@rive.app>
This pull request builds on top of fallback font support on iOS by including the ability to provide fallback fonts based on the styling of the missing character. Currently, the style information only contains weight. This weight is grabbed by calling `getAxisValue`. According to Luigi, this is a linear search, so perhaps there's room for a performance optimization later on.
There is one lower-level C++ change: `gFallbackProc` returns the font for the missing character, in addition _to_ the missing character (as a second parameter). This font will be used to generate the requested styling within the iOS runtime.
This adds a new class property to `RiveFont`: `fallbackFontCallback` (whose name I'm open to changing). This is a block (i.e closure) that will be called when a fallback font is requested. It supplies the styling of the missing character so that, for example, different fonts can be used based on the weight of the missing character. For example usage, see `SwiftFallbackFonts.swift`. This provider is what's used under-the-hood, and utilizes the pre-existing `fallbackFonts` class property
The "trickiest" bit here is the caching. NSDictionary requires equatable / hashable types as keys, and we want to minimize additional generation of a Rive font, so we cache any used fonts in a wrapper type, used as the value. When new fallback fonts are provided, either directly or when a new provider block is set, the cache will be reset. Once the weight is determined, generating the right key is as simple as calling the right initializer, and when set, generating the right value is simple as calling the right initializer with the created Rive font.
Finally, `RiveFactory` was getting a little bloated, so I did a little file cleanup.
This pull requests also includes Android support from #8621
Diffs=
7986d64d83 Support supplying mobile fallback fonts by style with caching (#8396)
Co-authored-by: David Skuza <david@rive.app>
Co-authored-by: Umberto <usonnino@gmail.com>
Co-authored-by: Umberto Sonnino <umberto@rive.app>
More experimenting on top of https://github.com/rive-app/rive/pull/8556
This breaks some APIs that still need to be fixed up elsewhere.
The basic concept here is that when you request a system font you can tell it whether you're requesting to use it a Harfbuzz shaped system font or a CoreText (System) shaped system font.
We prioritize Harfbuzz first so that we have predictable performance and results across edit and runtime. To do this the fallback process now comes with an index. Iteration will keep happening until no font is returned (or all glyphs are found).
If the registered fallbacks look like this:
```
RiveFont.fallbackFonts = [
UIFont(name: "PingFangSC-Semibold", size: 12)!,
UIFont(name: "Hiragino Sans", size: 12)!
]
```
The fallback process will return:
```
iter 0: Ping Fang Harfbuzz Shaped
iter 1: Hiragino San Harfbuzz Shaped
iter 2: Ping Fang Coretext Shaped
iter 3: Hiragino Sans Coretext Shaped
```
We also use Coretext last as usually shaping with Coretext causes Apple's shaper to do its own fallbacks (it calls them cascades like css). So iter 2 (in the example above) will be the final iteration as all glyphs get filled via Apple's own fallbacks.

Diffs=
3eefba5039 CoreText fallback shaper ex (#8568)
Co-authored-by: David Skuza <david@rive.app>
Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
Under certain circumstances, e.g "off-screen rendering" (i.e a Rive view not added to a view hierarchy), there is no window scene available, but there are still trait collections available. When using window scene, Rive would determine it is unable to draw because there is no window scene. However, using the trait collection allows Rive to continue drawing despite not being added to a view hierarchy. This allows manual calls to `draw` to continue when the view is _not_ added to a view hierarchy.
Diffs=
13939097af Use trait collection for display scale over window scene (#8472)
Co-authored-by: David Skuza <david@rive.app>
First steps towards supporting artboard resizing in our runtimes. This PR includes:
- New Fit type `autoResizeArtboard`. After a bit of back and forth, I think this keeps the API simple.
- ScaleFactor which represents a scale value to scale the artboard by in addition to resizing (only applies with `autoResizeArtboard`). This may be useful because an artboard is created at a specific width/height, but it may be deployed to platforms where it is rendered to a much smaller or larger surface/texture. Currently the default is 1.0 (no scale), however, an alternative is to have it default to something like textureSize / artboardSize so we sort of auto normalize it.
- Implemented on iOS. Once this is finalzed, we can work with DevRels to implement across all runtimes.
- TODO : Bubble up an event when the artboard size is changed internally by the .riv
https://github.com/user-attachments/assets/20e9fdda-5c3e-4f3f-b2f5-104ff0291fbe
Diffs=
e71b4cc081 feat: add runtime layout fit type for ios, android, web (#8341)
Co-authored-by: CI <pggordonhayes@gmail.com>
Co-authored-by: David Skuza <david@rive.app>
Co-authored-by: Philip Chung <philterdesign@gmail.com>
Fixes a build error introduced in #8334.
TL;DR: Adds a missing compile-time check for iOS vs macOS, so macOS was attempting to use a UIKit type.
Diffs=
64aab1d825 Fix build error when validating drawing on macOS (#8379)
Co-authored-by: David Skuza <david@rive.app>
This pull request fixes some crashes (see [rive-ios #343](https://github.com/rive-app/rive-ios/issues/343)) where the (drawable) size of the underlying view was not within the bounds within which Metal is capable of drawing.
Possible conditions:
- Width or height of the view is 0
- Transform of the view is x / y scale 0
The maximum allowed drawable sizes are based on [this Apple document](https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf). See: page 7.
Essentially, before every draw, we now check whether we _can_ draw via Metal based on the size of the view, as well as the provided drawable size of the underlying Metal view. If not, we do an early return and no drawing happens.
Unit tests have also been added for a few main scenarios under which this could occur.
Diffs=
fab89ebbba Validate rect and drawable size before drawing on iOS (#8334)
Co-authored-by: David Skuza <david@rive.app>
Adds (structured) logging via the iOS `Logger` API. Under the hood, this uses `os_log` for both in-memory and on-disk logging, depending on which level is used; this means _where_ is handled by the system, we just provide the level.
The API is a little interesting; you can't have a "generic" `log` function that takes in the message. iOS requires that you use interpolation when logging.
Logging is structured so that various categories are set under one subsystem. These categories are: view model, state machine, artboard, file, and view. Each of these can log one of debug, info, default, error, and fault levels. The developer can filter which categories and levels can be logged; Xcode also supports filtering within the console.
Logging itself is split into three things: the categories, the levels, and the logging. Within each "category" of logging, there exist events that can be logged. These are enums with associated values. When using Objective-C, there are helper functions that under-the-hood call logging functions with these events. Since there are a few categories, and various events for each category, these categories are split into extensions on `RiveLogger`. At the end of the day, there exists a single log function, which ensures a log category and level are available for logging, and then a log function that is essentially a switch statement on each event, logging the (interpolated) message.
These logging events are then utilized in the files mentioned above; the categories match the files where logging has been added. Primarily setters are called, or errors that may not be handled, but may be useful. Fatal errors are also logged.
When adding new logging:
1. Check if an existing extension exists. If not, create one.
2. Create an enum of possible events.
3. Create a `log` function that takes the model, and the event.
4. Create a `_log` function that verifies that an event has been called.
## Example usage
```swift
// Somewhere early in the app lifecycle…
RiveLogger.isEnabled = true
RiveLogger.isVerbose = true // advances are considered verbose
RiveLogger.levels = [.fatal] // filter for only specific levels, such as fatal errors
RiveLogger.categories = [.stateMachine, .viewModel] // filter for only specific categories
```
Diffs=
e1fc239974 Add logging to rive-ios (#8252)
Co-authored-by: David Skuza <david@rive.app>
This gives better support for smaller screens and side-by-side windows.
Also standardize the formatting check on GitHub on version 17.
Diffs=
e52e9fff29 Drop the ColumnLimit to 80 for clang-format (#8320)
Co-authored-by: Chris Dalton <99840794+csmartdalton@users.noreply.github.com>
This removes some legacy code that prevented the correct factory from being initialized when used on Macs with non-Apple-Silicon GPUs. Additionally, it removes explicitly setting the storage mode, which was causing Metal API validation to fail on non-Apple-Silicon GPU Macs.
## Storage Mode
Explicitly setting the storage mode to shared has been removed. This has no impact on iOS. For macOS, this defaults to managed, which should be appropriately handled by the C++ runtime, per Chris.
Per the docs for `MTLTextureDescriptor.storageMode`:
> In iOS and tvOS, the default value is MTLStorageMode.shared. In macOS, the default value is MTLStorageMode.managed.
## Testing
These changes were tested on an i9 Intel Mac against a file that was reproducibly causing crashes. Post-changes, the file no longer crashes.
Diffs=
56d95d200 Fix Apple runtime crashes on Macs with non-Apple-Silicon GPUs (#8301)
Co-authored-by: David Skuza <david@rive.app>
Expands on the current iOS factory method to decode raw font data (from file) to adding a second font decoding function that can use a native Apple font (`UIFont` / `NSFont`). This reuses some of the logic from fallback fonts. There's one main difference - while we are calculating weight and width, those get ignored in addition to size; the font data returned seems to be used as vector(?) data to draw characters in the weight / width as defined in a text run, rather than overridden by any supplied font. But, we need to provide a weight and width when obtaining a Rive font from cpp, so we re-use the logic.
Diffs=
414c142f2 Add support for decoding Apple native font via factory (#8180)
Co-authored-by: David Skuza <david@rive.app>
Similar to #8167:
> Request from a customer.
>
> This unlocks the ability to resize images at runtime to fit the appropriate ImageAsset dimensions.
Rather than exposing an individual width and height, `CGSize` is used (similar to `UIImage`), accessible via a new `size` property on `RiveImageAsset`. A unit test was also added that tests a very simple referenced jpeg of size 320x240.
Diffs=
48212b2bb Add size property to RiveImageAsset on iOS (#8169)
Co-authored-by: David Skuza <david@rive.app>
This adds support for getting / setting nested text runs on iOS, via the exposed lower-level API. Tests have been added for: testing that setting the text run works at the artboard level, and at the view model level, and additionally that the parent text run will be returned if the path is empty.
Diffs=
bbec5cbbc Add support for nested text runs on iOS (#8108)
Co-authored-by: David Skuza <david@rive.app>
This builds on top of #7661 and adds an iOS / macOS API for setting fallback fonts.
At a high-level, this adds a class property to `RiveFont` for getting / setting the fallback font(s) **based on the system** (or _optionally_, a `UIFont/NSFont`)(accessible in Objective-C and Swift via `RiveFont.fallbackFonts`). This property is an array of a objects conforming to a new protocol: `RiveFallbackFontProvider` (platform-agnostic). By default, if no fallbacks are set, or an empty array is set, the default system font of regular weight will be used.
In terms of naming, the `RiveFallbackFontDescriptorDesign` and `RiveFallbackFontDescriptorWeight` types each have cases that mirror those available in 1st party Apple APIs, so that usage and expectations are similar across our APIs, as well as those provided by UIKit / AppKit.
## Example Usage
```swift
RiveFont.fallbackFonts = [
RiveFallbackFontDescriptor(systemDesign: .default, weight: .bold),
RiveFallbackFontDescriptor(systemDesign: .monospaced, weight: .ultraLight),
UIFont.systemFont(ofSize: 20, weight: .bold)
]
```
## RiveFallbackFontProvider
`RiveFallbackFontProvider` is a protocol that defines the interface for types that can be used to return system fonts, or any font that can be used as a fallback. `RiveFallbackFontDescriptor` and `UIFont/NSFont` conform to this protocol; both can be used to define fallback fonts.
## RiveFallbackFontDescriptor
`RiveFallbackFontDescriptor` is a platform-agnostic way of defining the _type_ of system font you want to request as a fallback, if necessary. It contains a couple of properties: `design` and `weight`. These are used in conjunction with each other to start with and update a system font (generated by `[UI/NS]Font.systemFont(ofSize:weight:)`, potentially matching on more than one font.
## Unit Tests
Unit tests have been written to verify that `design` and `weight` create different fonts, based on the provided values. The tests at a high-level are the same: for each case of both properties, check that there is at least one matching font. For each property, check that each font name is unique. On iOS, the font names are unique based on system design _and_ weight. I felt this was better than asserting against a specific font name, in case Apple changes that from under our feet. Additionally, what the default system fallback is set to is also tested.
## IRL Testing
This was tested by creating a riv file that contained a text run whose font was exported containing only the glyphs used, and setting the text run to some text that did not use the exported glyphs.
Tested on:
- [x] iOS (Simulator)
- [x] iPadOS
- [x] macOS
Diffs=
a4e15fb7b Add fallback font support for iOS and macOS (#7690)
Co-authored-by: David Skuza <david@rive.app>
Make sure to check for BGRA before assuming we can do typed UAV loads. Also handle BGRA_TYPELESS.
Diffs=
c88898459 Better support for BGRA in D3D (#8022)
9c5e96a32 Remove skia factory api which is not used (#8016)
bf121f507 Bye bye rive_common (#8007)
Co-authored-by: rivessamr <suki@rive.app>
Support for SIMD instructions for unpremult
First checkin, using rive::int16x4 instructions : 1 pixel at a time
Further checkin, using rive::int16x4 instructions : 2 pixels at a time
Last checkin, avoid computation when opaque pixels (assume there will be enough opaque pixels to warrant this)
Thanks to Chris for the SIMD instructions usage in rive
More checkins: move the decode and unpremult to the rive decoder - this requires modifications to build files. The benefits are we are now running tests on this path. However, there are some issues with decoding two images for tests:
"../../test/assets/bad.jpg" ... Apple Preview app cannot open this image, however, the current test says that it should be not null
And
"../../test/assets/bad.png", Apple Preview app can load this images, however, the current test says that it should be null
Diffs=
e992059d6 iOS images unpremult SIMD support (#7875)
Co-authored-by: rivessamr <suki@rive.app>
The method I was using to extract the pixel data doesn't always return RGBA and you cannot force Core Graphics to return RGBA (I tried CGImageCreateCopyWithColorSpace but it only works when the components per pixel match). This is particularly problematic with PNG8 where the image data is a palette, Core Graphics will return 8 bits per pixel in this case.
We let Core Graphics do the conversion by letting it render to a context and then grab the buffer as we did before. This only works with pre-multiplied alpha (the context cannot store un-multiplied, tried that too, fails on creation). So I've also re-introduced the un-multiply logic but I hand rolled it as the SIMD was failing.
Current:
```
// CG only supports premultiplied alpha. Unmultiply now.
size_t imageSizeInBytes = image.height * image.width * 4;
for (size_t i = 0; i < imageSizeInBytes; i += 4)
{
auto alpha = image.pixels[i + 3];
if (alpha != 0.0f)
{
auto alphaFactor = 255.0f / alpha;
for (size_t j = 0; j < 3; j++)
{
image.pixels[i + j] *= alphaFactor;
}
}
}
```
Not working SIMD attempt (should 255/rgba.a actually do floating point here or is this the problem?) @csmartdalton:
```
// CG only supports premultiplied alpha. Unmultiply now.
size_t imageSizeInBytes = image.height * image.width * 4;
for (size_t i = 0; i < imageSizeInBytes; i += 4)
{
auto rgba = rive::simd::load<uint8_t, 4>(&image.pixels[i]);
if (rgba.a != 0)
{
rive::simd::store(&image.pixels[i], rgba.rgb * 255 / rgba.a);
}
}
```
This now works with both the dwarf and the problematic png from here: https://2dimensions.slack.com/archives/CLLCU09T6/p1723735670398969?thread_ts=1723673292.651149&cid=CLLCU09T6
Diffs=
ccfcbffdf iOS images: back to rendering to a cg context with unmultiplying. (#7868)
Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
TL;DR: Do not request to draw frames when the host view's size width _or_ height is 0.
Some users were experiencing issues (and crashes, when Metal API validation is enabled) when a frame is resized to zero. This has been difficult to reproduce locally when testing scenarios that users were seeing (sometimes it's just how the developer(s) have implemented view presentation / dismissal). However, I was able to verify this crash / fix when:
1. Initially sizing a Rive view to a valid size (i.e > 0)
2. After 3 seconds, resizing the view to 0
Immediately after `2`, the crash would occur. With this fix, it doesn't.
Diffs=
7a55a6db3 Do not render frames on iOS if view size width or height is 0 (#7846)
Co-authored-by: David Skuza <david@rive.app>
The Rive renderer is stable and ready for production now. This cuts the runtime size from 7.1 MB to 2.3.
Diffs=
32f7a05eb Remove Skia from iOS runtime (#6072)
Co-authored-by: Chris Dalton <99840794+csmartdalton@users.noreply.github.com>
Updates the `RiveModel` API with the ability to set and get the volume for the currently set artboard. Any new artboards will default to use the last-set volume of the model. A volume default of 1.0 is set to match rive-cpp's default. `RiveArtboard` is also updated to forward volume calls to the artboard instance, exposing a new `volume` property.
There's an open question whether this belongs in `RiveViewModel`, or `RiveModel`, but I went for `RiveModel` since there's a direct reference to the artboard within the model itself, and an indirect reference through the view model (model?.artboard)
Diffs=
a31cd9761 Add ability to set iOS artboard volume through RiveModel (#7658)
Co-authored-by: David Skuza <david@rive.app>
This pull request adds a new delegate function that can be used to perform (UI) updates based on the result of a touch or a mouse event. This is an additive change that will not break existing behavior.
An example of where this could be used:
- In a collection view, where the animation should not prevent scrolling from occurring if a non-interactive portion of the animation is touched.
- By utilizing the new callback, a developer can check for a hit when a touch began, and update the appropriate collection view properties.
- Add support for:
- [x] iOS
- [x] macOS
Diffs=
fe60de3c3 Add new state machine delegate callback for touch event hit results (#7579)
Co-authored-by: David Skuza <david@rive.app>
This pull request improves the usage of nullable values that can be returned by various bits of the iOS renderer.
The initial place this appeared was [this rive-ios issue](https://github.com/rive-app/rive-ios/issues/330), where in the provided stack trace, we can see the following:
```
...
"exception" : {"codes":"0x0000000000000000, 0x0000000000000000","rawCodes":[0,0],"type":"EXC_CRASH","signal":"SIGABRT"},
"termination" : {"flags":0,"code":6,"namespace":"SIGNAL","indicator":"Abort trap: 6","byProc":"Application","byPid":1045},
"asi" : {"libsystem_c.dylib":["abort() called"]},
"exceptionReason" : {"arguments":["-[__NSArrayM insertObject:atIndex:]"],"format_string":"*** %s: object cannot be nil","name":"NSInvalidArgumentException","type":"objc-exception","composed_message":"*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil","class":"NSException"},
"extMods" : {"caller":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"system":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"targeted":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"warnings":0},
"lastExceptionBacktrace" : [
{"imageOffset":978358,"symbol":"__exceptionPreprocess","symbolLocation":226,"imageIndex":9},
{"imageOffset":81565,"symbol":"objc_exception_throw","symbolLocation":48,"imageIndex":7},
{"imageOffset":123841,"symbol":"-[__NSArrayM insertObject:atIndex:]","symbolLocation":1762,"imageIndex":9},
{"imageOffset":35776,"symbol":"-[RiveStateMachineInstance stateChanges]","symbolLocation":178,"imageIndex":1},
...
```
Peeking into `-[RiveStateMachineInstance stateChanges]` showed that we were not checking if the nullable value was valid before attempting to insert into an array, thus under certain conditions inserting nil (those conditions still tbd; I've asked the dev for a hopefully reproducible file).
I went ahead and peeked at various other portions of the renderer for nullable usage and added some other checks for array insertion that were similar.
Diffs=
cd8fef48f Improve handling of nullable values in iOS renderer (#7529)
Co-authored-by: David Skuza <david@rive.app>
Was testing using multiple instances of the same nested artboards and found this issue. We need all cached input refs to include the path in the dict key so we don't return the wrong input ref. The other platforms don't appear to cache the references so this was only needed on iOS.
Diffs=
8364ba99c Include nested artboard path in input cache on iOS (#7348)
Co-authored-by: Philip Chung <philterdesign@gmail.com>
simple things first.
after some debugging on audio "ducking"
it looks like we only start to kill audio after we initialize the audio engine. this first "fix" simply prevents us from initializing the audio engine if its not already been initialized. when going into the background/foreground.
other than this, we initialize the audio engine when you first play an audio clip in `void AudioEvent::play()`
this still leaves an issue lying around where after we have initialized the audio engine we will now "forever" duck audio when we go into the background/foreground. but at least you should be able to avoid this entirely if you never load a file with audio.
Diffs=
d4b3118e1 only start/stop the audio engine if its been initialized (#7335)
Co-authored-by: Maxwell Talbot <talbot.maxwell@gmail.com>
…nDidResignActiveNotification
good spot on the bad notification, will push another build with this when in
Diffs=
14ea38786 name:NSApplicationDidFinishLaunchingNotification -> name:NSApplicatio… (#7102)
Co-authored-by: Maxwell Talbot <talbot.maxwell@gmail.com>
we seem to use `#if __has_include(<UIKit/UIKit.h>)` & `#if TARGET_OS_IPHONE` to determine if we are buidling for ios or not.
i'm not sure if it really matters which we use here, but i guess we should just use one of them, i kinda like the look of TARGET_OS_IPHONE more.
Diffs=
f20d5944a patch backgrounding to use macos notifications when appropriate (#7101)
Co-authored-by: Maxwell Talbot <talbot.maxwell@gmail.com>
Follow up to #7048!
I nuked the custom defines and the miniaudio include. I think this fixes the need for miniaudio and the custom defines @mjtalbot! Give it a shot 🔫
Diffs=
89053041a add out of band audio support ios - abstracted audio! (#7079)
Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
Co-authored-by: Maxwell Talbot <talbot.maxwell@gmail.com>