// // RenderLayer.swift // lottie-swift // // Created by Brandon Withrow on 1/18/19. // import Foundation import QuartzCore /// The layer responsible for rendering shape objects final class ShapeRenderLayer: ShapeContainerLayer { // MARK: Lifecycle init(renderer: Renderable & NodeOutput) { self.renderer = renderer super.init() anchorPoint = .zero actions = [ "position" : NSNull(), "bounds" : NSNull(), "anchorPoint" : NSNull(), "path" : NSNull(), "transform" : NSNull(), "opacity" : NSNull(), "hidden" : NSNull(), ] shapeLayer.actions = [ "position" : NSNull(), "bounds" : NSNull(), "anchorPoint" : NSNull(), "path" : NSNull(), "fillColor" : NSNull(), "strokeColor" : NSNull(), "lineWidth" : NSNull(), "miterLimit" : NSNull(), "lineDashPhase" : NSNull(), "opacity": NSNull(), "hidden" : NSNull(), ] addSublayer(shapeLayer) renderer.setupSublayers(layer: shapeLayer) } override init(layer: Any) { guard let layer = layer as? ShapeRenderLayer else { fatalError("init(layer:) wrong class.") } renderer = layer.renderer super.init(layer: layer) } required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: Internal fileprivate(set) var renderer: Renderable & NodeOutput let shapeLayer = CAShapeLayer() override func hasRenderUpdate(forFrame: CGFloat) -> Bool { isHidden = !renderer.isEnabled guard isHidden == false else { return false } return renderer.hasRenderUpdates(forFrame) } override func rebuildContents(forFrame _: CGFloat) { if renderer.shouldRenderInContext { if let newPath = renderer.outputPath { bounds = renderer.renderBoundsFor(newPath.boundingBox) } else { bounds = .zero } position = bounds.origin setNeedsDisplay() } else { shapeLayer.path = renderer.outputPath renderer.updateShapeLayer(layer: shapeLayer) } } override func draw(in ctx: CGContext) { if let path = renderer.outputPath { if !path.isEmpty { ctx.addPath(path) } } renderer.render(ctx) } override func updateRenderScale() { super.updateRenderScale() shapeLayer.contentsScale = renderScale } }