lottie-ios 4.4.2 → 4.5.0

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 (82) hide show
  1. package/.github/workflows/main.yml +12 -39
  2. package/Lottie.xcodeproj/project.pbxproj +28 -0
  3. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  4. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +19 -6
  5. package/Package.resolved +2 -2
  6. package/Package.swift +1 -1
  7. package/README.md +2 -2
  8. package/Rakefile +1 -1
  9. package/Sources/PrivacyInfo.xcprivacy +1 -1
  10. package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +2 -2
  11. package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +6 -6
  12. package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +24 -9
  13. package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +2 -2
  14. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +7 -7
  15. package/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift +12 -12
  16. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +19 -19
  17. package/Sources/Private/CoreAnimation/ValueProviderStore.swift +4 -4
  18. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift +13 -6
  19. package/Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift +3 -3
  20. package/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+BackingConfiguration.swift +10 -6
  21. package/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Helpers.swift +4 -0
  22. package/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Progress.swift +2 -2
  23. package/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Reading.swift +5 -0
  24. package/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Writing.swift +2 -0
  25. package/Sources/Private/EmbeddedLibraries/ZipFoundation/Data+Compression.swift +1 -0
  26. package/Sources/Private/EmbeddedLibraries/ZipFoundation/Entry+ZIP64.swift +2 -2
  27. package/Sources/Private/EmbeddedLibraries/ZipFoundation/Entry.swift +1 -0
  28. package/Sources/Private/EmbeddedLibraries/ZipFoundation/FileManager+ZIP.swift +10 -9
  29. package/Sources/Private/MainThread/LayerContainers/CompLayers/CompositionLayer.swift +19 -0
  30. package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +7 -7
  31. package/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift +3 -0
  32. package/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift +24 -14
  33. package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +11 -10
  34. package/Sources/Private/MainThread/LayerContainers/Utility/CompositionLayersInitializer.swift +2 -0
  35. package/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift +102 -17
  36. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +11 -11
  37. package/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift +2 -0
  38. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/LayerEffectNodes/DropShadowNode.swift +102 -0
  39. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/LayerEffectNodes/LayerEffectNode.swift +24 -0
  40. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/FillRenderer.swift +4 -4
  41. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift +16 -16
  42. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +4 -4
  43. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +5 -5
  44. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +60 -1
  45. package/Sources/Private/Model/DotLottie/DotLottieAnimation.swift +2 -2
  46. package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +9 -6
  47. package/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift +4 -4
  48. package/Sources/Private/Model/LayerEffects/LayerEffect.swift +2 -2
  49. package/Sources/Private/Model/LayerStyles/LayerStyle.swift +2 -2
  50. package/Sources/Private/Model/Layers/LayerModel.swift +7 -7
  51. package/Sources/Private/Model/ShapeItems/ShapeItem.swift +15 -15
  52. package/Sources/Private/Model/Text/TextAnimator.swift +47 -1
  53. package/Sources/Private/Utility/Debugging/LayerDebugging.swift +6 -6
  54. package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +16 -16
  55. package/Sources/Private/Utility/Extensions/BlendMode+Filter.swift +16 -16
  56. package/Sources/Private/Utility/Extensions/CGColor+RGB.swift +18 -0
  57. package/Sources/Private/Utility/Extensions/CGFloatExtensions.swift +23 -23
  58. package/Sources/Private/Utility/Extensions/MathKit.swift +4 -11
  59. package/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift +9 -3
  60. package/Sources/Private/Utility/LottieAnimationSource.swift +4 -4
  61. package/Sources/Private/Utility/Primitives/BezierPath.swift +16 -2
  62. package/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift +2 -2
  63. package/Sources/Private/Utility/Primitives/ColorExtension.swift +20 -20
  64. package/Sources/Private/Utility/Primitives/CompoundBezierPath.swift +9 -9
  65. package/Sources/Public/Animation/LottieAnimationLayer.swift +36 -31
  66. package/Sources/Public/Animation/LottieAnimationView.swift +15 -15
  67. package/Sources/Public/Animation/LottieAnimationViewInitializers.swift +4 -0
  68. package/Sources/Public/Animation/LottiePlaybackMode.swift +12 -12
  69. package/Sources/Public/Animation/LottieView.swift +53 -5
  70. package/Sources/Public/Configuration/ReducedMotionOption.swift +5 -5
  71. package/Sources/Public/Configuration/RenderingEngineOption.swift +4 -4
  72. package/Sources/Public/Controls/AnimatedSwitch.swift +2 -2
  73. package/Sources/Public/DotLottie/DotLottieFile.swift +2 -2
  74. package/Sources/Public/DynamicProperties/AnyValueProvider.swift +9 -9
  75. package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +2 -2
  76. package/Sources/Public/Keyframes/Interpolatable.swift +2 -2
  77. package/Sources/Public/Primitives/LottieColor.swift +3 -3
  78. package/Sources/Public/TextProvider/AnimationTextProvider.swift +4 -4
  79. package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +13 -12
  80. package/Version.xcconfig +2 -2
  81. package/lottie-ios.podspec +2 -2
  82. package/package.json +1 -1
@@ -124,12 +124,12 @@ extension KeypathSearchable {
124
124
  func allKeypaths(for keyPath: AnimationKeypath? = nil) -> [String] {
125
125
  var allKeypaths: [String] = []
126
126
 
127
- let newKeypath: AnimationKeypath
128
- if let previousKeypath = keyPath {
129
- newKeypath = previousKeypath.appendingKey(keypathName)
130
- } else {
131
- newKeypath = AnimationKeypath(keys: [keypathName])
132
- }
127
+ let newKeypath: AnimationKeypath =
128
+ if let previousKeypath = keyPath {
129
+ previousKeypath.appendingKey(keypathName)
130
+ } else {
131
+ AnimationKeypath(keys: [keypathName])
132
+ }
133
133
 
134
134
  allKeypaths.append(newKeypath.fullPath)
135
135
 
@@ -148,12 +148,12 @@ extension KeypathSearchable {
148
148
  func layerKeypaths(for keyPath: AnimationKeypath? = nil) -> [CALayer: AnimationKeypath] {
149
149
  var allKeypaths: [CALayer: AnimationKeypath] = [:]
150
150
 
151
- let newKeypath: AnimationKeypath
152
- if let previousKeypath = keyPath {
153
- newKeypath = previousKeypath.appendingKey(keypathName)
154
- } else {
155
- newKeypath = AnimationKeypath(keys: [keypathName])
156
- }
151
+ let newKeypath: AnimationKeypath =
152
+ if let previousKeypath = keyPath {
153
+ previousKeypath.appendingKey(keypathName)
154
+ } else {
155
+ AnimationKeypath(keys: [keypathName])
156
+ }
157
157
 
158
158
  if let layer = self as? CALayer {
159
159
  allKeypaths[layer] = newKeypath
@@ -197,7 +197,7 @@ extension AnimationKeypath {
197
197
  keys.joined(separator: ".")
198
198
  }
199
199
 
200
- // Pops the top keypath from the stack if the keyname matches.
200
+ /// Pops the top keypath from the stack if the keyname matches.
201
201
  func popKey(_ keyname: String) -> AnimationKeypath? {
202
202
  guard
203
203
  let currentKey,
@@ -245,11 +245,11 @@ extension String {
245
245
  var keyPathType: KeyType {
246
246
  switch self {
247
247
  case "*":
248
- return .wildcard
248
+ .wildcard
249
249
  case "**":
250
- return .fuzzyWildcard
250
+ .fuzzyWildcard
251
251
  default:
252
- return .specific
252
+ .specific
253
253
  }
254
254
  }
255
255
 
@@ -10,22 +10,22 @@ extension BlendMode {
10
10
  /// Supported compositing filters are defined here: https://developer.apple.com/library/archive/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html#//apple_ref/doc/uid/TP30000136-SW71
11
11
  var filterName: String? {
12
12
  switch self {
13
- case .normal: return nil
14
- case .multiply: return "multiplyBlendMode"
15
- case .screen: return "screenBlendMode"
16
- case .overlay: return "overlayBlendMode"
17
- case .darken: return "darkenBlendMode"
18
- case .lighten: return "lightenBlendMode"
19
- case .colorDodge: return "colorDodgeBlendMode"
20
- case .colorBurn: return "colorBurnBlendMode"
21
- case .hardLight: return "hardLightBlendMode"
22
- case .softLight: return "softLightBlendMode"
23
- case .difference: return "differenceBlendMode"
24
- case .exclusion: return "exclusionBlendMode"
25
- case .hue: return "hueBlendMode"
26
- case .saturation: return "saturationBlendMode"
27
- case .color: return "colorBlendMode"
28
- case .luminosity: return "luminosityBlendMode"
13
+ case .normal: nil
14
+ case .multiply: "multiplyBlendMode"
15
+ case .screen: "screenBlendMode"
16
+ case .overlay: "overlayBlendMode"
17
+ case .darken: "darkenBlendMode"
18
+ case .lighten: "lightenBlendMode"
19
+ case .colorDodge: "colorDodgeBlendMode"
20
+ case .colorBurn: "colorBurnBlendMode"
21
+ case .hardLight: "hardLightBlendMode"
22
+ case .softLight: "softLightBlendMode"
23
+ case .difference: "differenceBlendMode"
24
+ case .exclusion: "exclusionBlendMode"
25
+ case .hue: "hueBlendMode"
26
+ case .saturation: "saturationBlendMode"
27
+ case .color: "colorBlendMode"
28
+ case .luminosity: "luminosityBlendMode"
29
29
  }
30
30
  }
31
31
  }
@@ -4,6 +4,23 @@
4
4
  import QuartzCore
5
5
 
6
6
  extension CGColor {
7
+ /// Retrieves the red, green, and blue color values from this `CGColor`
8
+ var rgb: (red: CGFloat, green: CGFloat, blue: CGFloat)? {
9
+ guard let components else { return nil }
10
+
11
+ switch numberOfComponents {
12
+ case 2:
13
+ return (red: components[0], green: components[0], blue: components[0])
14
+
15
+ case 3, 4:
16
+ return (red: components[0], green: components[1], blue: components[2])
17
+
18
+ default:
19
+ // Unsupported conversion
20
+ return nil
21
+ }
22
+ }
23
+
7
24
  /// Initializes a `CGColor` using the given `RGB` values
8
25
  static func rgb(_ red: CGFloat, _ green: CGFloat, _ blue: CGFloat) -> CGColor {
9
26
  rgba(red, green, blue, 1.0)
@@ -22,4 +39,5 @@ extension CGColor {
22
39
  colorSpace: LottieConfiguration.shared.colorSpace,
23
40
  components: [red, green, blue, alpha])!
24
41
  }
42
+
25
43
  }
@@ -41,19 +41,19 @@ extension CGFloat {
41
41
  t = 1
42
42
  } else {
43
43
  // Calculate t
44
- let a = -P0.x + 3 * P1.x - 3 * P2.x + P3.x;
45
- let b = 3 * P0.x - 6 * P1.x + 3 * P2.x;
46
- let c = -3 * P0.x + 3 * P1.x;
47
- let d = P0.x - self;
48
- let tTemp = CGFloat.SolveCubic(a, b, c, d);
44
+ let a = -P0.x + 3 * P1.x - 3 * P2.x + P3.x
45
+ let b = 3 * P0.x - 6 * P1.x + 3 * P2.x
46
+ let c = -3 * P0.x + 3 * P1.x
47
+ let d = P0.x - self
48
+ let tTemp = CGFloat.SolveCubic(a, b, c, d)
49
49
  if tTemp == -1 {
50
- return -1;
50
+ return -1
51
51
  }
52
52
  t = tTemp
53
53
  }
54
54
 
55
55
  // Calculate y from t
56
- return (1 - t).cubed * P0.y + 3 * t * (1 - t).squared * P1.y + 3 * t.squared * (1 - t) * P2.y + t.cubed * P3.y;
56
+ return (1 - t).cubed * P0.y + 3 * t * (1 - t).squared * P1.y + 3 * t.squared * (1 - t) * P2.y + t.cubed * P3.y
57
57
  }
58
58
 
59
59
  func cubicBezier(_ t: CGFloat, _ c1: CGFloat, _ c2: CGFloat, _ end: CGFloat) -> CGFloat {
@@ -66,23 +66,23 @@ extension CGFloat {
66
66
  return self * ttt_
67
67
  + 3.0 * c1 * tt_ * t
68
68
  + 3.0 * c2 * t_ * tt
69
- + end * ttt;
69
+ + end * ttt
70
70
  }
71
71
 
72
72
  // MARK: Fileprivate
73
73
 
74
74
  fileprivate static func SolveQuadratic(_ a: CGFloat, _ b: CGFloat, _ c: CGFloat) -> CGFloat {
75
- var result = (-b + sqrt(b.squared - 4 * a * c)) / (2 * a);
75
+ var result = (-b + sqrt(b.squared - 4 * a * c)) / (2 * a)
76
76
  guard !result.isInRangeOrEqual(0, 1) else {
77
77
  return result
78
78
  }
79
79
 
80
- result = (-b - sqrt(b.squared - 4 * a * c)) / (2 * a);
80
+ result = (-b - sqrt(b.squared - 4 * a * c)) / (2 * a)
81
81
  guard !result.isInRangeOrEqual(0, 1) else {
82
82
  return result
83
83
  }
84
84
 
85
- return -1;
85
+ return -1
86
86
  }
87
87
 
88
88
  fileprivate static func SolveCubic(_ a: CGFloat, _ b: CGFloat, _ c: CGFloat, _ d: CGFloat) -> CGFloat {
@@ -110,43 +110,43 @@ extension CGFloat {
110
110
  var t = r - sqrt(disc)
111
111
  t = (t < 0) ? -((-t).cubicRoot) : t.cubicRoot
112
112
 
113
- let result = -term1 + s + t;
113
+ let result = -term1 + s + t
114
114
  if result.isInRangeOrEqual(0, 1) {
115
115
  return result
116
116
  }
117
117
  } else if disc == 0 {
118
- let r13 = (r < 0) ? -((-r).cubicRoot) : r.cubicRoot;
118
+ let r13 = (r < 0) ? -((-r).cubicRoot) : r.cubicRoot
119
119
 
120
- var result = -term1 + 2.0 * r13;
120
+ var result = -term1 + 2.0 * r13
121
121
  if result.isInRangeOrEqual(0, 1) {
122
122
  return result
123
123
  }
124
124
 
125
- result = -(r13 + term1);
125
+ result = -(r13 + term1)
126
126
  if result.isInRangeOrEqual(0, 1) {
127
127
  return result
128
128
  }
129
129
 
130
130
  } else {
131
- q = -q;
132
- var dum1 = q * q * q;
133
- dum1 = acos(r / sqrt(dum1));
134
- let r13 = 2.0 * sqrt(q);
131
+ q = -q
132
+ var dum1 = q * q * q
133
+ dum1 = acos(r / sqrt(dum1))
134
+ let r13 = 2.0 * sqrt(q)
135
135
 
136
- var result = -term1 + r13 * cos(dum1 / 3.0);
136
+ var result = -term1 + r13 * cos(dum1 / 3.0)
137
137
  if result.isInRangeOrEqual(0, 1) {
138
138
  return result
139
139
  }
140
- result = -term1 + r13 * cos((dum1 + 2.0 * .pi) / 3.0);
140
+ result = -term1 + r13 * cos((dum1 + 2.0 * .pi) / 3.0)
141
141
  if result.isInRangeOrEqual(0, 1) {
142
142
  return result
143
143
  }
144
- result = -term1 + r13 * cos((dum1 + 4.0 * .pi) / 3.0);
144
+ result = -term1 + r13 * cos((dum1 + 4.0 * .pi) / 3.0)
145
145
  if result.isInRangeOrEqual(0, 1) {
146
146
  return result
147
147
  }
148
148
  }
149
149
 
150
- return -1;
150
+ return -1
151
151
  }
152
152
  }
@@ -33,13 +33,6 @@ extension CGFloat {
33
33
  return toLow + (self - fromLow) * (toHigh - toLow) / (fromHigh - fromLow)
34
34
  }
35
35
 
36
- /// Returns a value that is clamped between the two numbers
37
- ///
38
- /// 1. The order of arguments does not matter.
39
- func clamp(_ a: CGFloat, _ b: CGFloat) -> CGFloat {
40
- CGFloat(Double(self).clamp(Double(a), Double(b)))
41
- }
42
-
43
36
  /// Returns the difference between the receiver and the given number.
44
37
  /// - Parameter absolute: If *true* (Default) the returned value will always be positive.
45
38
  func diff(_ a: CGFloat, absolute: Bool = true) -> CGFloat {
@@ -54,20 +47,20 @@ extension CGFloat {
54
47
  // MARK: - Double
55
48
 
56
49
  extension Double {
57
-
58
50
  func remap(fromLow: Double, fromHigh: Double, toLow: Double, toHigh: Double) -> Double {
59
51
  toLow + (self - fromLow) * (toHigh - toLow) / (fromHigh - fromLow)
60
52
  }
53
+ }
61
54
 
55
+ extension Numeric where Self: Comparable {
62
56
  /// Returns a value that is clamped between the two numbers
63
57
  ///
64
58
  /// 1. The order of arguments does not matter.
65
- func clamp(_ a: Double, _ b: Double) -> Double {
59
+ func clamp(_ a: Self, _ b: Self) -> Self {
66
60
  let minValue = a <= b ? a : b
67
61
  let maxValue = a <= b ? b : a
68
62
  return max(min(self, maxValue), minValue)
69
63
  }
70
-
71
64
  }
72
65
 
73
66
  extension CGRect {
@@ -426,7 +419,7 @@ extension CGPoint {
426
419
  }
427
420
 
428
421
  func colinear(_ a: CGPoint, _ b: CGPoint) -> Bool {
429
- let area = x * (a.y - b.y) + a.x * (b.y - y) + b.x * (y - a.y);
422
+ let area = x * (a.y - b.y) + a.x * (b.y - y) + b.x * (y - a.y)
430
423
  let accuracy: CGFloat = 0.05
431
424
  if area < accuracy, area > -accuracy {
432
425
  return true
@@ -16,7 +16,7 @@ extension LottieColor {
16
16
  init(h: Double, s: Double, v: Double, a: Double) {
17
17
  let i = floor(h * 6)
18
18
  let f = h * 6 - i
19
- let p = v * (1 - s);
19
+ let p = v * (1 - s)
20
20
  let q = v * (1 - f * s)
21
21
  let t = v * (1 - (1 - f) * s)
22
22
 
@@ -25,26 +25,32 @@ extension LottieColor {
25
25
  r = v
26
26
  g = t
27
27
  b = p
28
+
28
29
  case 1:
29
30
  r = q
30
31
  g = v
31
32
  b = p
33
+
32
34
  case 2:
33
35
  r = p
34
36
  g = v
35
37
  b = t
38
+
36
39
  case 3:
37
40
  r = p
38
41
  g = q
39
42
  b = v
43
+
40
44
  case 4:
41
45
  r = t
42
46
  g = p
43
47
  b = v
48
+
44
49
  case 5:
45
50
  r = v
46
51
  g = p
47
52
  b = q
53
+
48
54
  default:
49
55
  r = 0
50
56
  g = 0
@@ -71,10 +77,10 @@ extension LottieColor {
71
77
  var h: Double, s: Double, v: Double = maxValue
72
78
 
73
79
  let d = maxValue - minValue
74
- s = maxValue == 0 ? 0 : d / maxValue;
80
+ s = maxValue == 0 ? 0 : d / maxValue
75
81
 
76
82
  if maxValue == minValue {
77
- h = 0; // achromatic
83
+ h = 0 // achromatic
78
84
  } else {
79
85
  switch maxValue {
80
86
  case r: h = (g - b) / d + (g < b ? 6 : 0)
@@ -19,9 +19,9 @@ extension LottieAnimationSource {
19
19
  var animation: LottieAnimation? {
20
20
  switch self {
21
21
  case .lottieAnimation(let animation):
22
- return animation
22
+ animation
23
23
  case .dotLottieFile:
24
- return dotLottieAnimation?.animation
24
+ dotLottieAnimation?.animation
25
25
  }
26
26
  }
27
27
 
@@ -29,9 +29,9 @@ extension LottieAnimationSource {
29
29
  var dotLottieAnimation: DotLottieFile.Animation? {
30
30
  switch self {
31
31
  case .lottieAnimation:
32
- return nil
32
+ nil
33
33
  case .dotLottieFile(let dotLottieFile):
34
- return dotLottieFile.animation()
34
+ dotLottieFile.animation()
35
35
  }
36
36
  }
37
37
  }
@@ -343,7 +343,14 @@ extension BezierPath: Codable {
343
343
  totalLength = totalLength + pathElement.length
344
344
  }
345
345
  if closed {
346
- let closeElement = previousElement.pathElementTo(firstVertex)
346
+ // Don't use an out tangent for the closing point, since the
347
+ // closing point is exactly equal to the starting point.
348
+ let closeVertex = CurveVertex(
349
+ point: firstVertex.point,
350
+ inTangentRelative: firstVertex.inTangentRelative,
351
+ outTangentRelative: .zero)
352
+
353
+ let closeElement = previousElement.pathElementTo(closeVertex)
347
354
  decodedElements.append(closeElement)
348
355
  totalLength = totalLength + closeElement.length
349
356
  }
@@ -448,7 +455,14 @@ extension BezierPath: AnyInitializable {
448
455
  totalLength = totalLength + pathElement.length
449
456
  }
450
457
  if closed {
451
- let closeElement = previousElement.pathElementTo(firstVertex)
458
+ // Don't use an out tangent for the closing point, since the
459
+ // closing point is exactly equal to the starting point.
460
+ let closeVertex = CurveVertex(
461
+ point: firstVertex.point,
462
+ inTangentRelative: firstVertex.inTangentRelative,
463
+ outTangentRelative: .zero)
464
+
465
+ let closeElement = previousElement.pathElementTo(closeVertex)
452
466
  decodedElements.append(closeElement)
453
467
  totalLength = totalLength + closeElement.length
454
468
  }
@@ -30,7 +30,7 @@ import Foundation
30
30
  // shape's vertex distances and the roundedness set in the animation.
31
31
 
32
32
  extension CompoundBezierPath {
33
- // Round corners of a compound bezier
33
+ /// Round corners of a compound bezier
34
34
  func roundCorners(radius: CGFloat) -> CompoundBezierPath {
35
35
  var newPaths = [BezierPath]()
36
36
  for path in paths {
@@ -43,7 +43,7 @@ extension CompoundBezierPath {
43
43
  }
44
44
 
45
45
  extension BezierPath {
46
- // Computes a new `BezierPath` with each corner rounded based on the given `radius`
46
+ /// Computes a new `BezierPath` with each corner rounded based on the given `radius`
47
47
  func roundCorners(radius: CGFloat) -> BezierPath {
48
48
  var newPath = BezierPath()
49
49
  var uniquePath = BezierPath()
@@ -16,26 +16,26 @@ extension LottieColor: Codable {
16
16
  public init(from decoder: Decoder) throws {
17
17
  var container = try decoder.unkeyedContainer()
18
18
 
19
- var r1: Double
20
- if !container.isAtEnd {
21
- r1 = try container.decode(Double.self)
22
- } else {
23
- r1 = 0
24
- }
25
-
26
- var g1: Double
27
- if !container.isAtEnd {
28
- g1 = try container.decode(Double.self)
29
- } else {
30
- g1 = 0
31
- }
32
-
33
- var b1: Double
34
- if !container.isAtEnd {
35
- b1 = try container.decode(Double.self)
36
- } else {
37
- b1 = 0
38
- }
19
+ var r1: Double =
20
+ if !container.isAtEnd {
21
+ try container.decode(Double.self)
22
+ } else {
23
+ 0
24
+ }
25
+
26
+ var g1: Double =
27
+ if !container.isAtEnd {
28
+ try container.decode(Double.self)
29
+ } else {
30
+ 0
31
+ }
32
+
33
+ var b1: Double =
34
+ if !container.isAtEnd {
35
+ try container.decode(Double.self)
36
+ } else {
37
+ 0
38
+ }
39
39
 
40
40
  if r1 > 1, g1 > 1, b1 > 1 {
41
41
  r1 = r1 / 255
@@ -101,15 +101,15 @@ struct CompoundBezierPath {
101
101
  return self
102
102
  }
103
103
 
104
- var positions: [(start: CGFloat, end: CGFloat)]
105
- if endPosition < startPosition {
106
- positions = [
107
- (start: 0, end: endPosition * length),
108
- (start: startPosition * length, end: length),
109
- ]
110
- } else {
111
- positions = [(start: startPosition * length, end: endPosition * length)]
112
- }
104
+ var positions: [(start: CGFloat, end: CGFloat)] =
105
+ if endPosition < startPosition {
106
+ [
107
+ (start: 0, end: endPosition * length),
108
+ (start: startPosition * length, end: length),
109
+ ]
110
+ } else {
111
+ [(start: startPosition * length, end: endPosition * length)]
112
+ }
113
113
 
114
114
  var compoundPath = CompoundBezierPath()
115
115
  var trim = positions.remove(at: 0)
@@ -237,12 +237,12 @@ public class LottieAnimationLayer: CALayer {
237
237
  self.loopMode = loopMode
238
238
  }
239
239
 
240
- let fromTime: CGFloat
241
- if let fromName = fromMarker, let from = markers[fromName] {
242
- fromTime = CGFloat(from.frameTime)
243
- } else {
244
- fromTime = currentFrame
245
- }
240
+ let fromTime: CGFloat =
241
+ if let fromName = fromMarker, let from = markers[fromName] {
242
+ CGFloat(from.frameTime)
243
+ } else {
244
+ currentFrame
245
+ }
246
246
 
247
247
  let playTo = playEndMarkerFrame ? CGFloat(to.frameTime) : CGFloat(to.frameTime) - 1
248
248
  let context = AnimationContext(
@@ -339,7 +339,7 @@ public class LottieAnimationLayer: CALayer {
339
339
  // If we don't have any more markers to play, then the marker sequence has completed.
340
340
  completion?(completed)
341
341
  } else {
342
- self.play(markers: followingMarkers, completion: completion)
342
+ play(markers: followingMarkers, completion: completion)
343
343
  }
344
344
  })
345
345
  }
@@ -370,6 +370,7 @@ public class LottieAnimationLayer: CALayer {
370
370
 
371
371
  case .frame(let animationFrameTime):
372
372
  currentFrame = animationFrameTime
373
+
373
374
  case .time(let timeInterval):
374
375
  currentTime = timeInterval
375
376
 
@@ -670,9 +671,9 @@ public class LottieAnimationLayer: CALayer {
670
671
  }
671
672
  get {
672
673
  if let animation {
673
- return animation.progressTime(forFrame: currentFrame)
674
+ animation.progressTime(forFrame: currentFrame)
674
675
  } else {
675
- return 0
676
+ 0
676
677
  }
677
678
  }
678
679
  }
@@ -692,9 +693,9 @@ public class LottieAnimationLayer: CALayer {
692
693
  }
693
694
  get {
694
695
  if let animation {
695
- return animation.time(forFrame: currentFrame)
696
+ animation.time(forFrame: currentFrame)
696
697
  } else {
697
- return 0
698
+ 0
698
699
  }
699
700
  }
700
701
  }
@@ -992,16 +993,20 @@ public class LottieAnimationLayer: CALayer {
992
993
  case .stop:
993
994
  removeCurrentAnimation()
994
995
  updateAnimationFrame(currentContext.playFrom)
996
+
995
997
  case .pause:
996
998
  removeCurrentAnimation()
999
+
997
1000
  case .pauseAndRestore:
998
1001
  currentContext.closure.ignoreDelegate = true
999
1002
  removeCurrentAnimation()
1000
1003
  /// Keep the stale context around for when the app enters the foreground.
1001
1004
  animationContext = currentContext
1005
+
1002
1006
  case .forceFinish:
1003
1007
  removeCurrentAnimation()
1004
1008
  updateAnimationFrame(currentContext.playTo)
1009
+
1005
1010
  case .continuePlaying:
1006
1011
  break
1007
1012
  }
@@ -1117,9 +1122,9 @@ public class LottieAnimationLayer: CALayer {
1117
1122
  fileprivate var activeAnimationName: String {
1118
1123
  switch rootAnimationLayer?.primaryAnimationKey {
1119
1124
  case .specific(let animationKey):
1120
- return animationKey
1125
+ animationKey
1121
1126
  case .managed, nil:
1122
- return _activeAnimationName
1127
+ _activeAnimationName
1123
1128
  }
1124
1129
  }
1125
1130
 
@@ -1148,15 +1153,15 @@ public class LottieAnimationLayer: CALayer {
1148
1153
  guard let animation else {
1149
1154
  return
1150
1155
  }
1151
- let rootAnimationLayer: RootAnimationLayer?
1152
- switch renderingEngine {
1153
- case .automatic:
1154
- rootAnimationLayer = makeAutomaticEngineLayer(for: animation)
1155
- case .specific(.coreAnimation):
1156
- rootAnimationLayer = makeCoreAnimationLayer(for: animation)
1157
- case .specific(.mainThread):
1158
- rootAnimationLayer = makeMainThreadAnimationLayer(for: animation)
1159
- }
1156
+ let rootAnimationLayer: RootAnimationLayer? =
1157
+ switch renderingEngine {
1158
+ case .automatic:
1159
+ makeAutomaticEngineLayer(for: animation)
1160
+ case .specific(.coreAnimation):
1161
+ makeCoreAnimationLayer(for: animation)
1162
+ case .specific(.mainThread):
1163
+ makeMainThreadAnimationLayer(for: animation)
1164
+ }
1160
1165
 
1161
1166
  guard let animationLayer = rootAnimationLayer else {
1162
1167
  return
@@ -1259,8 +1264,8 @@ public class LottieAnimationLayer: CALayer {
1259
1264
  }
1260
1265
  }
1261
1266
 
1262
- // Handles any compatibility issues with the Core Animation engine
1263
- // by falling back to the Main Thread engine
1267
+ /// Handles any compatibility issues with the Core Animation engine
1268
+ /// by falling back to the Main Thread engine
1264
1269
  fileprivate func automaticEngineLayerDidSetUpAnimation(_ compatibilityIssues: [CompatibilityIssue]) {
1265
1270
  // If there weren't any compatibility issues, then there's nothing else to do
1266
1271
  if compatibilityIssues.isEmpty {
@@ -1462,9 +1467,9 @@ public class LottieAnimationLayer: CALayer {
1462
1467
  private var reducedMotionMarker: Marker? {
1463
1468
  switch configuration.reducedMotionOption.currentReducedMotionMode {
1464
1469
  case .standardMotion:
1465
- return nil
1470
+ nil
1466
1471
  case .reducedMotion:
1467
- return animation?.reducedMotionMarker
1472
+ animation?.reducedMotionMarker
1468
1473
  }
1469
1474
  }
1470
1475
 
@@ -1503,15 +1508,15 @@ extension LottieLoopMode {
1503
1508
  var caAnimationConfiguration: (repeatCount: Float, autoreverses: Bool) {
1504
1509
  switch self {
1505
1510
  case .playOnce:
1506
- return (repeatCount: 1, autoreverses: false)
1511
+ (repeatCount: 1, autoreverses: false)
1507
1512
  case .loop:
1508
- return (repeatCount: .greatestFiniteMagnitude, autoreverses: false)
1513
+ (repeatCount: .greatestFiniteMagnitude, autoreverses: false)
1509
1514
  case .autoReverse:
1510
- return (repeatCount: .greatestFiniteMagnitude, autoreverses: true)
1515
+ (repeatCount: .greatestFiniteMagnitude, autoreverses: true)
1511
1516
  case .repeat(let amount):
1512
- return (repeatCount: amount, autoreverses: false)
1517
+ (repeatCount: amount, autoreverses: false)
1513
1518
  case .repeatBackwards(let amount):
1514
- return (repeatCount: amount, autoreverses: true)
1519
+ (repeatCount: amount, autoreverses: true)
1515
1520
  }
1516
1521
  }
1517
1522
  }