mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 14:45:21 +00:00
Various improvements
This commit is contained in:
@@ -3,7 +3,15 @@ import UIKit
|
||||
import QuartzCore
|
||||
import simd
|
||||
|
||||
struct DrawingColor: Equatable {
|
||||
struct DrawingColor: Equatable, Codable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case red
|
||||
case green
|
||||
case blue
|
||||
case alpha
|
||||
case position
|
||||
}
|
||||
|
||||
public static var clear = DrawingColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
|
||||
|
||||
public var red: CGFloat
|
||||
@@ -48,6 +56,24 @@ struct DrawingColor: Equatable {
|
||||
public init(rgb: UInt32) {
|
||||
self.init(color: UIColor(rgb: rgb))
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.red = try container.decode(CGFloat.self, forKey: .red)
|
||||
self.green = try container.decode(CGFloat.self, forKey: .green)
|
||||
self.blue = try container.decode(CGFloat.self, forKey: .blue)
|
||||
self.alpha = try container.decode(CGFloat.self, forKey: .alpha)
|
||||
self.position = try container.decodeIfPresent(CGPoint.self, forKey: .position)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(self.red, forKey: .red)
|
||||
try container.encode(self.green, forKey: .green)
|
||||
try container.encode(self.blue, forKey: .blue)
|
||||
try container.encode(self.alpha, forKey: .alpha)
|
||||
try container.encodeIfPresent(self.position, forKey: .position)
|
||||
}
|
||||
|
||||
func withUpdatedRed(_ red: CGFloat) -> DrawingColor {
|
||||
return DrawingColor(
|
||||
@@ -561,156 +587,6 @@ private func configureControlPoints(data: [CGPoint]) -> [(ctrl1: CGPoint, ctrl2:
|
||||
return []
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class FPSCounter: NSObject {
|
||||
|
||||
/// Helper class that relays display link updates to the FPSCounter
|
||||
///
|
||||
/// This is necessary because CADisplayLink retains its target. Thus
|
||||
/// if the FPSCounter class would be the target of the display link
|
||||
/// it would create a retain cycle. The delegate has a weak reference
|
||||
/// to its parent FPSCounter, thus preventing this.
|
||||
///
|
||||
internal class DisplayLinkProxy: NSObject {
|
||||
|
||||
/// A weak ref to the parent FPSCounter instance.
|
||||
@objc weak var parentCounter: FPSCounter?
|
||||
|
||||
/// Notify the parent FPSCounter of a CADisplayLink update.
|
||||
///
|
||||
/// This method is automatically called by the CADisplayLink.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - displayLink: The display link that updated
|
||||
///
|
||||
@objc func updateFromDisplayLink(_ displayLink: CADisplayLink) {
|
||||
parentCounter?.updateFromDisplayLink(displayLink)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
private let displayLink: CADisplayLink
|
||||
private let displayLinkProxy: DisplayLinkProxy
|
||||
|
||||
/// Create a new FPSCounter.
|
||||
///
|
||||
/// To start receiving FPS updates you need to start tracking with the
|
||||
/// `startTracking(inRunLoop:mode:)` method.
|
||||
///
|
||||
public override init() {
|
||||
self.displayLinkProxy = DisplayLinkProxy()
|
||||
self.displayLink = CADisplayLink(
|
||||
target: self.displayLinkProxy,
|
||||
selector: #selector(DisplayLinkProxy.updateFromDisplayLink(_:))
|
||||
)
|
||||
|
||||
super.init()
|
||||
|
||||
self.displayLinkProxy.parentCounter = self
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.displayLink.invalidate()
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Configuration
|
||||
|
||||
/// The delegate that should receive FPS updates.
|
||||
public weak var delegate: FPSCounterDelegate?
|
||||
|
||||
/// Delay between FPS updates. Longer delays mean more averaged FPS numbers.
|
||||
@objc public var notificationDelay: TimeInterval = 1.0
|
||||
|
||||
|
||||
// MARK: - Tracking
|
||||
|
||||
private var runloop: RunLoop?
|
||||
private var mode: RunLoop.Mode?
|
||||
|
||||
/// Start tracking FPS updates.
|
||||
///
|
||||
/// You can specify wich runloop to use for tracking, as well as the runloop modes.
|
||||
/// Usually you'll want the main runloop (default), and either the common run loop modes
|
||||
/// (default), or the tracking mode (`RunLoop.Mode.tracking`).
|
||||
///
|
||||
/// When the counter is already tracking, it's stopped first.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - runloop: The runloop to start tracking in
|
||||
/// - mode: The mode(s) to track in the runloop
|
||||
///
|
||||
@objc public func startTracking(inRunLoop runloop: RunLoop = .main, mode: RunLoop.Mode = .common) {
|
||||
self.stopTracking()
|
||||
|
||||
self.runloop = runloop
|
||||
self.mode = mode
|
||||
self.displayLink.add(to: runloop, forMode: mode)
|
||||
}
|
||||
|
||||
/// Stop tracking FPS updates.
|
||||
///
|
||||
/// This method does nothing if the counter is not currently tracking.
|
||||
///
|
||||
@objc public func stopTracking() {
|
||||
guard let runloop = self.runloop, let mode = self.mode else { return }
|
||||
|
||||
self.displayLink.remove(from: runloop, forMode: mode)
|
||||
self.runloop = nil
|
||||
self.mode = nil
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Handling Frame Updates
|
||||
|
||||
private var lastNotificationTime: CFAbsoluteTime = 0.0
|
||||
private var numberOfFrames = 0
|
||||
|
||||
private func updateFromDisplayLink(_ displayLink: CADisplayLink) {
|
||||
if self.lastNotificationTime == 0.0 {
|
||||
self.lastNotificationTime = CFAbsoluteTimeGetCurrent()
|
||||
return
|
||||
}
|
||||
|
||||
self.numberOfFrames += 1
|
||||
|
||||
let currentTime = CFAbsoluteTimeGetCurrent()
|
||||
let elapsedTime = currentTime - self.lastNotificationTime
|
||||
|
||||
if elapsedTime >= self.notificationDelay {
|
||||
self.notifyUpdateForElapsedTime(elapsedTime)
|
||||
self.lastNotificationTime = 0.0
|
||||
self.numberOfFrames = 0
|
||||
}
|
||||
}
|
||||
|
||||
private func notifyUpdateForElapsedTime(_ elapsedTime: CFAbsoluteTime) {
|
||||
let fps = Int(round(Double(self.numberOfFrames) / elapsedTime))
|
||||
self.delegate?.fpsCounter(self, didUpdateFramesPerSecond: fps)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// The delegate protocol for the FPSCounter class.
|
||||
///
|
||||
/// Implement this protocol if you want to receive updates from a `FPSCounter`.
|
||||
///
|
||||
protocol FPSCounterDelegate: NSObjectProtocol {
|
||||
|
||||
/// Called in regular intervals while the counter is tracking FPS.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - counter: The FPSCounter that sent the update
|
||||
/// - fps: The current FPS of the application
|
||||
///
|
||||
func fpsCounter(_ counter: FPSCounter, didUpdateFramesPerSecond fps: Int)
|
||||
}
|
||||
|
||||
class BezierPath {
|
||||
struct Element {
|
||||
enum ElementType {
|
||||
|
||||
Reference in New Issue
Block a user