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