1 //
2 //  LayerDebugging.swift
3 //  lottie-swift
4 //
5 //  Created by Brandon Withrow on 1/24/19.
6 //
7 
8 import Foundation
9 import QuartzCore
10 
11 struct LayerDebugStyle {
12   let anchorColor: CGColor
13   let boundsColor: CGColor
14   let anchorWidth: CGFloat
15   let boundsWidth: CGFloat
16 }
17 
18 protocol LayerDebugging {
19   var debugStyle: LayerDebugStyle { get }
20 }
21 
22 protocol CustomLayerDebugging {
layerForDebuggingnull23   func layerForDebugging() -> CALayer
24 }
25 
26 class DebugLayer: CALayer {
27   init(style: LayerDebugStyle) {
28     super.init()
29     zPosition = 1000
30     bounds = CGRect(x: 0, y: 0, width: style.anchorWidth, height: style.anchorWidth)
31     backgroundColor = style.anchorColor
32   }
33 
34   required init?(coder aDecoder: NSCoder) {
35     fatalError("init(coder:) has not been implemented")
36   }
37 }
38 
39 public extension CALayer {
40 
logLayerTreenull41   func logLayerTree(withIndent: Int = 0) {
42     var string = ""
43     for _ in 0...withIndent {
44       string = string + "  "
45     }
46     string = string + "|_" + String(describing: self)
47     print(string)
48     if let sublayers = sublayers {
49       for sublayer in sublayers {
50         sublayer.logLayerTree(withIndent: withIndent + 1)
51       }
52     }
53   }
54 
55 }
56 
57 extension CompositionLayer: CustomLayerDebugging {
layerForDebuggingnull58   func layerForDebugging() -> CALayer {
59     return contentsLayer
60   }
61 }
62 
63 extension CALayer {
64 
setDebuggingStatenull65   func setDebuggingState(visible: Bool) {
66 
67     var sublayers = self.sublayers
68     if let cust = self as? CustomLayerDebugging {
69       sublayers = cust.layerForDebugging().sublayers
70     }
71 
72     if let sublayers = sublayers {
73       for i in 0..<sublayers.count {
74         if let debugLayer = sublayers[i] as? DebugLayer {
75           debugLayer.removeFromSuperlayer()
76           break
77         }
78       }
79     }
80 
81     if let sublayers = sublayers {
82       sublayers.forEach({ $0.setDebuggingState(visible: visible) })
83     }
84 
85     if visible {
86       let style: LayerDebugStyle
87       if let layerDebugging = self as? LayerDebugging {
88         style = layerDebugging.debugStyle
89       } else {
90         style = LayerDebugStyle.defaultStyle()
91       }
92       let debugLayer = DebugLayer(style: style)
93       var container = self
94       if let cust = self as? CustomLayerDebugging {
95         container = cust.layerForDebugging()
96       }
97       container.addSublayer(debugLayer)
98       debugLayer.position = .zero
99       borderWidth = style.boundsWidth
100       borderColor = style.boundsColor
101     } else {
102       borderWidth = 0
103       borderColor = nil
104     }
105   }
106 }
107 
108 extension AnimationContainer: LayerDebugging {
109   var debugStyle: LayerDebugStyle {
110     return LayerDebugStyle.topLayerStyle()
111   }
112 }
113 
114 extension NullCompositionLayer: LayerDebugging {
115   var debugStyle: LayerDebugStyle {
116     return LayerDebugStyle.nullLayerStyle()
117   }
118 }
119 
120 extension ShapeCompositionLayer: LayerDebugging {
121   var debugStyle: LayerDebugStyle {
122     return LayerDebugStyle.shapeLayerStyle()
123   }
124 }
125 
126 extension ShapeRenderLayer: LayerDebugging {
127   var debugStyle: LayerDebugStyle {
128     return LayerDebugStyle.shapeRenderLayerStyle()
129   }
130 }
131 
132 extension LayerDebugStyle {
defaultStylenull133   static func defaultStyle() -> LayerDebugStyle {
134     let colorSpace = CGColorSpaceCreateDeviceRGB()
135 
136     let anchorColor = CGColor(colorSpace: colorSpace, components: [1, 0, 0, 1])!
137     let boundsColor = CGColor(colorSpace: colorSpace, components: [1, 1, 0, 1])!
138     return LayerDebugStyle(anchorColor: anchorColor,
139                            boundsColor: boundsColor,
140                            anchorWidth: 10,
141                            boundsWidth: 2)
142   }
143 
topLayerStylenull144   static func topLayerStyle() -> LayerDebugStyle {
145     let colorSpace = CGColorSpaceCreateDeviceRGB()
146     let anchorColor = CGColor(colorSpace: colorSpace, components: [1, 0.5, 0, 0])!
147     let boundsColor = CGColor(colorSpace: colorSpace, components: [0, 1, 0, 1])!
148 
149     return LayerDebugStyle(anchorColor: anchorColor,
150                            boundsColor: boundsColor,
151                            anchorWidth: 10,
152                            boundsWidth: 2)
153   }
154 
nullLayerStylenull155   static func nullLayerStyle() -> LayerDebugStyle {
156     let colorSpace = CGColorSpaceCreateDeviceRGB()
157     let anchorColor = CGColor(colorSpace: colorSpace, components: [0, 0, 1, 0])!
158     let boundsColor = CGColor(colorSpace: colorSpace, components: [0, 1, 0, 1])!
159 
160     return LayerDebugStyle(anchorColor: anchorColor,
161                            boundsColor: boundsColor,
162                            anchorWidth: 10,
163                            boundsWidth: 2)
164   }
165 
shapeLayerStylenull166   static func shapeLayerStyle() -> LayerDebugStyle {
167     let colorSpace = CGColorSpaceCreateDeviceRGB()
168     let anchorColor = CGColor(colorSpace: colorSpace, components: [0, 1, 0, 0])!
169     let boundsColor = CGColor(colorSpace: colorSpace, components: [0, 1, 0, 1])!
170 
171     return LayerDebugStyle(anchorColor: anchorColor,
172                            boundsColor: boundsColor,
173                            anchorWidth: 10,
174                            boundsWidth: 2)
175   }
176 
shapeRenderLayerStylenull177   static func shapeRenderLayerStyle() -> LayerDebugStyle {
178     let colorSpace = CGColorSpaceCreateDeviceRGB()
179     let anchorColor = CGColor(colorSpace: colorSpace, components: [0, 1, 1, 0])!
180     let boundsColor = CGColor(colorSpace: colorSpace, components: [0, 1, 0, 1])!
181 
182     return LayerDebugStyle(anchorColor: anchorColor,
183                            boundsColor: boundsColor,
184                            anchorWidth: 10,
185                            boundsWidth: 2)
186   }
187 }
188 
189 extension Array where Element == LayerModel {
190 
191   var parents: [Int] {
192     var array = [Int]()
193     for layer in self {
194       if let parent = layer.parent {
195         array.append(parent)
196       } else {
197         array.append(-1)
198       }
199     }
200     return array
201   }
202 
203 }
204