mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
217 lines
8.3 KiB
Swift
217 lines
8.3 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import CoreGraphics
|
|
import SwiftSignalKit
|
|
|
|
private enum Corner: Hashable {
|
|
case TopLeft(Int), TopRight(Int), BottomLeft(Int), BottomRight(Int)
|
|
|
|
var hashValue: Int {
|
|
switch self {
|
|
case let .TopLeft(radius):
|
|
return radius | (1 << 24)
|
|
case let .TopRight(radius):
|
|
return radius | (2 << 24)
|
|
case let .BottomLeft(radius):
|
|
return radius | (3 << 24)
|
|
case let .BottomRight(radius):
|
|
return radius | (4 << 24)
|
|
}
|
|
}
|
|
|
|
var radius: Int {
|
|
switch self {
|
|
case let .TopLeft(radius):
|
|
return radius
|
|
case let .TopRight(radius):
|
|
return radius
|
|
case let .BottomLeft(radius):
|
|
return radius
|
|
case let .BottomRight(radius):
|
|
return radius
|
|
}
|
|
}
|
|
}
|
|
|
|
private func ==(lhs: Corner, rhs: Corner) -> Bool {
|
|
switch lhs {
|
|
case let .TopLeft(lhsRadius):
|
|
switch rhs {
|
|
case let .TopLeft(rhsRadius) where rhsRadius == lhsRadius:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case let .TopRight(lhsRadius):
|
|
switch rhs {
|
|
case let .TopRight(rhsRadius) where rhsRadius == lhsRadius:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case let .BottomLeft(lhsRadius):
|
|
switch rhs {
|
|
case let .BottomLeft(rhsRadius) where rhsRadius == lhsRadius:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case let .BottomRight(lhsRadius):
|
|
switch rhs {
|
|
case let .BottomRight(rhsRadius) where rhsRadius == lhsRadius:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
private enum Tail: Hashable {
|
|
case BottomLeft(Int)
|
|
case BottomRight(Int)
|
|
|
|
var hashValue: Int {
|
|
switch self {
|
|
case let .BottomLeft(radius):
|
|
return radius | (1 << 24)
|
|
case let .BottomRight(radius):
|
|
return radius | (2 << 24)
|
|
}
|
|
}
|
|
|
|
var radius: Int {
|
|
switch self {
|
|
case let .BottomLeft(radius):
|
|
return radius
|
|
case let .BottomRight(radius):
|
|
return radius
|
|
}
|
|
}
|
|
}
|
|
|
|
private func ==(lhs: Tail, rhs: Tail) -> Bool {
|
|
switch lhs {
|
|
case let .BottomLeft(lhsRadius):
|
|
switch rhs {
|
|
case let .BottomLeft(rhsRadius) where rhsRadius == lhsRadius:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case let .BottomRight(lhsRadius):
|
|
switch rhs {
|
|
case let .BottomRight(rhsRadius) where rhsRadius == lhsRadius:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
private var cachedCorners = Atomic<[Corner: DrawingContext]>(value: [:])
|
|
|
|
private func cornerContext(_ corner: Corner) -> DrawingContext {
|
|
let cached: DrawingContext? = cachedCorners.with {
|
|
return $0[corner]
|
|
}
|
|
|
|
if let cached = cached {
|
|
return cached
|
|
} else {
|
|
let context = DrawingContext(size: CGSize(width: CGFloat(corner.radius), height: CGFloat(corner.radius)), clear: true)
|
|
|
|
context.withContext { c in
|
|
c.clear(CGRect(origin: CGPoint(), size: CGSize(width: CGFloat(corner.radius), height: CGFloat(corner.radius))))
|
|
c.setFillColor(UIColor.black.cgColor)
|
|
switch corner {
|
|
case let .TopLeft(radius):
|
|
let rect = CGRect(origin: CGPoint(), size: CGSize(width: CGFloat(radius * 2), height: CGFloat(radius * 2)))
|
|
c.fillEllipse(in: rect)
|
|
case let .TopRight(radius):
|
|
let rect = CGRect(origin: CGPoint(x: -CGFloat(radius), y: 0.0), size: CGSize(width: CGFloat(radius * 2), height: CGFloat(radius * 2)))
|
|
c.fillEllipse(in: rect)
|
|
case let .BottomLeft(radius):
|
|
let rect = CGRect(origin: CGPoint(x: 0.0, y: -CGFloat(radius)), size: CGSize(width: CGFloat(radius * 2), height: CGFloat(radius * 2)))
|
|
c.fillEllipse(in: rect)
|
|
case let .BottomRight(radius):
|
|
let rect = CGRect(origin: CGPoint(x: -CGFloat(radius), y: -CGFloat(radius)), size: CGSize(width: CGFloat(radius * 2), height: CGFloat(radius * 2)))
|
|
c.fillEllipse(in: rect)
|
|
}
|
|
}
|
|
|
|
let _ = cachedCorners.modify { current in
|
|
var current = current
|
|
current[corner] = context
|
|
return current
|
|
}
|
|
|
|
return context
|
|
}
|
|
}
|
|
|
|
public func addCorners(_ context: DrawingContext, arguments: TransformImageArguments) {
|
|
let corners = arguments.corners
|
|
let drawingRect = arguments.drawingRect
|
|
if case let .Corner(radius) = corners.topLeft, radius > CGFloat.ulpOfOne {
|
|
let corner = cornerContext(.TopLeft(Int(radius)))
|
|
context.blt(corner, at: CGPoint(x: drawingRect.minX, y: drawingRect.minY))
|
|
}
|
|
|
|
if case let .Corner(radius) = corners.topRight, radius > CGFloat.ulpOfOne {
|
|
let corner = cornerContext(.TopRight(Int(radius)))
|
|
context.blt(corner, at: CGPoint(x: drawingRect.maxX - radius, y: drawingRect.minY))
|
|
}
|
|
|
|
switch corners.bottomLeft {
|
|
case let .Corner(radius):
|
|
if radius > CGFloat.ulpOfOne {
|
|
let corner = cornerContext(.BottomLeft(Int(radius)))
|
|
context.blt(corner, at: CGPoint(x: drawingRect.minX, y: drawingRect.maxY - radius))
|
|
}
|
|
case let .Tail(radius, image):
|
|
if radius > CGFloat.ulpOfOne {
|
|
let color = context.colorAt(CGPoint(x: drawingRect.minX, y: drawingRect.maxY - 1.0))
|
|
context.withContext { c in
|
|
c.clear(CGRect(x: drawingRect.minX - 4.0, y: 0.0, width: 4.0, height: drawingRect.maxY - 6.0))
|
|
c.setFillColor(color.cgColor)
|
|
c.fill(CGRect(x: 0.0, y: drawingRect.maxY - 7.0, width: 4.0, height: 7.0))
|
|
c.setBlendMode(.destinationIn)
|
|
let cornerRect = CGRect(origin: CGPoint(x: drawingRect.minX - 6.0, y: drawingRect.maxY - image.size.height), size: image.size)
|
|
c.translateBy(x: cornerRect.midX, y: cornerRect.midY)
|
|
c.scaleBy(x: 1.0, y: -1.0)
|
|
c.translateBy(x: -cornerRect.midX, y: -cornerRect.midY)
|
|
c.draw(image.cgImage!, in: cornerRect)
|
|
c.translateBy(x: cornerRect.midX, y: cornerRect.midY)
|
|
c.scaleBy(x: 1.0, y: -1.0)
|
|
c.translateBy(x: -cornerRect.midX, y: -cornerRect.midY)
|
|
}
|
|
}
|
|
}
|
|
|
|
switch corners.bottomRight {
|
|
case let .Corner(radius):
|
|
if radius > CGFloat.ulpOfOne {
|
|
let corner = cornerContext(.BottomRight(Int(radius)))
|
|
context.blt(corner, at: CGPoint(x: drawingRect.maxX - radius, y: drawingRect.maxY - radius))
|
|
}
|
|
case let .Tail(radius, image):
|
|
if radius > CGFloat.ulpOfOne {
|
|
let color = context.colorAt(CGPoint(x: drawingRect.maxX - 1.0, y: drawingRect.maxY - 1.0))
|
|
context.withContext { c in
|
|
c.clear(CGRect(x: drawingRect.maxX, y: 0.0, width: 4.0, height: drawingRect.maxY - image.size.height))
|
|
c.setFillColor(color.cgColor)
|
|
c.fill(CGRect(x: drawingRect.maxX, y: drawingRect.maxY - 7.0, width: 5.0, height: 7.0))
|
|
c.setBlendMode(.destinationIn)
|
|
let cornerRect = CGRect(origin: CGPoint(x: drawingRect.maxX - image.size.width + 6.0, y: drawingRect.maxY - image.size.height), size: image.size)
|
|
c.translateBy(x: cornerRect.midX, y: cornerRect.midY)
|
|
c.scaleBy(x: 1.0, y: -1.0)
|
|
c.translateBy(x: -cornerRect.midX, y: -cornerRect.midY)
|
|
c.draw(image.cgImage!, in: cornerRect)
|
|
c.translateBy(x: cornerRect.midX, y: cornerRect.midY)
|
|
c.scaleBy(x: 1.0, y: -1.0)
|
|
c.translateBy(x: -cornerRect.midX, y: -cornerRect.midY)
|
|
}
|
|
}
|
|
}
|
|
}
|