lottie-ios 3.4.2 → 3.4.3

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 (137) hide show
  1. package/Lottie.xcodeproj/project.pbxproj +4 -0
  2. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  3. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +16 -0
  4. package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +17 -5
  5. package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +5 -4
  6. package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +25 -12
  7. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +3 -0
  8. package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +1 -0
  9. package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +2 -2
  10. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +3 -3
  11. package/Sources/Private/CoreAnimation/Layers/TextLayer.swift +15 -1
  12. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +1 -1
  13. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +12 -1
  14. package/Sources/Public/Animation/AnimationPublic.swift +2 -1
  15. package/Sources/Public/Animation/AnimationView.swift +2 -0
  16. package/Tests/AutomaticEngineTests.swift +1 -0
  17. package/Tests/SnapshotConfiguration.swift +15 -1
  18. package/Tests/SnapshotTests.swift +4 -0
  19. package/Tests/Utils/HardcodedTextProvider.swift +27 -0
  20. package/lottie-ios.podspec +1 -1
  21. package/package.json +1 -1
  22. package/Tests/Samples/9squares_AlBoardman.json +0 -1
  23. package/Tests/Samples/Boat_Loader.json +0 -1
  24. package/Tests/Samples/HamburgerArrow.json +0 -1
  25. package/Tests/Samples/IconTransitions.json +0 -1
  26. package/Tests/Samples/Images/dog.png +0 -0
  27. package/Tests/Samples/Issues/issue_1125.json +0 -1
  28. package/Tests/Samples/Issues/issue_1260.json +0 -1
  29. package/Tests/Samples/Issues/issue_1403.json +0 -1
  30. package/Tests/Samples/Issues/issue_1407.json +0 -1
  31. package/Tests/Samples/Issues/issue_1460.json +0 -1
  32. package/Tests/Samples/Issues/issue_1488.json +0 -1
  33. package/Tests/Samples/Issues/issue_1505.json +0 -1
  34. package/Tests/Samples/Issues/issue_1541.json +0 -1
  35. package/Tests/Samples/Issues/issue_1557.json +0 -1
  36. package/Tests/Samples/Issues/issue_1603.json +0 -1
  37. package/Tests/Samples/Issues/issue_1628.json +0 -1
  38. package/Tests/Samples/Issues/issue_1636.json +0 -1
  39. package/Tests/Samples/Issues/issue_1643.json +0 -1
  40. package/Tests/Samples/Issues/issue_1655.json +0 -1
  41. package/Tests/Samples/Issues/issue_1664.json +0 -1
  42. package/Tests/Samples/Issues/issue_1683.json +0 -1
  43. package/Tests/Samples/Issues/issue_1687.json +0 -1
  44. package/Tests/Samples/Issues/issue_1711.json +0 -1
  45. package/Tests/Samples/Issues/issue_1717.json +0 -1
  46. package/Tests/Samples/Issues/issue_769.json +0 -1
  47. package/Tests/Samples/Issues/issue_885.json +0 -1
  48. package/Tests/Samples/Issues/issue_965.json +0 -1
  49. package/Tests/Samples/Issues/pr_1536.json +0 -1
  50. package/Tests/Samples/Issues/pr_1563.json +0 -8439
  51. package/Tests/Samples/Issues/pr_1592.json +0 -5527
  52. package/Tests/Samples/Issues/pr_1599.json +0 -738
  53. package/Tests/Samples/Issues/pr_1604_1.json +0 -1
  54. package/Tests/Samples/Issues/pr_1604_2.json +0 -1
  55. package/Tests/Samples/Issues/pr_1632_1.json +0 -1
  56. package/Tests/Samples/Issues/pr_1632_2.json +0 -1
  57. package/Tests/Samples/Issues/pr_1686.json +0 -513
  58. package/Tests/Samples/Issues/pr_1698.json +0 -1
  59. package/Tests/Samples/Issues/pr_1699.json +0 -1
  60. package/Tests/Samples/LottieFiles/LICENSE.md +0 -14
  61. package/Tests/Samples/LottieFiles/bounce_strokes.json +0 -1
  62. package/Tests/Samples/LottieFiles/cactus.json +0 -1
  63. package/Tests/Samples/LottieFiles/dog_car_ride.json +0 -1
  64. package/Tests/Samples/LottieFiles/draft_icon.json +0 -1
  65. package/Tests/Samples/LottieFiles/fireworks.json +0 -1
  66. package/Tests/Samples/LottieFiles/gradient_1.json +0 -1
  67. package/Tests/Samples/LottieFiles/gradient_2.json +0 -1
  68. package/Tests/Samples/LottieFiles/gradient_pill.json +0 -1
  69. package/Tests/Samples/LottieFiles/gradient_shapes.json +0 -1
  70. package/Tests/Samples/LottieFiles/gradient_square.json +0 -1
  71. package/Tests/Samples/LottieFiles/growth.json +0 -1
  72. package/Tests/Samples/LottieFiles/infinity_loader.json +0 -1
  73. package/Tests/Samples/LottieFiles/loading_dots_1.json +0 -1
  74. package/Tests/Samples/LottieFiles/loading_dots_2.json +0 -1
  75. package/Tests/Samples/LottieFiles/loading_dots_3.json +0 -1
  76. package/Tests/Samples/LottieFiles/loading_gradient_strokes.json +0 -1
  77. package/Tests/Samples/LottieFiles/settings_slider.json +0 -1
  78. package/Tests/Samples/LottieFiles/shop.json +0 -1
  79. package/Tests/Samples/LottieFiles/step_loader.json +0 -1
  80. package/Tests/Samples/LottieLogo1.json +0 -1
  81. package/Tests/Samples/LottieLogo1_masked.json +0 -1
  82. package/Tests/Samples/LottieLogo2.json +0 -1
  83. package/Tests/Samples/MotionCorpse_Jrcanest.json +0 -1
  84. package/Tests/Samples/Nonanimating/BasicLayers.json +0 -1
  85. package/Tests/Samples/Nonanimating/DisableNodesTest.json +0 -1
  86. package/Tests/Samples/Nonanimating/FirstText.json +0 -1
  87. package/Tests/Samples/Nonanimating/GeometryTransformTest.json +0 -1
  88. package/Tests/Samples/Nonanimating/Text_AnimatedProperties.json +0 -1
  89. package/Tests/Samples/Nonanimating/Text_Glyph.json +0 -1
  90. package/Tests/Samples/Nonanimating/Text_NoAnimation.json +0 -1
  91. package/Tests/Samples/Nonanimating/Text_NoGlyph.json +0 -1
  92. package/Tests/Samples/Nonanimating/Zoom.json +0 -1
  93. package/Tests/Samples/Nonanimating/_dog.json +0 -1
  94. package/Tests/Samples/Nonanimating/base64Test.json +0 -1
  95. package/Tests/Samples/Nonanimating/blend_mode_test.json +0 -1
  96. package/Tests/Samples/Nonanimating/keypathTest.json +0 -1
  97. package/Tests/Samples/Nonanimating/verifyLineHeight.json +0 -1
  98. package/Tests/Samples/PinJump.json +0 -1
  99. package/Tests/Samples/Switch.json +0 -1
  100. package/Tests/Samples/Switch_States.json +0 -1
  101. package/Tests/Samples/TwitterHeart.json +0 -1
  102. package/Tests/Samples/TwitterHeartButton.json +0 -1
  103. package/Tests/Samples/TypeFace/A.json +0 -1
  104. package/Tests/Samples/TypeFace/Apostrophe.json +0 -1
  105. package/Tests/Samples/TypeFace/B.json +0 -1
  106. package/Tests/Samples/TypeFace/BlinkingCursor.json +0 -1
  107. package/Tests/Samples/TypeFace/C.json +0 -1
  108. package/Tests/Samples/TypeFace/Colon.json +0 -1
  109. package/Tests/Samples/TypeFace/Comma.json +0 -1
  110. package/Tests/Samples/TypeFace/D.json +0 -1
  111. package/Tests/Samples/TypeFace/E.json +0 -1
  112. package/Tests/Samples/TypeFace/F.json +0 -1
  113. package/Tests/Samples/TypeFace/G.json +0 -1
  114. package/Tests/Samples/TypeFace/H.json +0 -1
  115. package/Tests/Samples/TypeFace/I.json +0 -1
  116. package/Tests/Samples/TypeFace/J.json +0 -1
  117. package/Tests/Samples/TypeFace/K.json +0 -1
  118. package/Tests/Samples/TypeFace/L.json +0 -1
  119. package/Tests/Samples/TypeFace/M.json +0 -1
  120. package/Tests/Samples/TypeFace/N.json +0 -1
  121. package/Tests/Samples/TypeFace/O.json +0 -1
  122. package/Tests/Samples/TypeFace/P.json +0 -1
  123. package/Tests/Samples/TypeFace/Q.json +0 -1
  124. package/Tests/Samples/TypeFace/R.json +0 -1
  125. package/Tests/Samples/TypeFace/S.json +0 -1
  126. package/Tests/Samples/TypeFace/T.json +0 -1
  127. package/Tests/Samples/TypeFace/U.json +0 -1
  128. package/Tests/Samples/TypeFace/V.json +0 -1
  129. package/Tests/Samples/TypeFace/W.json +0 -1
  130. package/Tests/Samples/TypeFace/X.json +0 -1
  131. package/Tests/Samples/TypeFace/Y.json +0 -1
  132. package/Tests/Samples/TypeFace/Z.json +0 -1
  133. package/Tests/Samples/Watermelon.json +0 -1
  134. package/Tests/Samples/setValueTest.json +0 -1
  135. package/Tests/Samples/timeremap.json +0 -1
  136. package/Tests/Samples/vcTransition1.json +0 -1
  137. package/Tests/Samples/vcTransition2.json +0 -1
@@ -554,6 +554,7 @@
554
554
  2EAF5B0427A0798700E00531 /* AnimationFontProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EAF59F227A0798700E00531 /* AnimationFontProvider.swift */; };
555
555
  2EAF5B0527A0798700E00531 /* AnimationFontProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EAF59F227A0798700E00531 /* AnimationFontProvider.swift */; };
556
556
  2EAF5B0627A0798700E00531 /* AnimationFontProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EAF59F227A0798700E00531 /* AnimationFontProvider.swift */; };
557
+ 36E57EAC28AF7ADF00B7EFDA /* HardcodedTextProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36E57EAB28AF7ADF00B7EFDA /* HardcodedTextProvider.swift */; };
557
558
  6D0E635F28246BD0007C5DB6 /* Difference in Frameworks */ = {isa = PBXBuildFile; productRef = 6D0E635E28246BD0007C5DB6 /* Difference */; };
558
559
  6D99D6432823790700E5205B /* LegacyGradientFillRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D99D6422823790700E5205B /* LegacyGradientFillRenderer.swift */; };
559
560
  6D99D6442823790700E5205B /* LegacyGradientFillRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D99D6422823790700E5205B /* LegacyGradientFillRenderer.swift */; };
@@ -783,6 +784,7 @@
783
784
  2EAF59EF27A0798700E00531 /* GradientValueProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientValueProvider.swift; sourceTree = "<group>"; };
784
785
  2EAF59F027A0798700E00531 /* PointValueProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PointValueProvider.swift; sourceTree = "<group>"; };
785
786
  2EAF59F227A0798700E00531 /* AnimationFontProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationFontProvider.swift; sourceTree = "<group>"; };
787
+ 36E57EAB28AF7ADF00B7EFDA /* HardcodedTextProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HardcodedTextProvider.swift; sourceTree = "<group>"; };
786
788
  6D99D6422823790700E5205B /* LegacyGradientFillRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyGradientFillRenderer.swift; sourceTree = "<group>"; };
787
789
  6DB3BDB528243FA5002A276D /* ValueProvidersTests.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = ValueProvidersTests.swift; sourceTree = "<group>"; tabWidth = 2; };
788
790
  6DB3BDB7282454A6002A276D /* DictionaryInitializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryInitializable.swift; sourceTree = "<group>"; };
@@ -876,6 +878,7 @@
876
878
  2E8040BF27A07343006E74CB /* Snapshotting+presentationLayer.swift */,
877
879
  2EAF59A627A076BC00E00531 /* Bundle+Module.swift */,
878
880
  2E09FA0527B6CEB600BA84E5 /* HardcodedFontProvider.swift */,
881
+ 36E57EAB28AF7ADF00B7EFDA /* HardcodedTextProvider.swift */,
879
882
  );
880
883
  path = Utils;
881
884
  sourceTree = "<group>";
@@ -1876,6 +1879,7 @@
1876
1879
  6DEF696E2824A76C007D640F /* BundleTests.swift in Sources */,
1877
1880
  2EAF59A727A076BC00E00531 /* Bundle+Module.swift in Sources */,
1878
1881
  2E8044AE27A07347006E74CB /* Snapshotting+presentationLayer.swift in Sources */,
1882
+ 36E57EAC28AF7ADF00B7EFDA /* HardcodedTextProvider.swift in Sources */,
1879
1883
  2E72128527BB32DB0027BC56 /* PerformanceTests.swift in Sources */,
1880
1884
  6DB3BDC328245AA2002A276D /* ParsingTests.swift in Sources */,
1881
1885
  6DB3BDB628243FA5002A276D /* ValueProvidersTests.swift in Sources */,
@@ -18,5 +18,21 @@
18
18
  endingLineNumber = "44">
19
19
  </BreakpointContent>
20
20
  </BreakpointProxy>
21
+ <BreakpointProxy
22
+ BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
23
+ <BreakpointContent
24
+ uuid = "90B95B81-4B28-4BCD-AE7B-59ED8AA81AC1"
25
+ shouldBeEnabled = "No"
26
+ ignoreCount = "0"
27
+ continueAfterRunningActions = "No"
28
+ filePath = "Sources/Private/MainThread/NodeRenderSystem/NodeProperties/NodeProperty.swift"
29
+ startingColumnNumber = "9223372036854775807"
30
+ endingColumnNumber = "9223372036854775807"
31
+ startingLineNumber = "49"
32
+ endingLineNumber = "49"
33
+ landmarkName = "update(frame:)"
34
+ landmarkType = "7">
35
+ </BreakpointContent>
36
+ </BreakpointProxy>
21
37
  </Breakpoints>
22
38
  </Bucket>
@@ -36,11 +36,23 @@ extension GradientRenderLayer {
36
36
  type: GradientContentType,
37
37
  context: LayerAnimationContext) throws
38
38
  {
39
- // We have to set `colors` to a non-nil value with some valid number of colors
40
- // for the color animation below to have any effect
41
- colors = .init(
42
- repeating: CGColor.rgb(0, 0, 0),
43
- count: gradient.numberOfColors)
39
+ // We have to set `colors` and `locations` to non-nil values
40
+ // for the animations below to actually take effect
41
+ locations = []
42
+
43
+ // The initial value for `colors` must be an array with the exact same number of colors
44
+ // as the gradient that will be applied in the `CAAnimation`
45
+ switch type {
46
+ case .rgb:
47
+ colors = .init(
48
+ repeating: CGColor.rgb(0, 0, 0),
49
+ count: gradient.numberOfColors)
50
+
51
+ case .alpha:
52
+ colors = .init(
53
+ repeating: CGColor.rgb(0, 0, 0),
54
+ count: gradient.colorConfiguration(from: gradient.colors.keyframes[0].value, type: .alpha).count)
55
+ }
44
56
 
45
57
  try addAnimation(
46
58
  for: .colors,
@@ -55,12 +55,13 @@ extension CAShapeLayer {
55
55
  try addOpacityAnimation(for: stroke, context: context)
56
56
 
57
57
  if let (dashPattern, dashPhase) = stroke.dashPattern?.shapeLayerConfiguration {
58
- lineDashPattern = try dashPattern.map {
58
+ let lineDashPattern = try dashPattern.map {
59
59
  try KeyframeGroup(keyframes: $0)
60
- .exactlyOneKeyframe(context: context, description: "stroke dashPattern").cgFloatValue as NSNumber
60
+ .exactlyOneKeyframe(context: context, description: "stroke dashPattern").cgFloatValue
61
61
  }
62
- if lineDashPattern?.allSatisfy({ $0.floatValue.isZero }) == true {
63
- lineDashPattern = nil
62
+
63
+ if lineDashPattern.isSupportedLayerDashPattern {
64
+ self.lineDashPattern = lineDashPattern as [NSNumber]
64
65
  }
65
66
 
66
67
  try addAnimation(
@@ -17,6 +17,7 @@ final class CoreAnimationLayer: BaseAnimationLayer {
17
17
  init(
18
18
  animation: Animation,
19
19
  imageProvider: AnimationImageProvider,
20
+ textProvider: AnimationTextProvider,
20
21
  fontProvider: AnimationFontProvider,
21
22
  compatibilityTrackerMode: CompatibilityTracker.Mode,
22
23
  logger: LottieLogger)
@@ -24,6 +25,7 @@ final class CoreAnimationLayer: BaseAnimationLayer {
24
25
  {
25
26
  self.animation = animation
26
27
  self.imageProvider = imageProvider
28
+ self.textProvider = textProvider
27
29
  self.fontProvider = fontProvider
28
30
  self.logger = logger
29
31
  compatibilityTracker = CompatibilityTracker(mode: compatibilityTrackerMode, logger: logger)
@@ -44,6 +46,7 @@ final class CoreAnimationLayer: BaseAnimationLayer {
44
46
  animation = typedLayer.animation
45
47
  currentAnimationConfiguration = typedLayer.currentAnimationConfiguration
46
48
  imageProvider = typedLayer.imageProvider
49
+ textProvider = typedLayer.textProvider
47
50
  fontProvider = typedLayer.fontProvider
48
51
  didSetUpAnimation = typedLayer.didSetUpAnimation
49
52
  compatibilityTracker = typedLayer.compatibilityTracker
@@ -92,6 +95,16 @@ final class CoreAnimationLayer: BaseAnimationLayer {
92
95
  didSet { reloadImages() }
93
96
  }
94
97
 
98
+ /// The `AnimationTextProvider` that `TextLayer`'s use to retrieve texts,
99
+ /// that they should use to render their text context
100
+ var textProvider: AnimationTextProvider {
101
+ didSet {
102
+ // We need to rebuild the current animation after updating the text provider,
103
+ // since this is used in `TextLayer.setupAnimations(context:)`
104
+ rebuildCurrentAnimation()
105
+ }
106
+ }
107
+
95
108
  /// The `FontProvider` that `TextLayer`s use to retrieve the `CTFont`
96
109
  /// that they should use to render their text content
97
110
  var fontProvider: AnimationFontProvider {
@@ -203,6 +216,7 @@ final class CoreAnimationLayer: BaseAnimationLayer {
203
216
  LayerContext(
204
217
  animation: animation,
205
218
  imageProvider: imageProvider,
219
+ textProvider: textProvider,
206
220
  fontProvider: fontProvider,
207
221
  compatibilityTracker: compatibilityTracker,
208
222
  layerName: "root layer")
@@ -234,6 +248,7 @@ final class CoreAnimationLayer: BaseAnimationLayer {
234
248
  compatibilityTracker: compatibilityTracker,
235
249
  logger: logger,
236
250
  currentKeypath: AnimationKeypath(keys: []),
251
+ textProvider: textProvider,
237
252
  logHierarchyKeypaths: configuration.logHierarchyKeypaths)
238
253
 
239
254
  // Perform a layout pass if necessary so all of the sublayers
@@ -314,11 +329,18 @@ extension CoreAnimationLayer: RootAnimationLayer {
314
329
  }
315
330
 
316
331
  var isAnimationPlaying: Bool? {
317
- switch playbackState {
332
+ switch pendingAnimationConfiguration?.playbackState {
318
333
  case .playing:
319
- return animation(forKey: #keyPath(animationProgress)) != nil
320
- case nil, .paused:
334
+ return true
335
+ case .paused:
321
336
  return false
337
+ case nil:
338
+ switch playbackState {
339
+ case .playing:
340
+ return animation(forKey: #keyPath(animationProgress)) != nil
341
+ case nil, .paused:
342
+ return false
343
+ }
322
344
  }
323
345
  }
324
346
 
@@ -383,15 +405,6 @@ extension CoreAnimationLayer: RootAnimationLayer {
383
405
  (sublayers ?? []).filter { $0 is AnimationLayer }
384
406
  }
385
407
 
386
- var textProvider: AnimationTextProvider {
387
- get { DictionaryTextProvider([:]) }
388
- set {
389
- logger.assertionFailure("""
390
- The Core Animation rendering engine currently doesn't support `textProvider`s")
391
- """)
392
- }
393
- }
394
-
395
408
  func reloadImages() {
396
409
  // When the image provider changes, we have to update all `ImageLayer`s
397
410
  // so they can query the most up-to-date image from the new image provider.
@@ -41,6 +41,9 @@ struct LayerAnimationContext {
41
41
  /// The AnimationKeypath represented by the current layer
42
42
  var currentKeypath: AnimationKeypath
43
43
 
44
+ /// The `AnimationTextProvider`
45
+ var textProvider: AnimationTextProvider
46
+
44
47
  /// Whether or not to log `AnimationKeypath`s for all of the animation's layers
45
48
  /// - Used for `CoreAnimationLayer.logHierarchyKeypaths()`
46
49
  var logHierarchyKeypaths: Bool
@@ -9,6 +9,7 @@ import QuartzCore
9
9
  struct LayerContext {
10
10
  let animation: Animation
11
11
  let imageProvider: AnimationImageProvider
12
+ let textProvider: AnimationTextProvider
12
13
  let fontProvider: AnimationFontProvider
13
14
  let compatibilityTracker: CompatibilityTracker
14
15
  var layerName: String
@@ -68,12 +68,12 @@ final class PreCompLayer: BaseCompositionLayer {
68
68
  try setupLayerAnimations(context: context)
69
69
 
70
70
  // Precomp layers can adjust the local time of their child layers (relative to the
71
- // animation's global time) via `timeRemapping` or a custom `startTime`
71
+ // animation's global time) via `timeRemapping` or a custom `startTime` / `timeStretch`
72
72
  let contextForChildren = context.withTimeRemapping { [preCompLayer, timeRemappingInterpolator] layerLocalFrame in
73
73
  if let timeRemappingInterpolator = timeRemappingInterpolator {
74
74
  return timeRemappingInterpolator.value(frame: layerLocalFrame) as? AnimationFrameTime ?? layerLocalFrame
75
75
  } else {
76
- return layerLocalFrame + AnimationFrameTime(preCompLayer.startTime)
76
+ return (layerLocalFrame * AnimationFrameTime(preCompLayer.timeStretch)) + AnimationFrameTime(preCompLayer.startTime)
77
77
  }
78
78
  }
79
79
 
@@ -253,9 +253,9 @@ extension CALayer {
253
253
  pathForChildren.append(group.name)
254
254
  }
255
255
 
256
- let childItems = group.items.map {
257
- ShapeItemLayer.Item(item: $0, groupPath: pathForChildren)
258
- }
256
+ let childItems = group.items
257
+ .filter { !$0.hidden }
258
+ .map { ShapeItemLayer.Item(item: $0, groupPath: pathForChildren) }
259
259
 
260
260
  return try GroupLayer(
261
261
  group: group,
@@ -36,6 +36,21 @@ final class TextLayer: BaseCompositionLayer {
36
36
 
37
37
  // MARK: Internal
38
38
 
39
+ override func setupAnimations(context: LayerAnimationContext) throws {
40
+ try super.setupAnimations(context: context)
41
+ let textAnimationContext = context.addingKeypathComponent(textLayerModel.name)
42
+
43
+ let sourceText = try textLayerModel.text.exactlyOneKeyframe(
44
+ context: textAnimationContext,
45
+ description: "text layer text")
46
+
47
+ renderLayer.text = context.textProvider.textFor(
48
+ keypathName: textAnimationContext.currentKeypath.fullPath,
49
+ sourceText: sourceText.text)
50
+
51
+ renderLayer.sizeToFit()
52
+ }
53
+
39
54
  func configureRenderLayer(with context: LayerContext) throws {
40
55
  // We can't use `CATextLayer`, because it doesn't support enough features we use.
41
56
  // Instead, we use the same `CoreTextRenderLayer` (with a custom `draw` implementation)
@@ -54,7 +69,6 @@ final class TextLayer: BaseCompositionLayer {
54
69
  """)
55
70
  }
56
71
 
57
- renderLayer.text = text.text
58
72
  renderLayer.font = context.fontProvider.fontFor(family: text.fontFamily, size: CGFloat(text.fontSize))
59
73
 
60
74
  renderLayer.alignment = text.justification.textAlignment
@@ -140,7 +140,7 @@ final class GradientStrokeNode: AnimatorNode, RenderNode {
140
140
 
141
141
  /// Get dash lengths
142
142
  let dashLengths = strokeProperties.dashPattern.value.map { $0.cgFloatValue }
143
- if dashLengths.count > 0, !dashLengths.allSatisfy({ $0.isZero }) {
143
+ if dashLengths.count > 0, dashLengths.isSupportedLayerDashPattern {
144
144
  strokeRender.strokeRender.dashPhase = strokeProperties.dashPhase.value.cgFloatValue
145
145
  strokeRender.strokeRender.dashLengths = dashLengths
146
146
  } else {
@@ -118,7 +118,7 @@ final class StrokeNode: AnimatorNode, RenderNode {
118
118
 
119
119
  /// Get dash lengths
120
120
  let dashLengths = strokeProperties.dashPattern.value.map { $0.cgFloatValue }
121
- if dashLengths.count > 0, !dashLengths.allSatisfy({ $0.isZero }) {
121
+ if dashLengths.count > 0, dashLengths.isSupportedLayerDashPattern {
122
122
  strokeRender.dashPhase = strokeProperties.dashPhase.value.cgFloatValue
123
123
  strokeRender.dashLengths = dashLengths
124
124
  } else {
@@ -167,3 +167,14 @@ extension Array where Element == DashElement {
167
167
  return (dashPatterns, dashPhase)
168
168
  }
169
169
  }
170
+
171
+ extension Array where Element == CGFloat {
172
+ // If all of the items in the dash pattern are zeros, then we shouldn't attempt to render it.
173
+ // This causes Core Animation to have extremely poor performance for some reason, even though
174
+ // it doesn't affect the appearance of the animation.
175
+ // - We check for `== 0.01` instead of `== 0` because `dashPattern.shapeLayerConfiguration`
176
+ // converts all `0` values to `0.01` to work around a different Core Animation rendering issue.
177
+ var isSupportedLayerDashPattern: Bool {
178
+ !allSatisfy { $0 == 0.01 }
179
+ }
180
+ }
@@ -172,13 +172,14 @@ extension Animation {
172
172
  ///
173
173
  public static func loadedFrom(
174
174
  url: URL,
175
+ session: URLSession = .shared,
175
176
  closure: @escaping Animation.DownloadClosure,
176
177
  animationCache: AnimationCacheProvider?)
177
178
  {
178
179
  if let animationCache = animationCache, let animation = animationCache.animation(forKey: url.absoluteString) {
179
180
  closure(animation)
180
181
  } else {
181
- let task = URLSession.shared.dataTask(with: url) { data, _, error in
182
+ let task = session.dataTask(with: url) { data, _, error in
182
183
  guard error == nil, let jsonData = data else {
183
184
  DispatchQueue.main.async {
184
185
  closure(nil)
@@ -996,6 +996,7 @@ final public class AnimationView: AnimationViewBase {
996
996
  let coreAnimationLayer = try CoreAnimationLayer(
997
997
  animation: animation,
998
998
  imageProvider: imageProvider.cachedImageProvider,
999
+ textProvider: textProvider,
999
1000
  fontProvider: fontProvider,
1000
1001
  compatibilityTrackerMode: .track,
1001
1002
  logger: logger)
@@ -1030,6 +1031,7 @@ final public class AnimationView: AnimationViewBase {
1030
1031
  let coreAnimationLayer = try CoreAnimationLayer(
1031
1032
  animation: animation,
1032
1033
  imageProvider: imageProvider.cachedImageProvider,
1034
+ textProvider: textProvider,
1033
1035
  fontProvider: fontProvider,
1034
1036
  compatibilityTrackerMode: .abort,
1035
1037
  logger: logger)
@@ -19,6 +19,7 @@ final class AutomaticEngineTests: XCTestCase {
19
19
  let animationLayer = try XCTUnwrap(CoreAnimationLayer(
20
20
  animation: animation,
21
21
  imageProvider: BundleImageProvider(bundle: Bundle.main, searchPath: nil),
22
+ textProvider: DefaultTextProvider(),
22
23
  fontProvider: DefaultFontProvider(),
23
24
  compatibilityTrackerMode: .track,
24
25
  logger: .shared))
@@ -22,6 +22,9 @@ struct SnapshotConfiguration {
22
22
  /// A custom `AnimationImageProvider` to use when rendering this animation
23
23
  var customImageProvider: AnimationImageProvider?
24
24
 
25
+ /// A custom `AnimationTextProvider` to use when rendering this animation
26
+ var customTextProvider: AnimationTextProvider?
27
+
25
28
  /// A custom `AnimationFontProvider` to use when rendering this animation
26
29
  var customFontProvider: AnimationFontProvider?
27
30
 
@@ -44,7 +47,6 @@ extension SnapshotConfiguration {
44
47
  "Nonanimating/FirstText": .precision(0.99),
45
48
  "Nonanimating/verifyLineHeight": .precision(0.99),
46
49
  "Nonanimating/blend_mode_test": .precision(0.99),
47
- "Issues/issue_885": .precision(0.99),
48
50
 
49
51
  /// Test cases for the `AnimationKeypath` / `AnyValueProvider` system
50
52
  "Nonanimating/keypathTest": .customValueProviders([
@@ -70,6 +72,9 @@ extension SnapshotConfiguration {
70
72
  // Test cases for `AnimatedImageProvider`
71
73
  "Nonanimating/_dog": .customImageProvider(HardcodedImageProvider(imageName: "Samples/Images/dog.png")),
72
74
 
75
+ // Test cases for `AnimatedTextProvider`
76
+ "Issues/issue_1722": .customTextProvider(HardcodedTextProvider(text: "Bounce-bounce")),
77
+
73
78
  // Test cases for `AnimationFontProvider`
74
79
  "Nonanimating/Text_Glyph": .customFontProvider(HardcodedFontProvider(font: UIFont(name: "Chalkduster", size: 36)!)),
75
80
 
@@ -128,6 +133,15 @@ extension SnapshotConfiguration {
128
133
  return configuration
129
134
  }
130
135
 
136
+ static func customTextProvider(
137
+ _ customTextProvider: AnimationTextProvider)
138
+ -> SnapshotConfiguration
139
+ {
140
+ var configuration = SnapshotConfiguration.default
141
+ configuration.customTextProvider = customTextProvider
142
+ return configuration
143
+ }
144
+
131
145
  /// A `SnapshotConfiguration` value using the given custom value providers
132
146
  static func customFontProvider(
133
147
  _ customFontProvider: AnimationFontProvider)
@@ -256,6 +256,10 @@ extension SnapshotConfiguration {
256
256
  animationView.imageProvider = customImageProvider
257
257
  }
258
258
 
259
+ if let customTextProvider = snapshotConfiguration.customTextProvider {
260
+ animationView.textProvider = customTextProvider
261
+ }
262
+
259
263
  if let customFontProvider = snapshotConfiguration.customFontProvider {
260
264
  animationView.fontProvider = customFontProvider
261
265
  }
@@ -0,0 +1,27 @@
1
+ // Created by Igor Katselenbogen on 08/19/22.
2
+ // Copyright © 2022 Airbnb Inc. All rights reserved.
3
+
4
+ import Lottie
5
+
6
+ // MARK: - HardcodedTextProvider
7
+
8
+ /// An `AnimationTextProvider` that always returns a specific hardcoded text
9
+ class HardcodedTextProvider: AnimationTextProvider {
10
+
11
+ // MARK: Lifecycle
12
+
13
+ init(text: String) {
14
+ self.text = text
15
+ }
16
+
17
+ // MARK: Internal
18
+
19
+ func textFor(keypathName _: String, sourceText _: String) -> String {
20
+ text
21
+ }
22
+
23
+ // MARK: Private
24
+
25
+ private let text: String
26
+
27
+ }
@@ -8,7 +8,7 @@
8
8
 
9
9
  Pod::Spec.new do |s|
10
10
  s.name = 'lottie-ios'
11
- s.version = '3.4.2'
11
+ s.version = '3.4.3'
12
12
  s.summary = 'A library to render native animations from bodymovin json'
13
13
 
14
14
  s.description = <<-DESC
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lottie-ios",
3
- "version": "3.4.2",
3
+ "version": "3.4.3",
4
4
  "description": "Lottie is a mobile library for Android and iOS that parses Adobe After Effects animations exported as json with bodymovin and renders the vector animations natively on mobile and through React Native!",
5
5
  "main": "index.js",
6
6
  "scripts": {