228 lines
5.5 KiB
Swift
228 lines
5.5 KiB
Swift
//
|
|
// LayerDebugging.swift
|
|
// lottie-swift
|
|
//
|
|
// Created by Brandon Withrow on 1/24/19.
|
|
//
|
|
|
|
import Foundation
|
|
import QuartzCore
|
|
|
|
// MARK: - LayerDebugStyle
|
|
|
|
struct LayerDebugStyle {
|
|
let anchorColor: CGColor
|
|
let boundsColor: CGColor
|
|
let anchorWidth: CGFloat
|
|
let boundsWidth: CGFloat
|
|
}
|
|
|
|
// MARK: - LayerDebugging
|
|
|
|
protocol LayerDebugging {
|
|
var debugStyle: LayerDebugStyle { get }
|
|
}
|
|
|
|
// MARK: - CustomLayerDebugging
|
|
|
|
protocol CustomLayerDebugging {
|
|
func layerForDebugging() -> CALayer
|
|
}
|
|
|
|
// MARK: - DebugLayer
|
|
|
|
class DebugLayer: CALayer {
|
|
init(style: LayerDebugStyle) {
|
|
super.init()
|
|
zPosition = 1000
|
|
bounds = CGRect(x: 0, y: 0, width: style.anchorWidth, height: style.anchorWidth)
|
|
backgroundColor = style.anchorColor
|
|
}
|
|
|
|
required init?(coder _: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
}
|
|
|
|
extension CALayer {
|
|
|
|
@nonobjc
|
|
public func logLayerTree(withIndent: Int = 0) {
|
|
var string = ""
|
|
for _ in 0...withIndent {
|
|
string = string + " "
|
|
}
|
|
string = string + "|_" + String(describing: self)
|
|
LottieLogger.shared.info(string)
|
|
if let sublayers = sublayers {
|
|
for sublayer in sublayers {
|
|
sublayer.logLayerTree(withIndent: withIndent + 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// MARK: - CompositionLayer + CustomLayerDebugging
|
|
|
|
extension CompositionLayer: CustomLayerDebugging {
|
|
func layerForDebugging() -> CALayer {
|
|
contentsLayer
|
|
}
|
|
}
|
|
|
|
extension CALayer {
|
|
|
|
@nonobjc
|
|
func setDebuggingState(visible: Bool) {
|
|
var sublayers = self.sublayers
|
|
if let cust = self as? CustomLayerDebugging {
|
|
sublayers = cust.layerForDebugging().sublayers
|
|
}
|
|
|
|
if let sublayers = sublayers {
|
|
for i in 0..<sublayers.count {
|
|
if let debugLayer = sublayers[i] as? DebugLayer {
|
|
debugLayer.removeFromSuperlayer()
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if let sublayers = sublayers {
|
|
sublayers.forEach({ $0.setDebuggingState(visible: visible) })
|
|
}
|
|
|
|
if visible {
|
|
let style: LayerDebugStyle
|
|
if let layerDebugging = self as? LayerDebugging {
|
|
style = layerDebugging.debugStyle
|
|
} else {
|
|
style = LayerDebugStyle.defaultStyle()
|
|
}
|
|
let debugLayer = DebugLayer(style: style)
|
|
var container = self
|
|
if let cust = self as? CustomLayerDebugging {
|
|
container = cust.layerForDebugging()
|
|
}
|
|
container.addSublayer(debugLayer)
|
|
debugLayer.position = .zero
|
|
borderWidth = style.boundsWidth
|
|
borderColor = style.boundsColor
|
|
} else {
|
|
borderWidth = 0
|
|
borderColor = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - MainThreadAnimationLayer + LayerDebugging
|
|
|
|
extension MainThreadAnimationLayer: LayerDebugging {
|
|
var debugStyle: LayerDebugStyle {
|
|
LayerDebugStyle.topLayerStyle()
|
|
}
|
|
}
|
|
|
|
// MARK: - NullCompositionLayer + LayerDebugging
|
|
|
|
extension NullCompositionLayer: LayerDebugging {
|
|
var debugStyle: LayerDebugStyle {
|
|
LayerDebugStyle.nullLayerStyle()
|
|
}
|
|
}
|
|
|
|
// MARK: - ShapeCompositionLayer + LayerDebugging
|
|
|
|
extension ShapeCompositionLayer: LayerDebugging {
|
|
var debugStyle: LayerDebugStyle {
|
|
LayerDebugStyle.shapeLayerStyle()
|
|
}
|
|
}
|
|
|
|
// MARK: - ShapeRenderLayer + LayerDebugging
|
|
|
|
extension ShapeRenderLayer: LayerDebugging {
|
|
var debugStyle: LayerDebugStyle {
|
|
LayerDebugStyle.shapeRenderLayerStyle()
|
|
}
|
|
}
|
|
|
|
extension LayerDebugStyle {
|
|
static func defaultStyle() -> LayerDebugStyle {
|
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
|
|
|
let anchorColor = CGColor(colorSpace: colorSpace, components: [1, 0, 0, 1])!
|
|
let boundsColor = CGColor(colorSpace: colorSpace, components: [1, 1, 0, 1])!
|
|
return LayerDebugStyle(
|
|
anchorColor: anchorColor,
|
|
boundsColor: boundsColor,
|
|
anchorWidth: 10,
|
|
boundsWidth: 2)
|
|
}
|
|
|
|
static func topLayerStyle() -> LayerDebugStyle {
|
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
|
let anchorColor = CGColor(colorSpace: colorSpace, components: [1, 0.5, 0, 0])!
|
|
let boundsColor = CGColor(colorSpace: colorSpace, components: [0, 1, 0, 1])!
|
|
|
|
return LayerDebugStyle(
|
|
anchorColor: anchorColor,
|
|
boundsColor: boundsColor,
|
|
anchorWidth: 10,
|
|
boundsWidth: 2)
|
|
}
|
|
|
|
static func nullLayerStyle() -> LayerDebugStyle {
|
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
|
let anchorColor = CGColor(colorSpace: colorSpace, components: [0, 0, 1, 0])!
|
|
let boundsColor = CGColor(colorSpace: colorSpace, components: [0, 1, 0, 1])!
|
|
|
|
return LayerDebugStyle(
|
|
anchorColor: anchorColor,
|
|
boundsColor: boundsColor,
|
|
anchorWidth: 10,
|
|
boundsWidth: 2)
|
|
}
|
|
|
|
static func shapeLayerStyle() -> LayerDebugStyle {
|
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
|
let anchorColor = CGColor(colorSpace: colorSpace, components: [0, 1, 0, 0])!
|
|
let boundsColor = CGColor(colorSpace: colorSpace, components: [0, 1, 0, 1])!
|
|
|
|
return LayerDebugStyle(
|
|
anchorColor: anchorColor,
|
|
boundsColor: boundsColor,
|
|
anchorWidth: 10,
|
|
boundsWidth: 2)
|
|
}
|
|
|
|
static func shapeRenderLayerStyle() -> LayerDebugStyle {
|
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
|
let anchorColor = CGColor(colorSpace: colorSpace, components: [0, 1, 1, 0])!
|
|
let boundsColor = CGColor(colorSpace: colorSpace, components: [0, 1, 0, 1])!
|
|
|
|
return LayerDebugStyle(
|
|
anchorColor: anchorColor,
|
|
boundsColor: boundsColor,
|
|
anchorWidth: 10,
|
|
boundsWidth: 2)
|
|
}
|
|
}
|
|
|
|
extension Array where Element == LayerModel {
|
|
|
|
var parents: [Int] {
|
|
var array = [Int]()
|
|
for layer in self {
|
|
if let parent = layer.parent {
|
|
array.append(parent)
|
|
} else {
|
|
array.append(-1)
|
|
}
|
|
}
|
|
return array
|
|
}
|
|
|
|
}
|