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,67 @@
1
+ //
2
+ // FilepathImageProvider.swift
3
+ // lottie-swift
4
+ //
5
+ // Created by Brandon Withrow on 2/1/19.
6
+ //
7
+
8
+ #if os(macOS)
9
+ import AppKit
10
+
11
+ /// An `AnimationImageProvider` that provides images by name from a specific filepath.
12
+ public class FilepathImageProvider: AnimationImageProvider {
13
+
14
+ // MARK: Lifecycle
15
+
16
+ /// Initializes an image provider with a specific filepath.
17
+ ///
18
+ /// - Parameter filepath: The absolute filepath containing the images.
19
+ ///
20
+ public init(filepath: String) {
21
+ self.filepath = URL(fileURLWithPath: filepath)
22
+ }
23
+
24
+ public init(filepath: URL) {
25
+ self.filepath = filepath
26
+ }
27
+
28
+ // MARK: Public
29
+
30
+ public func imageForAsset(asset: ImageAsset) -> CGImage? {
31
+ if
32
+ asset.name.hasPrefix("data:"),
33
+ let url = URL(string: asset.name),
34
+ let data = try? Data(contentsOf: url),
35
+ let image = NSImage(data: data)
36
+ {
37
+ return image.lottie_CGImage
38
+ }
39
+
40
+ let directPath = filepath.appendingPathComponent(asset.name).path
41
+ if FileManager.default.fileExists(atPath: directPath) {
42
+ return NSImage(contentsOfFile: directPath)?.lottie_CGImage
43
+ }
44
+
45
+ let pathWithDirectory = filepath.appendingPathComponent(asset.directory).appendingPathComponent(asset.name).path
46
+ if FileManager.default.fileExists(atPath: pathWithDirectory) {
47
+ return NSImage(contentsOfFile: pathWithDirectory)?.lottie_CGImage
48
+ }
49
+
50
+ LottieLogger.shared.warn("Could not find image \"\(asset.name)\" in bundle")
51
+ return nil
52
+ }
53
+
54
+ // MARK: Internal
55
+
56
+ let filepath: URL
57
+ }
58
+
59
+ extension NSImage {
60
+ @nonobjc
61
+ var lottie_CGImage: CGImage? {
62
+ guard let imageData = tiffRepresentation else { return nil }
63
+ guard let sourceData = CGImageSourceCreateWithData(imageData as CFData, nil) else { return nil }
64
+ return CGImageSourceCreateImageAtIndex(sourceData, 0, nil)
65
+ }
66
+ }
67
+ #endif
@@ -0,0 +1,103 @@
1
+ // Created by Cal Stephens on 1/24/22.
2
+ // Copyright © 2022 Airbnb Inc. All rights reserved.
3
+
4
+ import SnapshotTesting
5
+ import XCTest
6
+
7
+ @testable import Lottie
8
+
9
+ final class AnimationKeypathTests: XCTestCase {
10
+
11
+ // MARK: Internal
12
+
13
+ func testKeypathMatches() {
14
+ let keypath = AnimationKeypath(keypath: "Layer.Shape Group.Stroke 1.Color")
15
+
16
+ XCTAssertTrue(keypath.matches("Layer.Shape Group.Stroke 1.Color"))
17
+ XCTAssertTrue(keypath.matches("**.Color"))
18
+ XCTAssertTrue(keypath.matches("**.Stroke 1.Color"))
19
+ XCTAssertTrue(keypath.matches("**.Shape Group.Stroke 1.Color"))
20
+ XCTAssertTrue(keypath.matches("Layer.**.Color"))
21
+ XCTAssertTrue(keypath.matches("Layer.Shape Group.*.Color"))
22
+ XCTAssertTrue(keypath.matches("Layer.*.*.Color"))
23
+
24
+ XCTAssertFalse(keypath.matches("Layer.*.Color"))
25
+ XCTAssertFalse(keypath.matches("**.Layer.Shape Group.Stroke 1.Color"))
26
+ XCTAssertFalse(keypath.matches("*.Layer.Shape Group.Stroke 1.Color"))
27
+ XCTAssertFalse(keypath.matches("Layer.Shape Group.Stroke 1.Color.*"))
28
+ XCTAssertFalse(keypath.matches("Layer.Shape Group.Stroke 1.Color.**"))
29
+ }
30
+
31
+ func testLayerForKeypath() {
32
+ let animationView = AnimationView(
33
+ animation: Samples.animation(named: "Boat_Loader"),
34
+ configuration: LottieConfiguration(renderingEngine: .mainThread))
35
+
36
+ XCTAssertNotNil(animationView.animationLayer?.layer(for: "Success.FishComplete.Fish1Tail 7"))
37
+ XCTAssertNotNil(animationView.animationLayer?.layer(for: "Success.FishComplete"))
38
+ XCTAssertNotNil(animationView.animationLayer?.layer(for: "Success"))
39
+ XCTAssertNotNil(animationView.animationLayer?.layer(for: "Success.*.Fish1Tail 7"))
40
+ }
41
+
42
+ func testMainThreadEngineKeypathLogging() {
43
+ snapshotHierarchyKeypaths(
44
+ animationName: "Switch",
45
+ configuration: LottieConfiguration(renderingEngine: .mainThread))
46
+ }
47
+
48
+ func testCoreAnimationEngineKeypathLogging() {
49
+ snapshotHierarchyKeypaths(
50
+ animationName: "Switch",
51
+ configuration: LottieConfiguration(renderingEngine: .coreAnimation))
52
+
53
+ snapshotHierarchyKeypaths(
54
+ animationName: "Issues/issue_1664",
55
+ configuration: LottieConfiguration(renderingEngine: .coreAnimation))
56
+ }
57
+
58
+ /// The Core Animation engine supports a subset of the keypaths supported by the Main Thread engine.
59
+ /// All keypaths that are supported in the Core Animation engine should also be supported by the Main Thread engine.
60
+ func testCoreAnimationEngineKeypathCompatibility() {
61
+ let mainThreadKeypaths = Set(hierarchyKeypaths(animationName: "Switch", configuration: .init(renderingEngine: .mainThread)))
62
+ let coreAnimationKeypaths = hierarchyKeypaths(animationName: "Switch", configuration: .init(renderingEngine: .coreAnimation))
63
+
64
+ for coreAnimationKeypath in coreAnimationKeypaths {
65
+ XCTAssert(
66
+ mainThreadKeypaths.contains(coreAnimationKeypath),
67
+ """
68
+ \(coreAnimationKeypath) from Core Animation rendering engine \
69
+ is not supported in Main Thread rendering engine
70
+ """)
71
+ }
72
+ }
73
+
74
+ // MARK: Private
75
+
76
+ private func snapshotHierarchyKeypaths(
77
+ animationName: String,
78
+ configuration: LottieConfiguration,
79
+ function: String = #function,
80
+ line: UInt = #line)
81
+ {
82
+ let hierarchyKeypaths = hierarchyKeypaths(animationName: animationName, configuration: configuration)
83
+
84
+ assertSnapshot(
85
+ matching: hierarchyKeypaths.sorted().joined(separator: "\n"),
86
+ as: .description,
87
+ named: animationName,
88
+ testName: function,
89
+ line: line)
90
+ }
91
+
92
+ private func hierarchyKeypaths(animationName: String, configuration: LottieConfiguration) -> [String] {
93
+ var printedMessages = [String]()
94
+ let logger = LottieLogger(info: { message in
95
+ printedMessages.append(message())
96
+ })
97
+
98
+ let animationView = SnapshotConfiguration.makeAnimationView(for: animationName, configuration: configuration, logger: logger)
99
+ animationView?.logHierarchyKeypaths()
100
+ return Array(printedMessages[1...])
101
+ }
102
+
103
+ }
@@ -0,0 +1,57 @@
1
+ // Created by Cal Stephens on 5/2/22.
2
+ // Copyright © 2022 Airbnb Inc. All rights reserved.
3
+
4
+ import SnapshotTesting
5
+ import UIKit
6
+ import XCTest
7
+
8
+ @testable import Lottie
9
+
10
+ final class AutomaticEngineTests: XCTestCase {
11
+
12
+ /// Snapshot tests for whether or not each sample animation supports the Core Animation engine
13
+ func testAutomaticEngineDetection() throws {
14
+ for sampleAnimationName in Samples.sampleAnimationNames {
15
+ guard let animation = Samples.animation(named: sampleAnimationName) else { continue }
16
+
17
+ var compatibilityIssues = [CompatibilityIssue]()
18
+
19
+ let animationLayer = try XCTUnwrap(CoreAnimationLayer(
20
+ animation: animation,
21
+ imageProvider: BundleImageProvider(bundle: Bundle.main, searchPath: nil),
22
+ fontProvider: DefaultFontProvider(),
23
+ compatibilityTrackerMode: .track,
24
+ logger: .shared))
25
+
26
+ animationLayer.didSetUpAnimation = { issues in
27
+ compatibilityIssues = issues
28
+ }
29
+
30
+ animationLayer.bounds = CGRect(origin: .zero, size: animation.size)
31
+ animationLayer.layoutIfNeeded()
32
+ animationLayer.display()
33
+
34
+ let compatibilityReport: String
35
+ if compatibilityIssues.isEmpty {
36
+ compatibilityReport = "Supports Core Animation engine"
37
+ } else {
38
+ compatibilityReport = "Does not support Core Animation engine. Encountered compatibility issues:\n"
39
+ + compatibilityIssues.map { $0.description }.joined(separator: "\n")
40
+ }
41
+
42
+ assertSnapshot(
43
+ matching: compatibilityReport,
44
+ as: .description,
45
+ named: sampleAnimationName)
46
+ }
47
+ }
48
+
49
+ override func setUp() {
50
+ LottieLogger.shared = .printToConsole
51
+ }
52
+
53
+ override func tearDown() {
54
+ LottieLogger.shared = LottieLogger()
55
+ }
56
+
57
+ }
@@ -0,0 +1,25 @@
1
+ //
2
+ // BundleTests.swift
3
+ // LottieTests
4
+ //
5
+ // Created by Marcelo Fabri on 5/5/22.
6
+ //
7
+
8
+ import XCTest
9
+
10
+ @testable import Lottie
11
+
12
+ final class BundleTests: XCTestCase {
13
+
14
+ var bundle: Bundle { .module }
15
+
16
+ func testGetAnimationDataWithSuffix() throws {
17
+ let data = try bundle.getAnimationData("HamburgerArrow.json", subdirectory: "Samples")
18
+ XCTAssertNotNil(data)
19
+ }
20
+
21
+ func testGetAnimationDataWithoutSuffix() throws {
22
+ let data = try bundle.getAnimationData("HamburgerArrow", subdirectory: "Samples")
23
+ XCTAssertNotNil(data)
24
+ }
25
+ }
@@ -0,0 +1,64 @@
1
+ // Created by Nicholas Mata on 2/23/22.
2
+ // Copyright © 2022 Airbnb Inc. All rights reserved.
3
+
4
+ import Foundation
5
+ import XCTest
6
+
7
+ @testable import Lottie
8
+
9
+ // MARK: - DataURLTests
10
+
11
+ // Tests are based on implementation found here
12
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
13
+ final class DataURLTests: XCTestCase {
14
+
15
+ let red5x5 =
16
+ "%89%50%4e%47%0d%0a%1a%0a%00%00%00%0d%49%48%44%52%00%00%00%05%00%00%00%05%08%06%00%00%00%8d%6f%26%e5%00%00%00%12%49%44%41%54%78%da%63%fc%cf%c0%00%44%a8%80%91%06%82%00%5c%65%09%fc%86%fe%00%b0%00%00%00%00%49%45%4e%44%ae%42%60%82"
17
+
18
+ let red5x5Base64 = "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAEklEQVR42mP8z8AARKiAkQaCAFxlCfyG/gCwAAAAAElFTkSuQmCC"
19
+
20
+ func testValidDataURL() {
21
+ let dataString = "data:image/png;base64,\(red5x5Base64)"
22
+
23
+ let data = Data(dataString: dataString)
24
+ XCTAssertNotNil(data, "Data should not be nil if valid base64 string")
25
+ let image = UIImage(data: data!)
26
+ XCTAssertNotNil(image, "Should be valid image")
27
+
28
+ // Since legacy options will print nil host logs
29
+ let legacyData = Data(dataString: dataString, options: .legacy)
30
+ XCTAssertNotNil(legacyData, "Data should not be nil if valid base64 string")
31
+ let legacyImage = UIImage(data: legacyData!)
32
+ XCTAssertNotNil(legacyImage, "Should be valid image")
33
+
34
+ XCTAssertEqual(data, legacyData)
35
+ }
36
+
37
+ func testValidDataURLWithoutBase64() {
38
+ let dataString = "data:image/png,\(red5x5)"
39
+ // Since ;base64 is missing still prints nil host warnings.
40
+ // If we can figure out how to turn red5x5 into Data properly
41
+ // like Data(contentsOf:) does then we can avoid the warning.
42
+ let data = Data(dataString: dataString)
43
+ XCTAssertNotNil(data, "Data should not be nil since format is valid data URL")
44
+
45
+ let image = UIImage(data: data!)
46
+ XCTAssertNotNil(image, "Should be valid image. Since missing ';base64' the data is valid just not base64 encoded")
47
+ }
48
+
49
+ func testInvalidDataURLWithBadBase64() {
50
+ let dataString = "data:image/png;base64,INVALIDBASE64"
51
+
52
+ let data = Data(dataString: dataString)
53
+ let legacyData = Data(dataString: dataString, options: .legacy)
54
+ XCTAssertNil(data, "Data should be nil because 'INVALIDBASE64' is not valid base64 string.")
55
+ XCTAssertNil(legacyData, "Data should be nil because 'INVALIDBASE64' is not valid base64 string.")
56
+ }
57
+
58
+ func testInvalidDataURL() {
59
+ let dataString = "ImageAssetName"
60
+
61
+ let data = Data(dataString: dataString)
62
+ XCTAssertNil(data, "Data should be nil as valid Data URL starts with 'data:'")
63
+ }
64
+ }
@@ -0,0 +1,43 @@
1
+ //
2
+ // ParsingTests.swift
3
+ // Lottie
4
+ //
5
+ // Created by Marcelo Fabri on 5/5/22.
6
+ //
7
+
8
+ import Difference
9
+ import Foundation
10
+ import Lottie
11
+ import XCTest
12
+
13
+ // MARK: - ParsingTests
14
+
15
+ final class ParsingTests: XCTestCase {
16
+
17
+ func testParsingIsTheSameForBothImplementations() throws {
18
+ for url in Samples.sampleAnimationURLs {
19
+ do {
20
+ let data = try Data(contentsOf: url)
21
+ let codableAnimation = try Animation.from(data: data, strategy: .codable)
22
+ let dictAnimation = try Animation.from(data: data, strategy: .dictionaryBased)
23
+
24
+ XCTAssertNoDiff(codableAnimation, dictAnimation)
25
+ } catch {
26
+ XCTFail("Error for \(url.lastPathComponent): \(error)")
27
+ }
28
+ }
29
+ }
30
+ }
31
+
32
+ func XCTAssertNoDiff<T>(
33
+ _ expected: @autoclosure () throws -> T,
34
+ _ received: @autoclosure () throws -> T,
35
+ file: StaticString = #filePath,
36
+ line: UInt = #line) rethrows
37
+ {
38
+ let expected = try expected()
39
+ let received = try received()
40
+ let diff = diff(expected, received)
41
+ let isEqual = diff.isEmpty || diff.allSatisfy(\.isEmpty)
42
+ XCTAssertTrue(isEqual, "Found difference for \n" + diff.joined(separator: ", "), file: file, line: line)
43
+ }
@@ -0,0 +1,214 @@
1
+ // Created by Cal Stephens on 2/14/22.
2
+ // Copyright © 2022 Airbnb Inc. All rights reserved.
3
+
4
+ import Foundation
5
+ import XCTest
6
+
7
+ @testable import Lottie
8
+
9
+ // MARK: - PerformanceTests
10
+
11
+ final class PerformanceTests: XCTestCase {
12
+
13
+ // MARK: Internal
14
+
15
+ func testAnimationViewSetup_simpleAnimation() {
16
+ // Compare the performance of displaying this simple animation in the two animation engines
17
+ let ratio = compareEngineSetupPerformance(
18
+ of: .mainThread,
19
+ with: .coreAnimation,
20
+ for: simpleAnimation,
21
+ iterations: 2000)
22
+
23
+ // This is basically a snapshot test for the performance of the Core Animation engine
24
+ // compared to the Main Thread engine. Currently, the Core Animation engine is
25
+ // about the same speed as the Main Thread engine in this example.
26
+ XCTAssertEqual(ratio, 1.0, accuracy: 0.35)
27
+ }
28
+
29
+ func testAnimationViewSetup_complexAnimation() {
30
+ // Compare the performance of displaying this simple animation in the two animation engines
31
+ let ratio = compareEngineSetupPerformance(
32
+ of: .mainThread,
33
+ with: .coreAnimation,
34
+ for: complexAnimation,
35
+ iterations: 500)
36
+
37
+ // The Core Animation engine is currently about 1.5x slower than the
38
+ // Main Thread engine in this example.
39
+ XCTAssertEqual(ratio, 1.5, accuracy: 0.6)
40
+ }
41
+
42
+ func testAnimationViewSetup_automaticEngine() {
43
+ // Compare the performance of displaying this simple animation with the core animation engine
44
+ // vs with the automatic engine option
45
+ let ratio = compareEngineSetupPerformance(
46
+ of: .coreAnimation,
47
+ with: .automatic,
48
+ for: simpleAnimation,
49
+ iterations: 2000)
50
+
51
+ // The automatic engine option should have the same performance as the core animation engine,
52
+ // when rendering an animation supported by the CA engine.
53
+ XCTAssertEqual(ratio, 1.0, accuracy: 0.5)
54
+ }
55
+
56
+ func testAnimationViewScrubbing_simpleAnimation() {
57
+ let ratio = compareEngineScrubbingPerformance(for: simpleAnimation, iterations: 2000)
58
+ XCTAssertEqual(ratio, 0.01, accuracy: 0.01)
59
+ }
60
+
61
+ func testAnimationViewScrubbing_complexAnimation() {
62
+ let ratio = compareEngineScrubbingPerformance(for: complexAnimation, iterations: 2000)
63
+ XCTAssertEqual(ratio, 0.01, accuracy: 0.01)
64
+ }
65
+
66
+ func testParsing_simpleAnimation() throws {
67
+ let data = try XCTUnwrap(Bundle.module.getAnimationData("loading_dots_1", subdirectory: "Samples/LottieFiles"))
68
+ let ratio = try compareDeserializationPerformance(data: data, iterations: 2000)
69
+ XCTAssertEqual(ratio, 2, accuracy: 0.65)
70
+ }
71
+
72
+ func testParsing_complexAnimation() throws {
73
+ let data = try XCTUnwrap(Bundle.module.getAnimationData("LottieLogo2", subdirectory: "Samples"))
74
+ let ratio = try compareDeserializationPerformance(data: data, iterations: 500)
75
+ XCTAssertEqual(ratio, 1.7, accuracy: 0.6)
76
+ }
77
+
78
+ override func setUp() {
79
+ TestHelpers.performanceTestsAreRunning = true
80
+ }
81
+
82
+ override func tearDown() {
83
+ TestHelpers.performanceTestsAreRunning = false
84
+ }
85
+
86
+ // MARK: Private
87
+
88
+ private let simpleAnimation = Animation.named(
89
+ "loading_dots_1",
90
+ bundle: .module,
91
+ subdirectory: "Samples/LottieFiles")!
92
+
93
+ private let complexAnimation = Animation.named(
94
+ "LottieLogo2",
95
+ bundle: .module,
96
+ subdirectory: "Samples")!
97
+
98
+ /// Compares initializing the given animation with the two given engines,
99
+ /// and returns the ratio of how much slower engine B is than engine A.
100
+ private func compareEngineSetupPerformance(
101
+ of engineA: RenderingEngineOption,
102
+ with engineB: RenderingEngineOption,
103
+ for animation: Animation,
104
+ iterations: Int)
105
+ -> Double
106
+ {
107
+ let engineAPerformance = measurePerformance {
108
+ for _ in 0..<iterations {
109
+ setUpAndTearDownAnimationView(with: animation, configuration: .init(renderingEngine: engineA))
110
+ }
111
+ }
112
+
113
+ LottieLogger.shared.info("\(engineA) engine took \(engineAPerformance) seconds")
114
+
115
+ let engineBPerformance = measurePerformance {
116
+ for _ in 0..<iterations {
117
+ setUpAndTearDownAnimationView(with: animation, configuration: .init(renderingEngine: engineB))
118
+ }
119
+ }
120
+
121
+ LottieLogger.shared.info("\(engineB) engine took \(engineBPerformance) seconds")
122
+
123
+ let ratio = engineBPerformance / engineAPerformance
124
+ LottieLogger.shared.info("\(engineB) engine took \(ratio)x as long as \(engineA) engine")
125
+ return ratio
126
+ }
127
+
128
+ private func setUpAndTearDownAnimationView(with animation: Animation, configuration: LottieConfiguration) {
129
+ // Each animation setup needs to be wrapped in its own `CATransaction`
130
+ // in order for the layers to be deallocated immediately. Otherwise
131
+ // the layers aren't deallocated until the end of the test run,
132
+ // which causes memory usage to grow unbounded.
133
+ CATransaction.begin()
134
+ let animationView = setupAnimationView(with: animation, configuration: configuration)
135
+ // Call `display()` on the layer to make sure any pending setup occurs immediately
136
+ animationView.animationLayer!.display()
137
+ CATransaction.commit()
138
+
139
+ /// The view / layer is deallocated when the transaction is flushed
140
+ CATransaction.flush()
141
+ }
142
+
143
+ /// Compares performance of scrubbing the given animation with both the Main Thread and Core Animation engine,
144
+ /// and returns the ratio of how much slower the Core Animation is than the Main Thread engine
145
+ private func compareEngineScrubbingPerformance(for animation: Animation, iterations: Int) -> Double {
146
+ let mainThreadAnimationView = setupAnimationView(with: animation, configuration: .init(renderingEngine: .mainThread))
147
+ let mainThreadEnginePerformance = measurePerformance {
148
+ for i in 0..<iterations {
149
+ mainThreadAnimationView.currentProgress = Double(i) / Double(iterations)
150
+
151
+ // Since the main thread engine only re-renders in `display()`, which is normally called by Core Animation,
152
+ // we have to invoke it manually. This triggers the same code path that would happen when scrubbing in
153
+ // a real use case.
154
+ mainThreadAnimationView.animationLayer!.display()
155
+ }
156
+ }
157
+
158
+ LottieLogger.shared.info("Main thread engine took \(mainThreadEnginePerformance) seconds")
159
+
160
+ let coreAnimationView = setupAnimationView(with: animation, configuration: .init(renderingEngine: .coreAnimation))
161
+ let coreAnimationEnginePerformance = measurePerformance {
162
+ for i in 0..<iterations {
163
+ coreAnimationView.currentProgress = Double(i) / Double(iterations)
164
+
165
+ // Call `display()` on the layer to make sure any pending setup occurs immediately
166
+ coreAnimationView.animationLayer!.display()
167
+ }
168
+ }
169
+
170
+ LottieLogger.shared.info("Core Animation engine took \(coreAnimationEnginePerformance) seconds")
171
+
172
+ let ratio = coreAnimationEnginePerformance / mainThreadEnginePerformance
173
+ LottieLogger.shared.info("Core Animation engine took \(ratio)x as long as the Main Thread engine")
174
+ return ratio
175
+ }
176
+
177
+ private func compareDeserializationPerformance(data: Data, iterations: Int) throws -> Double {
178
+ let codablePerformance = try measurePerformance {
179
+ for _ in 0..<iterations {
180
+ _ = try Animation.from(data: data, strategy: .codable)
181
+ }
182
+ }
183
+
184
+ LottieLogger.shared.info("Codable deserialization took \(codablePerformance) seconds")
185
+
186
+ let dictPerformance = try measurePerformance {
187
+ for _ in 0..<iterations {
188
+ _ = try Animation.from(data: data, strategy: .dictionaryBased)
189
+ }
190
+ }
191
+
192
+ LottieLogger.shared.info("DictionaryBased deserialization took \(dictPerformance) seconds")
193
+ let ratio = codablePerformance / dictPerformance
194
+ LottieLogger.shared.info("Codable deserialization took \(ratio)x as long as DictionaryBased")
195
+ return ratio
196
+ }
197
+
198
+ @discardableResult
199
+ private func setupAnimationView(with animation: Animation, configuration: LottieConfiguration) -> AnimationView {
200
+ let animationView = AnimationView(animation: animation, configuration: configuration)
201
+ animationView.frame.size = CGSize(width: animation.width, height: animation.height)
202
+ animationView.layoutIfNeeded()
203
+ return animationView
204
+ }
205
+
206
+ private func measurePerformance(_ block : () throws -> Void) rethrows -> TimeInterval {
207
+ let start = DispatchTime.now()
208
+ try block()
209
+ let end = DispatchTime.now()
210
+ let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds
211
+ return Double(nanoTime) / 1_000_000_000
212
+ }
213
+
214
+ }