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>
previously, when an animation advanced by 0 seconds, it would return true, which was interpreted as meaning that the animation needed to keep advancing.
We changed that behavior and now a linear animation will return false if it didn't advance.
A side effect of that is that now the animation state that calls advance, sets keepGoing to false instead of true.
So the animation wouldn't keep going in that frame.
Which is ok as long as we add a new condition to identify whether the state machine layer should keep going in the next frame based on whether it changed its state internally.
This PR adds that condition
Diffs=
51c3bbcde2 return keep going when a state machine has changed its state (#8564)
Co-authored-by: hernan <hernan@rive.app>
we had inverted the order of advances between parent and child to fix a frame delay.
But this introduced a bug where the child would report an event, than in turn would trigger an event in the parent.
But immediately after, the parent would advance causing the event to get cleared.
Diffs=
01bc166a8e invert order of advance between parent and child (#8547)
Co-authored-by: hernan <hernan@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>
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>
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>
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>