lottie-ios 3.2.3 → 3.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/.github/actions/setup/action.yml +32 -0
  2. package/.github/issue_template.md +6 -23
  3. package/.github/workflows/main.yml +98 -0
  4. package/.github/workflows/stale_issues.yml +17 -0
  5. package/.spi.yml +6 -0
  6. package/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +7 -0
  7. package/.swiftpm/xcode/package.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  8. package/.swiftpm/xcode/package.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  9. package/.swiftpm/xcode/xcuserdata/{brandonwithrow.xcuserdatad → cal.xcuserdatad}/xcschemes/xcschememanagement.plist +25 -15
  10. package/.swiftpm/xcode/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  11. package/Gemfile +4 -0
  12. package/Gemfile.lock +102 -0
  13. package/Lottie.xcodeproj/project.pbxproj +2011 -1972
  14. package/Lottie.xcodeproj/project.xcworkspace/contents.xcworkspacedata +1 -1
  15. package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  16. package/Lottie.xcodeproj/xcshareddata/xcschemes/{Lottie_iOS.xcscheme → Lottie (iOS).xcscheme } +15 -18
  17. package/Lottie.xcodeproj/xcshareddata/xcschemes/{Lottie_tvOS.xcscheme → Lottie (macOS).xcscheme } +5 -18
  18. package/Lottie.xcodeproj/xcshareddata/xcschemes/{Lottie_macOS.xcscheme → Lottie (tvOS).xcscheme } +5 -18
  19. package/Lottie.xcodeproj/xcuserdata/cal.xcuserdatad/xcschemes/xcschememanagement.plist +37 -0
  20. package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +24 -0
  21. package/Lottie.xcworkspace/contents.xcworkspacedata +10 -0
  22. package/Lottie.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  23. package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +34 -0
  24. package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  25. package/{Lottie.xcodeproj/xcuserdata/brandonwithrow.xcuserdatad → Lottie.xcworkspace/xcuserdata/cal.xcuserdatad}/xcdebugger/Breakpoints_v2.xcbkptlist +2 -2
  26. package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/xcdebugger/Expressions.xcexplist +153 -0
  27. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  28. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +22 -0
  29. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +138 -0
  30. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +30 -0
  31. package/Package.swift +5 -15
  32. package/README.md +40 -60
  33. package/Rakefile +160 -0
  34. package/Sources/Private/CoreAnimation/Animations/CAAnimation+TimingConfiguration.swift +81 -0
  35. package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +447 -0
  36. package/Sources/Private/CoreAnimation/Animations/CombinedShapeAnimation.swift +81 -0
  37. package/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift +41 -0
  38. package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +55 -0
  39. package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +210 -0
  40. package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +229 -0
  41. package/Sources/Private/CoreAnimation/Animations/OpacityAnimation.swift +52 -0
  42. package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +58 -0
  43. package/Sources/Private/CoreAnimation/Animations/ShapeAnimation.swift +257 -0
  44. package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +124 -0
  45. package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +73 -0
  46. package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +205 -0
  47. package/Sources/Private/CoreAnimation/Animations/VisibilityAnimation.swift +37 -0
  48. package/Sources/Private/CoreAnimation/CompatibilityTracker.swift +130 -0
  49. package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +497 -0
  50. package/Sources/Private/CoreAnimation/Extensions/CALayer+fillBounds.swift +35 -0
  51. package/Sources/Private/CoreAnimation/Extensions/KeyframeGroup+exactlyOneKeyframe.swift +37 -0
  52. package/Sources/Private/CoreAnimation/Extensions/Keyframes+combinedIfPossible.swift +154 -0
  53. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +83 -0
  54. package/Sources/Private/CoreAnimation/Layers/BaseAnimationLayer.swift +33 -0
  55. package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +88 -0
  56. package/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift +167 -0
  57. package/Sources/Private/CoreAnimation/Layers/GradientRenderLayer.swift +94 -0
  58. package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +79 -0
  59. package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +64 -0
  60. package/Sources/Private/CoreAnimation/Layers/MaskCompositionLayer.swift +138 -0
  61. package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +140 -0
  62. package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +85 -0
  63. package/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift +315 -0
  64. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +390 -0
  65. package/Sources/Private/CoreAnimation/Layers/SolidLayer.swift +47 -0
  66. package/Sources/Private/CoreAnimation/Layers/TextLayer.swift +91 -0
  67. package/Sources/Private/CoreAnimation/Layers/TransformLayer.swift +11 -0
  68. package/Sources/Private/CoreAnimation/ValueProviderStore.swift +139 -0
  69. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/CompositionLayer.swift +94 -86
  70. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/ImageCompositionLayer.swift +24 -21
  71. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/MaskContainerLayer.swift +75 -54
  72. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/NullCompositionLayer.swift +5 -5
  73. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/PreCompositionLayer.swift +59 -43
  74. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/ShapeCompositionLayer.swift +22 -20
  75. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/SolidCompositionLayer.swift +26 -17
  76. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/TextCompositionLayer.swift +42 -36
  77. package/{lottie-swift/src/Private/LayerContainers/AnimationContainer.swift → Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift} +200 -140
  78. package/Sources/Private/MainThread/LayerContainers/Utility/CachedImageProvider.swift +47 -0
  79. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/Utility/CompositionLayersInitializer.swift +33 -24
  80. package/{lottie-swift/src/Private/LayerContainers/Utility/TextLayer.swift → Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift} +149 -106
  81. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/Utility/InvertedMatteLayer.swift +26 -24
  82. package/Sources/Private/MainThread/LayerContainers/Utility/LayerFontProvider.swift +41 -0
  83. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/Utility/LayerImageProvider.swift +20 -16
  84. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTextProvider.swift +40 -0
  85. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/Utility/LayerTransformNode.swift +82 -67
  86. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Extensions/ItemsExtension.swift +9 -4
  87. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/NodeProperty.swift +29 -21
  88. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/Protocols/AnyNodeProperty.swift +16 -10
  89. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/Protocols/AnyValueContainer.swift +6 -6
  90. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/Protocols/KeypathSearchable.swift +5 -5
  91. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/Protocols/NodePropertyMap.swift +10 -8
  92. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/ValueContainer.swift +25 -21
  93. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/ValueProviders/GroupInterpolator.swift +23 -17
  94. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/ValueProviders/SingleValueProvider.swift +22 -17
  95. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/ModifierNodes/TrimPathNode.swift +110 -79
  96. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/GroupOutputNode.swift +22 -16
  97. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/PassThroughOutputNode.swift +19 -15
  98. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/PathOutputNode.swift +22 -20
  99. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/Renderables/FillRenderer.swift +22 -23
  100. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift +247 -0
  101. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientStrokeRenderer.swift +30 -24
  102. package/{lottie-swift/src/Private/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift → Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift} +93 -66
  103. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift +23 -19
  104. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +139 -0
  105. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +170 -0
  106. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/PathNodes/RectNode.swift +95 -58
  107. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/PathNodes/ShapeNode.swift +42 -29
  108. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/PathNodes/StarNode.swift +108 -69
  109. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +155 -0
  110. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/RenderNodes/FillNode.swift +51 -37
  111. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +57 -42
  112. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +66 -58
  113. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +169 -0
  114. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +138 -119
  115. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Protocols/AnimatorNode.swift +80 -79
  116. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Protocols/PathNode.swift +5 -3
  117. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Protocols/RenderNode.swift +22 -17
  118. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift +27 -24
  119. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/RenderLayers/ShapeRenderLayer.swift +34 -25
  120. package/Sources/Private/Model/Animation.swift +160 -0
  121. package/Sources/Private/Model/Assets/Asset.swift +43 -0
  122. package/{lottie-swift/src → Sources}/Private/Model/Assets/AssetLibrary.swift +40 -13
  123. package/Sources/Private/Model/Assets/ImageAsset.swift +112 -0
  124. package/{lottie-swift/src → Sources}/Private/Model/Assets/PrecompAsset.swift +20 -10
  125. package/Sources/Private/Model/DictionaryInitializable.swift +67 -0
  126. package/Sources/Private/Model/Extensions/Bundle.swift +34 -0
  127. package/{lottie-swift/src → Sources}/Private/Model/Extensions/KeyedDecodingContainerExtensions.swift +8 -4
  128. package/Sources/Private/Model/Keyframes/KeyframeData.swift +113 -0
  129. package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +222 -0
  130. package/{lottie-swift/src → Sources}/Private/Model/Layers/ImageLayerModel.swift +21 -11
  131. package/Sources/Private/Model/Layers/LayerModel.swift +228 -0
  132. package/{lottie-swift/src → Sources}/Private/Model/Layers/PreCompLayerModel.swift +39 -22
  133. package/{lottie-swift/src → Sources}/Private/Model/Layers/ShapeLayerModel.swift +23 -12
  134. package/{lottie-swift/src → Sources}/Private/Model/Layers/SolidLayerModel.swift +31 -19
  135. package/{lottie-swift/src → Sources}/Private/Model/Layers/TextLayerModel.swift +33 -19
  136. package/Sources/Private/Model/Objects/DashPattern.swift +44 -0
  137. package/Sources/Private/Model/Objects/Marker.swift +33 -0
  138. package/Sources/Private/Model/Objects/Mask.swift +80 -0
  139. package/Sources/Private/Model/Objects/Transform.swift +179 -0
  140. package/Sources/Private/Model/ShapeItems/Ellipse.swift +74 -0
  141. package/Sources/Private/Model/ShapeItems/Fill.swift +74 -0
  142. package/Sources/Private/Model/ShapeItems/GradientFill.swift +137 -0
  143. package/Sources/Private/Model/ShapeItems/GradientStroke.swift +185 -0
  144. package/Sources/Private/Model/ShapeItems/Group.swift +48 -0
  145. package/{lottie-swift/src → Sources}/Private/Model/ShapeItems/Merge.swift +29 -12
  146. package/Sources/Private/Model/ShapeItems/Rectangle.swift +72 -0
  147. package/Sources/Private/Model/ShapeItems/Repeater.swift +135 -0
  148. package/Sources/Private/Model/ShapeItems/Shape.swift +56 -0
  149. package/Sources/Private/Model/ShapeItems/ShapeItem.swift +163 -0
  150. package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +135 -0
  151. package/Sources/Private/Model/ShapeItems/Star.swift +131 -0
  152. package/Sources/Private/Model/ShapeItems/Stroke.swift +101 -0
  153. package/Sources/Private/Model/ShapeItems/Trim.swift +77 -0
  154. package/Sources/Private/Model/Text/Font.swift +61 -0
  155. package/{lottie-swift/src → Sources}/Private/Model/Text/Glyph.swift +63 -39
  156. package/Sources/Private/Model/Text/TextAnimator.swift +164 -0
  157. package/Sources/Private/Model/Text/TextDocument.swift +123 -0
  158. package/Sources/Private/RootAnimationLayer.swift +51 -0
  159. package/{lottie-swift/src → Sources}/Private/Utility/Debugging/AnimatorNodeDebugging.swift +7 -7
  160. package/{lottie-swift/src → Sources}/Private/Utility/Debugging/LayerDebugging.swift +72 -48
  161. package/Sources/Private/Utility/Debugging/TestHelpers.swift +10 -0
  162. package/{lottie-swift/src → Sources}/Private/Utility/Extensions/AnimationKeypathExtension.swift +69 -59
  163. package/Sources/Private/Utility/Extensions/BlendMode+Filter.swift +31 -0
  164. package/Sources/Private/Utility/Extensions/CGColor+RGB.swift +22 -0
  165. package/{lottie-swift/src → Sources}/Private/Utility/Extensions/CGFloatExtensions.swift +70 -67
  166. package/Sources/Private/Utility/Extensions/DataExtension.swift +27 -0
  167. package/Sources/Private/Utility/Extensions/MathKit.swift +450 -0
  168. package/Sources/Private/Utility/Extensions/StringExtensions.swift +38 -0
  169. package/{lottie-swift/src → Sources}/Private/Utility/Helpers/AnimationContext.swift +42 -16
  170. package/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift +134 -0
  171. package/{lottie-swift/src → Sources}/Private/Utility/Interpolatable/KeyframeExtensions.swift +13 -10
  172. package/Sources/Private/Utility/Interpolatable/KeyframeGroup+Extensions.swift +59 -0
  173. package/{lottie-swift/src/Private/NodeRenderSystem/NodeProperties/ValueProviders → Sources/Private/Utility/Interpolatable}/KeyframeInterpolator.swift +125 -108
  174. package/{lottie-swift/src → Sources}/Private/Utility/Primitives/BezierPath.swift +229 -143
  175. package/Sources/Private/Utility/Primitives/CGPointExtension.swift +35 -0
  176. package/{lottie-swift/src → Sources}/Private/Utility/Primitives/ColorExtension.swift +46 -14
  177. package/{lottie-swift/src → Sources}/Private/Utility/Primitives/CompoundBezierPath.swift +58 -49
  178. package/Sources/Private/Utility/Primitives/CurveVertex.swift +184 -0
  179. package/Sources/Private/Utility/Primitives/PathElement.swift +75 -0
  180. package/Sources/Private/Utility/Primitives/UnitBezier.swift +115 -0
  181. package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +341 -0
  182. package/Sources/Public/Animation/AnimationPublic.swift +266 -0
  183. package/Sources/Public/Animation/AnimationView.swift +1335 -0
  184. package/Sources/Public/Animation/AnimationViewInitializers.swift +109 -0
  185. package/Sources/Public/AnimationCache/AnimationCacheProvider.swift +22 -0
  186. package/{lottie-swift/src → Sources}/Public/AnimationCache/LRUAnimationCache.swift +22 -18
  187. package/Sources/Public/DynamicProperties/AnimationKeypath.swift +49 -0
  188. package/Sources/Public/DynamicProperties/AnyValueProvider.swift +132 -0
  189. package/{lottie-swift/src → Sources}/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +54 -36
  190. package/{lottie-swift/src → Sources}/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +40 -36
  191. package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +123 -0
  192. package/{lottie-swift/src → Sources}/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +40 -35
  193. package/{lottie-swift/src → Sources}/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +40 -35
  194. package/{lottie-swift/src → Sources}/Public/FontProvider/AnimationFontProvider.swift +15 -8
  195. package/Sources/Public/ImageProvider/AnimationImageProvider.swift +21 -0
  196. package/Sources/Public/Keyframes/Interpolatable.swift +253 -0
  197. package/Sources/Public/Keyframes/Keyframe.swift +92 -0
  198. package/Sources/Public/Logging/LottieLogger.swift +137 -0
  199. package/Sources/Public/LottieConfiguration.swift +143 -0
  200. package/{lottie-swift/src → Sources}/Public/Primitives/AnimationTime.swift +1 -1
  201. package/{lottie-swift/src → Sources}/Public/Primitives/Color.swift +10 -6
  202. package/{lottie-swift/src → Sources}/Public/Primitives/Vectors.swift +13 -12
  203. package/Sources/Public/TextProvider/AnimationTextProvider.swift +53 -0
  204. package/{lottie-swift/src → Sources}/Public/iOS/AnimatedButton.swift +42 -26
  205. package/{lottie-swift/src → Sources}/Public/iOS/AnimatedControl.swift +100 -91
  206. package/{lottie-swift/src → Sources}/Public/iOS/AnimatedSwitch.swift +128 -94
  207. package/{lottie-swift/src → Sources}/Public/iOS/AnimationSubview.swift +3 -3
  208. package/Sources/Public/iOS/AnimationViewBase.swift +78 -0
  209. package/{lottie-swift/src → Sources}/Public/iOS/BundleImageProvider.swift +36 -34
  210. package/{lottie-swift/src → Sources}/Public/iOS/Compatibility/CompatibleAnimationKeypath.swift +4 -0
  211. package/{lottie-swift/src → Sources}/Public/iOS/Compatibility/CompatibleAnimationView.swift +38 -29
  212. package/{lottie-swift/src → Sources}/Public/iOS/FilepathImageProvider.swift +24 -21
  213. package/{lottie-swift/src → Sources}/Public/iOS/UIColorExtension.swift +4 -4
  214. package/{lottie-swift/src/Public/MacOS/AnimationSubview.swift → Sources/Public/macOS/AnimationSubview.macOS.swift} +4 -5
  215. package/{lottie-swift/src/Public/MacOS/LottieView.swift → Sources/Public/macOS/AnimationViewBase.macOS.swift} +58 -50
  216. package/{lottie-swift/src/Public/MacOS/BundleImageProvider.swift → Sources/Public/macOS/BundleImageProvider.macOS.swift} +31 -32
  217. package/Sources/Public/macOS/FilepathImageProvider.macOS.swift +67 -0
  218. package/Tests/AnimationKeypathTests.swift +103 -0
  219. package/Tests/AutomaticEngineTests.swift +57 -0
  220. package/Tests/BundleTests.swift +25 -0
  221. package/Tests/DataURLTests.swift +64 -0
  222. package/Tests/ParsingTests.swift +43 -0
  223. package/Tests/PerformanceTests.swift +214 -0
  224. package/Tests/Samples/9squares_AlBoardman.json +1 -0
  225. package/Tests/Samples/Boat_Loader.json +1 -0
  226. package/Tests/Samples/HamburgerArrow.json +1 -0
  227. package/Tests/Samples/IconTransitions.json +1 -0
  228. package/Tests/Samples/Images/dog.png +0 -0
  229. package/Tests/Samples/Issues/issue_1125.json +1 -0
  230. package/Tests/Samples/Issues/issue_1260.json +1 -0
  231. package/Tests/Samples/Issues/issue_1403.json +1 -0
  232. package/Tests/Samples/Issues/issue_1407.json +1 -0
  233. package/Tests/Samples/Issues/issue_1460.json +1 -0
  234. package/Tests/Samples/Issues/issue_1488.json +1 -0
  235. package/Tests/Samples/Issues/issue_1505.json +1 -0
  236. package/Tests/Samples/Issues/issue_1541.json +1 -0
  237. package/Tests/Samples/Issues/issue_1557.json +1 -0
  238. package/Tests/Samples/Issues/issue_1603.json +1 -0
  239. package/Tests/Samples/Issues/issue_1628.json +1 -0
  240. package/Tests/Samples/Issues/issue_1636.json +1 -0
  241. package/Tests/Samples/Issues/issue_1643.json +1 -0
  242. package/Tests/Samples/Issues/issue_1655.json +1 -0
  243. package/Tests/Samples/Issues/issue_1664.json +1 -0
  244. package/Tests/Samples/Issues/issue_1683.json +1 -0
  245. package/Tests/Samples/Issues/issue_1687.json +1 -0
  246. package/Tests/Samples/Issues/issue_1711.json +1 -0
  247. package/Tests/Samples/Issues/issue_1717.json +1 -0
  248. package/Tests/Samples/Issues/issue_769.json +1 -0
  249. package/Tests/Samples/Issues/issue_885.json +1 -0
  250. package/Tests/Samples/Issues/issue_965.json +1 -0
  251. package/Tests/Samples/Issues/pr_1536.json +1 -0
  252. package/Tests/Samples/Issues/pr_1563.json +8439 -0
  253. package/Tests/Samples/Issues/pr_1592.json +5527 -0
  254. package/Tests/Samples/Issues/pr_1599.json +738 -0
  255. package/Tests/Samples/Issues/pr_1604_1.json +1 -0
  256. package/Tests/Samples/Issues/pr_1604_2.json +1 -0
  257. package/Tests/Samples/Issues/pr_1632_1.json +1 -0
  258. package/Tests/Samples/Issues/pr_1632_2.json +1 -0
  259. package/Tests/Samples/Issues/pr_1686.json +513 -0
  260. package/Tests/Samples/Issues/pr_1698.json +1 -0
  261. package/Tests/Samples/Issues/pr_1699.json +1 -0
  262. package/Tests/Samples/LottieFiles/LICENSE.md +14 -0
  263. package/Tests/Samples/LottieFiles/bounce_strokes.json +1 -0
  264. package/Tests/Samples/LottieFiles/cactus.json +1 -0
  265. package/Tests/Samples/LottieFiles/dog_car_ride.json +1 -0
  266. package/Tests/Samples/LottieFiles/draft_icon.json +1 -0
  267. package/Tests/Samples/LottieFiles/fireworks.json +1 -0
  268. package/Tests/Samples/LottieFiles/gradient_1.json +1 -0
  269. package/Tests/Samples/LottieFiles/gradient_2.json +1 -0
  270. package/Tests/Samples/LottieFiles/gradient_pill.json +1 -0
  271. package/Tests/Samples/LottieFiles/gradient_shapes.json +1 -0
  272. package/Tests/Samples/LottieFiles/gradient_square.json +1 -0
  273. package/Tests/Samples/LottieFiles/growth.json +1 -0
  274. package/Tests/Samples/LottieFiles/infinity_loader.json +1 -0
  275. package/Tests/Samples/LottieFiles/loading_dots_1.json +1 -0
  276. package/Tests/Samples/LottieFiles/loading_dots_2.json +1 -0
  277. package/Tests/Samples/LottieFiles/loading_dots_3.json +1 -0
  278. package/Tests/Samples/LottieFiles/loading_gradient_strokes.json +1 -0
  279. package/Tests/Samples/LottieFiles/settings_slider.json +1 -0
  280. package/Tests/Samples/LottieFiles/shop.json +1 -0
  281. package/Tests/Samples/LottieFiles/step_loader.json +1 -0
  282. package/Tests/Samples/LottieLogo1.json +1 -0
  283. package/Tests/Samples/LottieLogo1_masked.json +1 -0
  284. package/Tests/Samples/LottieLogo2.json +1 -0
  285. package/Tests/Samples/MotionCorpse_Jrcanest.json +1 -0
  286. package/Tests/Samples/Nonanimating/BasicLayers.json +1 -0
  287. package/Tests/Samples/Nonanimating/DisableNodesTest.json +1 -0
  288. package/Tests/Samples/Nonanimating/FirstText.json +1 -0
  289. package/Tests/Samples/Nonanimating/GeometryTransformTest.json +1 -0
  290. package/Tests/Samples/Nonanimating/Text_AnimatedProperties.json +1 -0
  291. package/Tests/Samples/Nonanimating/Text_Glyph.json +1 -0
  292. package/Tests/Samples/Nonanimating/Text_NoAnimation.json +1 -0
  293. package/Tests/Samples/Nonanimating/Text_NoGlyph.json +1 -0
  294. package/Tests/Samples/Nonanimating/Zoom.json +1 -0
  295. package/Tests/Samples/Nonanimating/_dog.json +1 -0
  296. package/Tests/Samples/Nonanimating/base64Test.json +1 -0
  297. package/Tests/Samples/Nonanimating/blend_mode_test.json +1 -0
  298. package/Tests/Samples/Nonanimating/keypathTest.json +1 -0
  299. package/Tests/Samples/Nonanimating/verifyLineHeight.json +1 -0
  300. package/Tests/Samples/PinJump.json +1 -0
  301. package/Tests/Samples/Switch.json +1 -0
  302. package/Tests/Samples/Switch_States.json +1 -0
  303. package/Tests/Samples/TwitterHeart.json +1 -0
  304. package/Tests/Samples/TwitterHeartButton.json +1 -0
  305. package/Tests/Samples/TypeFace/A.json +1 -0
  306. package/Tests/Samples/TypeFace/Apostrophe.json +1 -0
  307. package/Tests/Samples/TypeFace/B.json +1 -0
  308. package/Tests/Samples/TypeFace/BlinkingCursor.json +1 -0
  309. package/Tests/Samples/TypeFace/C.json +1 -0
  310. package/Tests/Samples/TypeFace/Colon.json +1 -0
  311. package/Tests/Samples/TypeFace/Comma.json +1 -0
  312. package/Tests/Samples/TypeFace/D.json +1 -0
  313. package/Tests/Samples/TypeFace/E.json +1 -0
  314. package/Tests/Samples/TypeFace/F.json +1 -0
  315. package/Tests/Samples/TypeFace/G.json +1 -0
  316. package/Tests/Samples/TypeFace/H.json +1 -0
  317. package/Tests/Samples/TypeFace/I.json +1 -0
  318. package/Tests/Samples/TypeFace/J.json +1 -0
  319. package/Tests/Samples/TypeFace/K.json +1 -0
  320. package/Tests/Samples/TypeFace/L.json +1 -0
  321. package/Tests/Samples/TypeFace/M.json +1 -0
  322. package/Tests/Samples/TypeFace/N.json +1 -0
  323. package/Tests/Samples/TypeFace/O.json +1 -0
  324. package/Tests/Samples/TypeFace/P.json +1 -0
  325. package/Tests/Samples/TypeFace/Q.json +1 -0
  326. package/Tests/Samples/TypeFace/R.json +1 -0
  327. package/Tests/Samples/TypeFace/S.json +1 -0
  328. package/Tests/Samples/TypeFace/T.json +1 -0
  329. package/Tests/Samples/TypeFace/U.json +1 -0
  330. package/Tests/Samples/TypeFace/V.json +1 -0
  331. package/Tests/Samples/TypeFace/W.json +1 -0
  332. package/Tests/Samples/TypeFace/X.json +1 -0
  333. package/Tests/Samples/TypeFace/Y.json +1 -0
  334. package/Tests/Samples/TypeFace/Z.json +1 -0
  335. package/Tests/Samples/Watermelon.json +1 -0
  336. package/Tests/Samples/setValueTest.json +1 -0
  337. package/Tests/Samples/timeremap.json +1 -0
  338. package/Tests/Samples/vcTransition1.json +1 -0
  339. package/Tests/Samples/vcTransition2.json +1 -0
  340. package/Tests/SnapshotConfiguration.swift +158 -0
  341. package/Tests/SnapshotTests.swift +265 -0
  342. package/Tests/Utils/Bundle+Module.swift +30 -0
  343. package/Tests/Utils/HardcodedFontProvider.swift +19 -0
  344. package/Tests/Utils/HardcodedImageProvider.swift +23 -0
  345. package/Tests/Utils/Snapshotting+presentationLayer.swift +47 -0
  346. package/Tests/ValueProvidersTests.swift +27 -0
  347. package/lottie-ios.podspec +12 -12
  348. package/package.json +1 -1
  349. package/script/test-carthage/Cartfile +1 -0
  350. package/script/test-carthage/Cartfile.resolved +1 -0
  351. package/script/test-carthage/CarthageTest/AppDelegate.swift +26 -0
  352. package/script/test-carthage/CarthageTest/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  353. package/script/test-carthage/CarthageTest/Assets.xcassets/AppIcon.appiconset/Contents.json +98 -0
  354. package/script/test-carthage/CarthageTest/Assets.xcassets/Contents.json +6 -0
  355. package/script/test-carthage/CarthageTest/Base.lproj/LaunchScreen.storyboard +25 -0
  356. package/script/test-carthage/CarthageTest/Base.lproj/Main.storyboard +24 -0
  357. package/script/test-carthage/CarthageTest/Info.plist +66 -0
  358. package/script/test-carthage/CarthageTest/SceneDelegate.swift +10 -0
  359. package/script/test-carthage/CarthageTest/ViewController.swift +15 -0
  360. package/script/test-carthage/CarthageTest-macOS/AppDelegate.swift +7 -0
  361. package/script/test-carthage/CarthageTest-macOS/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  362. package/script/test-carthage/CarthageTest-macOS/Assets.xcassets/AppIcon.appiconset/Contents.json +58 -0
  363. package/script/test-carthage/CarthageTest-macOS/Assets.xcassets/Contents.json +6 -0
  364. package/script/test-carthage/CarthageTest-macOS/Base.lproj/Main.storyboard +717 -0
  365. package/script/test-carthage/CarthageTest-macOS/CarthageTest_macOS.entitlements +10 -0
  366. package/script/test-carthage/CarthageTest-macOS/ViewController.swift +15 -0
  367. package/script/test-carthage/CarthageTest.xcodeproj/project.pbxproj +532 -0
  368. package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  369. package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  370. package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  371. package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  372. package/script/test-carthage/CarthageTest.xcodeproj/xcuserdata/cal.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  373. package/script/test-carthage/CarthageTest.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +19 -0
  374. package/script/test-carthage/Mintfile +1 -0
  375. package/script/test-spm/LottieSPM.xcworkspace/contents.xcworkspacedata +7 -0
  376. package/script/test-spm/LottieSPM.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  377. package/script/test-spm/Mintfile +1 -0
  378. package/.swiftpm/xcode/package.xcworkspace/xcuserdata/brandonwithrow.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  379. package/Lottie/Info.plist +0 -22
  380. package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/brandonwithrow.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  381. package/Lottie.xcodeproj/xcuserdata/brandonwithrow.xcuserdatad/xcschemes/LottieLibraryMacOS.xcscheme +0 -80
  382. package/Lottie.xcodeproj/xcuserdata/brandonwithrow.xcuserdatad/xcschemes/xcschememanagement.plist +0 -57
  383. package/lottie-swift/Assets/.gitkeep +0 -0
  384. package/lottie-swift/src/Private/LayerContainers/Utility/LayerFontProvider.swift +0 -37
  385. package/lottie-swift/src/Private/LayerContainers/Utility/LayerTextProvider.swift +0 -36
  386. package/lottie-swift/src/Private/Model/Animation.swift +0 -107
  387. package/lottie-swift/src/Private/Model/Assets/Asset.swift +0 -27
  388. package/lottie-swift/src/Private/Model/Assets/ImageAsset.swift +0 -48
  389. package/lottie-swift/src/Private/Model/Keyframes/Keyframe.swift +0 -128
  390. package/lottie-swift/src/Private/Model/Keyframes/KeyframeGroup.swift +0 -108
  391. package/lottie-swift/src/Private/Model/Layers/LayerModel.swift +0 -150
  392. package/lottie-swift/src/Private/Model/Objects/DashPattern.swift +0 -24
  393. package/lottie-swift/src/Private/Model/Objects/Marker.swift +0 -23
  394. package/lottie-swift/src/Private/Model/Objects/Mask.swift +0 -48
  395. package/lottie-swift/src/Private/Model/Objects/Transform.swift +0 -105
  396. package/lottie-swift/src/Private/Model/ShapeItems/Ellipse.swift +0 -50
  397. package/lottie-swift/src/Private/Model/ShapeItems/FillI.swift +0 -49
  398. package/lottie-swift/src/Private/Model/ShapeItems/GradientFill.swift +0 -86
  399. package/lottie-swift/src/Private/Model/ShapeItems/GradientStroke.swift +0 -125
  400. package/lottie-swift/src/Private/Model/ShapeItems/Group.swift +0 -32
  401. package/lottie-swift/src/Private/Model/ShapeItems/Rectangle.swift +0 -50
  402. package/lottie-swift/src/Private/Model/ShapeItems/Repeater.swift +0 -80
  403. package/lottie-swift/src/Private/Model/ShapeItems/Shape.swift +0 -37
  404. package/lottie-swift/src/Private/Model/ShapeItems/ShapeItem.swift +0 -95
  405. package/lottie-swift/src/Private/Model/ShapeItems/ShapeTransform.swift +0 -68
  406. package/lottie-swift/src/Private/Model/ShapeItems/Star.swift +0 -86
  407. package/lottie-swift/src/Private/Model/ShapeItems/Stroke.swift +0 -67
  408. package/lottie-swift/src/Private/Model/ShapeItems/Trim.swift +0 -53
  409. package/lottie-swift/src/Private/Model/Text/Font.swift +0 -35
  410. package/lottie-swift/src/Private/Model/Text/TextAnimator.swift +0 -99
  411. package/lottie-swift/src/Private/Model/Text/TextDocument.swift +0 -70
  412. package/lottie-swift/src/Private/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +0 -109
  413. package/lottie-swift/src/Private/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +0 -132
  414. package/lottie-swift/src/Private/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +0 -141
  415. package/lottie-swift/src/Private/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +0 -127
  416. package/lottie-swift/src/Private/Utility/Extensions/MathKit.swift +0 -539
  417. package/lottie-swift/src/Private/Utility/Extensions/StringExtensions.swift +0 -32
  418. package/lottie-swift/src/Private/Utility/Interpolatable/Interpolatable.swift +0 -18
  419. package/lottie-swift/src/Private/Utility/Interpolatable/InterpolatableExtensions.swift +0 -170
  420. package/lottie-swift/src/Private/Utility/Primitives/CurveVertex.swift +0 -177
  421. package/lottie-swift/src/Private/Utility/Primitives/PathElement.swift +0 -68
  422. package/lottie-swift/src/Private/Utility/Primitives/VectorsExtensions.swift +0 -218
  423. package/lottie-swift/src/Public/Animation/AnimationPublic.swift +0 -196
  424. package/lottie-swift/src/Public/Animation/AnimationView.swift +0 -1006
  425. package/lottie-swift/src/Public/Animation/AnimationViewInitializers.swift +0 -83
  426. package/lottie-swift/src/Public/AnimationCache/AnimationCacheProvider.swift +0 -24
  427. package/lottie-swift/src/Public/DynamicProperties/AnimationKeypath.swift +0 -46
  428. package/lottie-swift/src/Public/DynamicProperties/AnyValueProvider.swift +0 -29
  429. package/lottie-swift/src/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +0 -114
  430. package/lottie-swift/src/Public/ImageProvider/AnimationImageProvider.swift +0 -23
  431. package/lottie-swift/src/Public/MacOS/FilepathImageProvider.swift +0 -67
  432. package/lottie-swift/src/Public/TextProvider/AnimationTextProvider.swift +0 -39
  433. package/lottie-swift/src/Public/iOS/LottieView.swift +0 -62
  434. package/lottie-swift-testing.podspec +0 -32
@@ -0,0 +1,154 @@
1
+ // Created by Cal Stephens on 1/28/22.
2
+ // Copyright © 2022 Airbnb Inc. All rights reserved.
3
+
4
+ // MARK: - Keyframes
5
+
6
+ enum Keyframes {
7
+
8
+ // MARK: Internal
9
+
10
+ /// Combines the given keyframe groups of `Keyframe<T>`s into a single keyframe group of
11
+ /// of `Keyframe<[T]>`s if all of the `KeyframeGroup`s have the exact same animation timing
12
+ static func combinedIfPossible<T>(_ allGroups: [KeyframeGroup<T>]) -> KeyframeGroup<[T]>? {
13
+ combinedIfPossible(allGroups, makeCombinedResult: { index in
14
+ allGroups.map { $0.valueForCombinedKeyframes(at: index) }
15
+ })
16
+ }
17
+
18
+ /// Combines the given keyframe groups of `Keyframe<T>`s into a single keyframe group of
19
+ /// of `Keyframe<[T]>`s if all of the `KeyframeGroup`s have the exact same animation timing
20
+ static func combinedIfPossible<T1, T2, CombinedResult>(
21
+ _ k1: KeyframeGroup<T1>,
22
+ _ k2: KeyframeGroup<T2>,
23
+ makeCombinedResult: (T1, T2) -> CombinedResult)
24
+ -> KeyframeGroup<CombinedResult>?
25
+ {
26
+ combinedIfPossible(
27
+ [k1, k2],
28
+ makeCombinedResult: { index in
29
+ makeCombinedResult(
30
+ k1.valueForCombinedKeyframes(at: index),
31
+ k2.valueForCombinedKeyframes(at: index))
32
+ })
33
+ }
34
+
35
+ /// Combines the given keyframe groups of `Keyframe<T>`s into a single keyframe group of
36
+ /// of `Keyframe<[T]>`s if all of the `KeyframeGroup`s have the exact same animation timing
37
+ static func combinedIfPossible<T1, T2, T3, CombinedResult>(
38
+ _ k1: KeyframeGroup<T1>,
39
+ _ k2: KeyframeGroup<T2>,
40
+ _ k3: KeyframeGroup<T3>,
41
+ makeCombinedResult: (T1, T2, T3) -> CombinedResult)
42
+ -> KeyframeGroup<CombinedResult>?
43
+ {
44
+ combinedIfPossible(
45
+ [k1, k2, k3],
46
+ makeCombinedResult: { index in
47
+ makeCombinedResult(
48
+ k1.valueForCombinedKeyframes(at: index),
49
+ k2.valueForCombinedKeyframes(at: index),
50
+ k3.valueForCombinedKeyframes(at: index))
51
+ })
52
+ }
53
+
54
+ /// Combines the given keyframe groups of `Keyframe<T>`s into a single keyframe group of
55
+ /// of `Keyframe<[T]>`s if all of the `KeyframeGroup`s have the exact same animation timing
56
+ static func combinedIfPossible<T1, T2, T3, T4, T5, T6, T7, CombinedResult>(
57
+ _ k1: KeyframeGroup<T1>,
58
+ _ k2: KeyframeGroup<T2>,
59
+ _ k3: KeyframeGroup<T3>,
60
+ _ k4: KeyframeGroup<T4>,
61
+ _ k5: KeyframeGroup<T5>,
62
+ _ k6: KeyframeGroup<T6>,
63
+ _ k7: KeyframeGroup<T7>,
64
+ makeCombinedResult: (T1, T2, T3, T4, T5, T6, T7) -> CombinedResult)
65
+ -> KeyframeGroup<CombinedResult>?
66
+ {
67
+ combinedIfPossible(
68
+ [k1, k2, k3, k4, k5, k6, k7],
69
+ makeCombinedResult: { index in
70
+ makeCombinedResult(
71
+ k1.valueForCombinedKeyframes(at: index),
72
+ k2.valueForCombinedKeyframes(at: index),
73
+ k3.valueForCombinedKeyframes(at: index),
74
+ k4.valueForCombinedKeyframes(at: index),
75
+ k5.valueForCombinedKeyframes(at: index),
76
+ k6.valueForCombinedKeyframes(at: index),
77
+ k7.valueForCombinedKeyframes(at: index))
78
+ })
79
+ }
80
+
81
+ // MARK: Private
82
+
83
+ /// Combines the given `[KeyframeGroup]` of `Keyframe<T>`s into a single `KeyframeGroup`
84
+ /// of `Keyframe<CombinedResult>`s if all of the `KeyframeGroup`s have the exact same animation timing
85
+ private static func combinedIfPossible<CombinedResult>(
86
+ _ allGroups: [AnyKeyframeGroup],
87
+ makeCombinedResult: (_ index: Int) -> CombinedResult)
88
+ -> KeyframeGroup<CombinedResult>?
89
+ {
90
+ let untypedGroups = allGroups.map { $0.untyped }
91
+
92
+ // Animations with no timing information (e.g. with just a single keyframe)
93
+ // can be trivially combined with any other set of keyframes, so we don't need
94
+ // to check those.
95
+ let animatingKeyframes = untypedGroups.filter { $0.keyframes.count > 1 }
96
+
97
+ guard
98
+ !allGroups.isEmpty,
99
+ animatingKeyframes.allSatisfy({ $0.hasSameTimingParameters(as: animatingKeyframes[0]) })
100
+ else { return nil }
101
+
102
+ var combinedKeyframes = ContiguousArray<Keyframe<CombinedResult>>()
103
+ let baseKeyframes = (animatingKeyframes.first ?? untypedGroups[0]).keyframes
104
+
105
+ for index in baseKeyframes.indices {
106
+ let baseKeyframe = baseKeyframes[index]
107
+ let combinedValue = makeCombinedResult(index)
108
+ combinedKeyframes.append(baseKeyframe.withValue(combinedValue))
109
+ }
110
+
111
+ return KeyframeGroup(keyframes: combinedKeyframes)
112
+ }
113
+
114
+ }
115
+
116
+ extension KeyframeGroup {
117
+ /// Whether or not all of the keyframes in this `KeyframeGroup` have the same
118
+ /// timing parameters as the corresponding keyframe in the other given `KeyframeGroup`
119
+ func hasSameTimingParameters<T>(as other: KeyframeGroup<T>) -> Bool {
120
+ guard keyframes.count == other.keyframes.count else {
121
+ return false
122
+ }
123
+
124
+ return zip(keyframes, other.keyframes).allSatisfy {
125
+ $0.hasSameTimingParameters(as: $1)
126
+ }
127
+ }
128
+ }
129
+
130
+ extension Keyframe {
131
+ /// Whether or not this keyframe has the same timing parameters as the given keyframe,
132
+ /// excluding `spatialInTangent` and `spatialOutTangent`.
133
+ fileprivate func hasSameTimingParameters<T>(as other: Keyframe<T>) -> Bool {
134
+ time == other.time
135
+ && isHold == other.isHold
136
+ && inTangent == other.inTangent
137
+ && outTangent == other.outTangent
138
+ // We intentionally don't compare spatial in/out tangents,
139
+ // since those values are only used in very specific cases
140
+ // (animating the x/y position of a layer), which aren't ever
141
+ // combined in this way.
142
+ }
143
+ }
144
+
145
+ extension KeyframeGroup {
146
+ /// The value to use for a combined set of keyframes, for the given index
147
+ fileprivate func valueForCombinedKeyframes(at index: Int) -> T {
148
+ if keyframes.count == 1 {
149
+ return keyframes[0].value
150
+ } else {
151
+ return keyframes[index].value
152
+ }
153
+ }
154
+ }
@@ -0,0 +1,83 @@
1
+ // Created by Cal Stephens on 12/14/21.
2
+ // Copyright © 2021 Airbnb Inc. All rights reserved.
3
+
4
+ import QuartzCore
5
+
6
+ // MARK: - AnimationLayer
7
+
8
+ /// A type of `CALayer` that can be used in a Lottie animation
9
+ /// - Layers backed by a `LayerModel` subclass should subclass `BaseCompositionLayer`
10
+ protocol AnimationLayer: CALayer {
11
+ /// Instructs this layer to setup its `CAAnimation`s
12
+ /// using the given `LayerAnimationContext`
13
+ func setupAnimations(context: LayerAnimationContext) throws
14
+ }
15
+
16
+ // MARK: - LayerAnimationContext
17
+
18
+ // Context describing the timing parameters of the current animation
19
+ struct LayerAnimationContext {
20
+ /// The animation being played
21
+ let animation: Animation
22
+
23
+ /// The timing configuration that should be applied to `CAAnimation`s
24
+ let timingConfiguration: CoreAnimationLayer.CAMediaTimingConfiguration
25
+
26
+ /// The absolute frame number that this animation begins at
27
+ let startFrame: AnimationFrameTime
28
+
29
+ /// The absolute frame number that this animation ends at
30
+ let endFrame: AnimationFrameTime
31
+
32
+ /// The set of custom Value Providers applied to this animation
33
+ let valueProviderStore: ValueProviderStore
34
+
35
+ /// Information about whether or not an animation is compatible with the Core Animation engine
36
+ let compatibilityTracker: CompatibilityTracker
37
+
38
+ /// The logger that should be used for assertions and warnings
39
+ let logger: LottieLogger
40
+
41
+ /// The AnimationKeypath represented by the current layer
42
+ var currentKeypath: AnimationKeypath
43
+
44
+ /// Whether or not to log `AnimationKeypath`s for all of the animation's layers
45
+ /// - Used for `CoreAnimationLayer.logHierarchyKeypaths()`
46
+ var logHierarchyKeypaths: Bool
47
+
48
+ /// A closure that remaps the given frame in the child layer's local time to a frame
49
+ /// in the animation's overall global time
50
+ private(set) var timeRemapping: ((AnimationFrameTime) -> AnimationFrameTime) = { $0 }
51
+
52
+ /// Adds the given component string to the `AnimationKeypath` stored
53
+ /// that describes the current path being configured by this context value
54
+ func addingKeypathComponent(_ component: String) -> LayerAnimationContext {
55
+ var context = self
56
+ context.currentKeypath.keys.append(component)
57
+ return context
58
+ }
59
+
60
+ /// The `AnimationProgressTime` for the given `AnimationFrameTime` within this layer,
61
+ /// accounting for the `timeRemapping` applied to this layer
62
+ func progressTime(for frame: AnimationFrameTime) -> AnimationProgressTime {
63
+ animation.progressTime(forFrame: timeRemapping(frame), clamped: false)
64
+ }
65
+
66
+ /// The real-time `TimeInterval` for the given `AnimationFrameTime` within this layer,
67
+ /// accounting for the `timeRemapping` applied to this layer
68
+ func time(for frame: AnimationFrameTime) -> TimeInterval {
69
+ animation.time(forFrame: timeRemapping(frame))
70
+ }
71
+
72
+ /// Chains an additional `timeRemapping` closure onto this layer context
73
+ func withTimeRemapping(
74
+ _ additionalTimeRemapping: @escaping (AnimationFrameTime) -> AnimationFrameTime)
75
+ -> LayerAnimationContext
76
+ {
77
+ var copy = self
78
+ copy.timeRemapping = { [existingTimeRemapping = timeRemapping] time in
79
+ existingTimeRemapping(additionalTimeRemapping(time))
80
+ }
81
+ return copy
82
+ }
83
+ }
@@ -0,0 +1,33 @@
1
+ // Created by Cal Stephens on 1/27/22.
2
+ // Copyright © 2022 Airbnb Inc. All rights reserved.
3
+
4
+ import QuartzCore
5
+
6
+ /// A base `CALayer` that manages the frame and animations
7
+ /// of its `sublayers` and `mask`
8
+ class BaseAnimationLayer: CALayer, AnimationLayer {
9
+
10
+ // MARK: Internal
11
+
12
+ override func layoutSublayers() {
13
+ super.layoutSublayers()
14
+
15
+ for sublayer in managedSublayers {
16
+ sublayer.fillBoundsOfSuperlayer()
17
+ }
18
+ }
19
+
20
+ func setupAnimations(context: LayerAnimationContext) throws {
21
+ for childAnimationLayer in managedSublayers {
22
+ try (childAnimationLayer as? AnimationLayer)?.setupAnimations(context: context)
23
+ }
24
+ }
25
+
26
+ // MARK: Private
27
+
28
+ /// All of the sublayers managed by this container
29
+ private var managedSublayers: [CALayer] {
30
+ (sublayers ?? []) + [mask].compactMap { $0 }
31
+ }
32
+
33
+ }
@@ -0,0 +1,88 @@
1
+ // Created by Cal Stephens on 12/20/21.
2
+ // Copyright © 2021 Airbnb Inc. All rights reserved.
3
+
4
+ import QuartzCore
5
+
6
+ // MARK: - BaseCompositionLayer
7
+
8
+ /// The base type of `AnimationLayer` that can contain other `AnimationLayer`s
9
+ class BaseCompositionLayer: BaseAnimationLayer {
10
+
11
+ // MARK: Lifecycle
12
+
13
+ init(layerModel: LayerModel) {
14
+ baseLayerModel = layerModel
15
+ super.init()
16
+
17
+ setupSublayers()
18
+ compositingFilter = layerModel.blendMode.filterName
19
+ name = layerModel.name
20
+ }
21
+
22
+ required init?(coder _: NSCoder) {
23
+ fatalError("init(coder:) has not been implemented")
24
+ }
25
+
26
+ /// Called by CoreAnimation to create a shadow copy of this layer
27
+ /// More details: https://developer.apple.com/documentation/quartzcore/calayer/1410842-init
28
+ override init(layer: Any) {
29
+ guard let typedLayer = layer as? Self else {
30
+ fatalError("\(Self.self).init(layer:) incorrectly called with \(type(of: layer))")
31
+ }
32
+
33
+ baseLayerModel = typedLayer.baseLayerModel
34
+ super.init(layer: typedLayer)
35
+ }
36
+
37
+ // MARK: Internal
38
+
39
+ /// Whether or not this layer render should render any visible content
40
+ var renderLayerContents: Bool { true }
41
+
42
+ /// Sets up the base `LayerModel` animations for this layer,
43
+ /// and all child `AnimationLayer`s.
44
+ /// - Can be overridden by subclasses, which much call `super`.
45
+ override func setupAnimations(context: LayerAnimationContext) throws {
46
+ var context = context
47
+ if renderLayerContents {
48
+ context = context.addingKeypathComponent(baseLayerModel.name)
49
+ }
50
+
51
+ try setupLayerAnimations(context: context)
52
+ try setupChildAnimations(context: context)
53
+ }
54
+
55
+ func setupLayerAnimations(context: LayerAnimationContext) throws {
56
+ let context = context.addingKeypathComponent(baseLayerModel.name)
57
+
58
+ try addTransformAnimations(for: baseLayerModel.transform, context: context)
59
+
60
+ if renderLayerContents {
61
+ try addOpacityAnimation(for: baseLayerModel.transform, context: context)
62
+
63
+ addVisibilityAnimation(
64
+ inFrame: CGFloat(baseLayerModel.inFrame),
65
+ outFrame: CGFloat(baseLayerModel.outFrame),
66
+ context: context)
67
+ }
68
+ }
69
+
70
+ func setupChildAnimations(context: LayerAnimationContext) throws {
71
+ try super.setupAnimations(context: context)
72
+ }
73
+
74
+ // MARK: Private
75
+
76
+ private let baseLayerModel: LayerModel
77
+
78
+ private func setupSublayers() {
79
+ if
80
+ renderLayerContents,
81
+ let masks = baseLayerModel.masks?.filter({ $0.mode != .none }),
82
+ !masks.isEmpty
83
+ {
84
+ mask = MaskCompositionLayer(masks: masks)
85
+ }
86
+ }
87
+
88
+ }
@@ -0,0 +1,167 @@
1
+ // Created by Cal Stephens on 1/11/22.
2
+ // Copyright © 2022 Airbnb Inc. All rights reserved.
3
+
4
+ import QuartzCore
5
+
6
+ extension CALayer {
7
+
8
+ // MARK: Internal
9
+
10
+ /// Sets up an `AnimationLayer` / `CALayer` hierarchy in this layer,
11
+ /// using the given list of layers.
12
+ @nonobjc
13
+ func setupLayerHierarchy(
14
+ for layers: [LayerModel],
15
+ context: LayerContext)
16
+ throws
17
+ {
18
+ // An `Animation`'s `LayerModel`s are listed from front to back,
19
+ // but `CALayer.sublayers` are listed from back to front.
20
+ // We reverse the layer ordering to match what Core Animation expects.
21
+ // The final view hierarchy must display the layers in this exact order.
22
+ let layersInZAxisOrder = layers.reversed()
23
+
24
+ let layersByIndex = Dictionary(grouping: layersInZAxisOrder, by: \.index)
25
+ .compactMapValues(\.first)
26
+
27
+ /// Layers specify a `parent` layer. Child layers inherit the `transform` of their parent.
28
+ /// - We can't add the child as a sublayer of the parent `CALayer`, since that would
29
+ /// break the ordering specified in `layersInZAxisOrder`.
30
+ /// - Instead, we create an invisible `TransformLayer` to handle the parent
31
+ /// transform animations, and add the child layer to that `TransformLayer`.
32
+ func makeParentTransformLayer(
33
+ childLayerModel: LayerModel,
34
+ childLayer: CALayer,
35
+ name: (LayerModel) -> String)
36
+ -> CALayer
37
+ {
38
+ guard
39
+ let parentIndex = childLayerModel.parent,
40
+ let parentLayerModel = layersByIndex[parentIndex]
41
+ else { return childLayer }
42
+
43
+ let parentLayer = TransformLayer(layerModel: parentLayerModel)
44
+ parentLayer.name = name(parentLayerModel)
45
+ parentLayer.addSublayer(childLayer)
46
+
47
+ return makeParentTransformLayer(
48
+ childLayerModel: parentLayerModel,
49
+ childLayer: parentLayer,
50
+ name: name)
51
+ }
52
+
53
+ // Create an `AnimationLayer` for each `LayerModel`
54
+ for (layerModel, mask) in try layersInZAxisOrder.pairedLayersAndMasks(context: context) {
55
+ guard let layer = try layerModel.makeAnimationLayer(context: context) else {
56
+ continue
57
+ }
58
+
59
+ // If this layer has a `parent`, we create an invisible `TransformLayer`
60
+ // to handle displaying / animating the parent transform.
61
+ let parentTransformLayer = makeParentTransformLayer(
62
+ childLayerModel: layerModel,
63
+ childLayer: layer,
64
+ name: { parentLayerModel in
65
+ "\(layerModel.name) (parent, \(parentLayerModel.name))"
66
+ })
67
+
68
+ // Create the `mask` layer for this layer, if it has a `MatteType`
69
+ if
70
+ let mask = mask,
71
+ let maskLayer = try maskLayer(for: mask.model, type: mask.matteType, context: context)
72
+ {
73
+ let maskParentTransformLayer = makeParentTransformLayer(
74
+ childLayerModel: mask.model,
75
+ childLayer: maskLayer,
76
+ name: { parentLayerModel in
77
+ "\(mask.model.name) (mask of \(layerModel.name)) (parent, \(parentLayerModel.name))"
78
+ })
79
+
80
+ // Set up a parent container to host both the layer
81
+ // and its mask in the same coordinate space
82
+ let maskContainer = BaseAnimationLayer()
83
+ maskContainer.name = "\(layerModel.name) (parent, masked)"
84
+ maskContainer.addSublayer(parentTransformLayer)
85
+
86
+ // Core Animation will silently fail to apply a mask if a `mask` layer
87
+ // itself _also_ has a `mask`. As a workaround, we can wrap this layer's
88
+ // mask in an additional container layer which never has its own `mask`.
89
+ let additionalMaskParent = BaseAnimationLayer()
90
+ additionalMaskParent.addSublayer(maskParentTransformLayer)
91
+ maskContainer.mask = additionalMaskParent
92
+
93
+ addSublayer(maskContainer)
94
+ }
95
+
96
+ else {
97
+ addSublayer(parentTransformLayer)
98
+ }
99
+ }
100
+ }
101
+
102
+ // MARK: Fileprivate
103
+
104
+ /// Creates a mask `CALayer` from the given matte layer model, using the `MatteType`
105
+ /// from the layer that is being masked.
106
+ fileprivate func maskLayer(
107
+ for matteLayerModel: LayerModel,
108
+ type: MatteType,
109
+ context: LayerContext) throws
110
+ -> CALayer?
111
+ {
112
+ switch type {
113
+ case .add:
114
+ return try matteLayerModel.makeAnimationLayer(context: context)
115
+
116
+ case .invert:
117
+ guard let maskLayer = try matteLayerModel.makeAnimationLayer(context: context) else {
118
+ return nil
119
+ }
120
+
121
+ // We can invert the mask layer by having a large solid black layer with the
122
+ // given mask layer subtracted out using the `xor` blend mode. When applied to the
123
+ // layer being masked, this creates an inverted mask where only areas _outside_
124
+ // of the mask layer are visible.
125
+ // https://developer.apple.com/documentation/coregraphics/cgblendmode/xor
126
+ let base = BaseAnimationLayer()
127
+ base.backgroundColor = .rgb(0, 0, 0)
128
+ base.addSublayer(maskLayer)
129
+ maskLayer.compositingFilter = "xor"
130
+ return base
131
+
132
+ case .none, .unknown:
133
+ return nil
134
+ }
135
+ }
136
+
137
+ }
138
+
139
+ extension Collection where Element == LayerModel {
140
+ /// Pairs each `LayerModel` within this array with
141
+ /// a `LayerModel` to use as its mask, if applicable
142
+ /// based on the layer's `MatteType` configuration.
143
+ /// - Assumes the layers are sorted in z-axis order.
144
+ fileprivate func pairedLayersAndMasks(context _: LayerContext) throws
145
+ -> [(layer: LayerModel, mask: (model: LayerModel, matteType: MatteType)?)]
146
+ {
147
+ var layersAndMasks = [(layer: LayerModel, mask: (model: LayerModel, matteType: MatteType)?)]()
148
+ var unprocessedLayers = reversed()
149
+
150
+ while let layer = unprocessedLayers.popLast() {
151
+ /// If a layer has a `MatteType`, then the next layer will be used as its `mask`
152
+ if
153
+ let matteType = layer.matte,
154
+ matteType != .none,
155
+ let maskLayer = unprocessedLayers.popLast()
156
+ {
157
+ layersAndMasks.append((layer: layer, mask: (model: maskLayer, matteType: matteType)))
158
+ }
159
+
160
+ else {
161
+ layersAndMasks.append((layer: layer, mask: nil))
162
+ }
163
+ }
164
+
165
+ return layersAndMasks
166
+ }
167
+ }
@@ -0,0 +1,94 @@
1
+ // Created by Cal Stephens on 1/10/22.
2
+ // Copyright © 2022 Airbnb Inc. All rights reserved.
3
+
4
+ import QuartzCore
5
+
6
+ // MARK: - GradientRenderLayer
7
+
8
+ /// A `CAGradientLayer` subclass used to render a gradient _outside_ the normal layer bounds
9
+ ///
10
+ /// - `GradientFill.startPoint` and `GradientFill.endPoint` are expressed
11
+ /// with respect to the `bounds` of the `ShapeItemLayer`.
12
+ ///
13
+ /// - The gradient itself is supposed to be rendered infinitely in all directions
14
+ /// (e.g. including outside of `bounds`). This is because `ShapeItemLayer` paths
15
+ /// don't necessarily sit within the layer's `bounds`.
16
+ ///
17
+ /// - To support this, `GradientRenderLayer` tracks a `gradientReferenceBounds`
18
+ /// that `startPoint` / `endPoint` are calculated relative to.
19
+ /// The _actual_ `bounds` of this layer is padded by a large amount so that
20
+ /// the gradient can be drawn outside of the `gradientReferenceBounds`.
21
+ ///
22
+ final class GradientRenderLayer: CAGradientLayer {
23
+
24
+ // MARK: Internal
25
+
26
+ /// The reference bounds within this layer that the gradient's
27
+ /// `startPoint` and `endPoint` should be calculated relative to
28
+ var gradientReferenceBounds: CGRect = .zero {
29
+ didSet {
30
+ if oldValue != gradientReferenceBounds {
31
+ updateLayout()
32
+ }
33
+ }
34
+ }
35
+
36
+ /// Converts the given `CGPoint` within `gradientReferenceBounds`
37
+ /// to a percentage value relative to the full `bounds` of this layer
38
+ /// - This converts absolute `startPoint` and `endPoint` values into
39
+ /// the percent-based values expected by Core Animation,
40
+ /// with respect to the custom bounds geometry used by this layer type.
41
+ func percentBasedPointInBounds(from referencePoint: CGPoint) -> CGPoint {
42
+ guard bounds.width > 0, bounds.height > 0 else {
43
+ LottieLogger.shared.assertionFailure("Size must be non-zero before an animation can be played")
44
+ return .zero
45
+ }
46
+
47
+ let pointInBounds = CGPoint(
48
+ x: referencePoint.x + gradientPadding,
49
+ y: referencePoint.y + gradientPadding)
50
+
51
+ return CGPoint(
52
+ x: CGFloat(pointInBounds.x) / bounds.width,
53
+ y: CGFloat(pointInBounds.y) / bounds.height)
54
+ }
55
+
56
+ // MARK: Private
57
+
58
+ /// Extra padding around the `gradientReferenceBounds` where the gradient is also rendered
59
+ /// - This specific value is arbitrary and can be increased if necessary.
60
+ /// Theoretically this should be "infinite", to match the behavior of
61
+ /// `CGContext.drawLinearGradient` with `[.drawsAfterEndLocation, .drawsBeforeStartLocation]`.
62
+ private let gradientPadding: CGFloat = 10_000
63
+
64
+ private func updateLayout() {
65
+ anchorPoint = .zero
66
+
67
+ bounds = CGRect(
68
+ x: gradientReferenceBounds.origin.x,
69
+ y: gradientReferenceBounds.origin.y,
70
+ width: gradientPadding + gradientReferenceBounds.width + gradientPadding,
71
+ height: gradientPadding + gradientReferenceBounds.height + gradientPadding)
72
+
73
+ // Align the center of this layer to be at the center point of its parent layer
74
+ let superlayerSize = superlayer?.frame.size ?? gradientReferenceBounds.size
75
+
76
+ transform = CATransform3DMakeTranslation(
77
+ (superlayerSize.width - bounds.width) / 2,
78
+ (superlayerSize.height - bounds.height) / 2,
79
+ 0)
80
+ }
81
+
82
+ }
83
+
84
+ // MARK: CustomLayoutLayer
85
+
86
+ extension GradientRenderLayer: CustomLayoutLayer {
87
+ func layout(superlayerBounds: CGRect) {
88
+ gradientReferenceBounds = superlayerBounds
89
+
90
+ if let gradientMask = mask as? GradientRenderLayer {
91
+ gradientMask.layout(superlayerBounds: superlayerBounds)
92
+ }
93
+ }
94
+ }