// // PathNodeOutput.swift // lottie-swift // // Created by Brandon Withrow on 1/30/19. // import CoreGraphics import Foundation /// A node that has an output of a BezierPath class PathOutputNode: NodeOutput { // MARK: Lifecycle init(parent: NodeOutput?) { self.parent = parent } // MARK: Internal let parent: NodeOutput? fileprivate(set) var outputPath: CGPath? = nil var lastUpdateFrame: CGFloat? = nil var lastPathBuildFrame: CGFloat? = nil var isEnabled = true fileprivate(set) var totalLength: CGFloat = 0 fileprivate(set) var pathObjects: [CompoundBezierPath] = [] func hasOutputUpdates(_ forFrame: CGFloat) -> Bool { guard isEnabled else { let upstreamUpdates = parent?.hasOutputUpdates(forFrame) ?? false outputPath = parent?.outputPath return upstreamUpdates } /// Ask if parent was updated let upstreamUpdates = parent?.hasOutputUpdates(forFrame) ?? false /// If parent was updated and the path hasn't been built for this frame, clear the path. if upstreamUpdates && lastPathBuildFrame != forFrame { outputPath = nil } if outputPath == nil { /// If the path is clear, build the new path. lastPathBuildFrame = forFrame let newPath = CGMutablePath() if let parentNode = parent, let parentPath = parentNode.outputPath { newPath.addPath(parentPath) } for path in pathObjects { for subPath in path.paths { newPath.addPath(subPath.cgPath()) } } outputPath = newPath } /// Return true if there were upstream updates or if this node was updated. return upstreamUpdates || (lastUpdateFrame == forFrame) } @discardableResult func removePaths(updateFrame: CGFloat?) -> [CompoundBezierPath] { lastUpdateFrame = updateFrame let returnPaths = pathObjects outputPath = nil totalLength = 0 pathObjects = [] return returnPaths } func setPath(_ path: BezierPath, updateFrame: CGFloat) { lastUpdateFrame = updateFrame outputPath = nil totalLength = path.length pathObjects = [CompoundBezierPath(path: path)] } func appendPath(_ path: CompoundBezierPath, updateFrame: CGFloat) { lastUpdateFrame = updateFrame outputPath = nil totalLength = totalLength + path.length pathObjects.append(path) } }