Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2021-06-17 00:05:35 +03:00
commit 562265997d
21 changed files with 172 additions and 156 deletions

View File

@ -614,7 +614,7 @@ private final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource
self.data = data self.data = data
self.width = width self.width = width
self.height = height self.height = height
self.bytesPerRow = (4 * Int(width) + 15) & (~15) self.bytesPerRow = DeviceGraphicsContextSettings.shared.bytesPerRow(forWidth: Int(width))
self.currentFrame = 0 self.currentFrame = 0
let rawData = TGGUnzipData(data, 8 * 1024 * 1024) ?? data let rawData = TGGUnzipData(data, 8 * 1024 * 1024) ?? data
let decompressedData = transformedWithFitzModifier(data: rawData, fitzModifier: fitzModifier) let decompressedData = transformedWithFitzModifier(data: rawData, fitzModifier: fitzModifier)

View File

@ -13,7 +13,7 @@ final class SoftwareAnimationRenderer: ASDisplayNode, AnimationRenderer {
queue.async { [weak self] in queue.async { [weak self] in
switch type { switch type {
case .argb: case .argb:
let calculatedBytesPerRow = (4 * Int(width) + 15) & (~15) let calculatedBytesPerRow = DeviceGraphicsContextSettings.shared.bytesPerRow(forWidth: Int(width))
assert(bytesPerRow == calculatedBytesPerRow) assert(bytesPerRow == calculatedBytesPerRow)
case .yuva: case .yuva:
break break

View File

@ -6,7 +6,7 @@
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 // Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
// //
#import "ASCGImageBuffer.h" #import <AsyncDisplayKit/ASCGImageBuffer.h>
#import <sys/mman.h> #import <sys/mman.h>
#import <mach/mach_init.h> #import <mach/mach_init.h>
@ -32,7 +32,7 @@
{ {
if (self = [super init]) { if (self = [super init]) {
_length = length; _length = length;
_isVM = (length >= vm_page_size); _isVM = false;//(length >= vm_page_size);
if (_isVM) { if (_isVM) {
_mutableBytes = mmap(NULL, length, PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, VM_MAKE_TAG(VM_MEMORY_COREGRAPHICS_DATA), 0); _mutableBytes = mmap(NULL, length, PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, VM_MAKE_TAG(VM_MEMORY_COREGRAPHICS_DATA), 0);
if (_mutableBytes == MAP_FAILED) { if (_mutableBytes == MAP_FAILED) {
@ -43,7 +43,7 @@
// Check the VM flag again because we may have failed above. // Check the VM flag again because we may have failed above.
if (!_isVM) { if (!_isVM) {
_mutableBytes = calloc(1, length); _mutableBytes = malloc(length);
} }
} }
return self; return self;

View File

@ -7,7 +7,7 @@
// //
#import <AsyncDisplayKit/ASGraphicsContext.h> #import <AsyncDisplayKit/ASGraphicsContext.h>
#import "ASCGImageBuffer.h" #import <AsyncDisplayKit/ASCGImageBuffer.h>
#import <AsyncDisplayKit/ASAssert.h> #import <AsyncDisplayKit/ASAssert.h>
#import <AsyncDisplayKit/ASConfigurationInternal.h> #import <AsyncDisplayKit/ASConfigurationInternal.h>
#import <AsyncDisplayKit/ASInternalHelpers.h> #import <AsyncDisplayKit/ASInternalHelpers.h>

View File

@ -161,7 +161,7 @@ public func peerAvatarImage(account: Account, peerReference: PeerReference?, aut
} }
if shouldBlur { if shouldBlur {
let imageContextSize = CGSize(width: 64.0, height: 64.0) let imageContextSize = CGSize(width: 64.0, height: 64.0)
let imageContext = DrawingContext(size: imageContextSize, scale: 1.0, premultiplied: true, clear: true) let imageContext = DrawingContext(size: imageContextSize, scale: 1.0, clear: true)
imageContext.withFlippedContext { c in imageContext.withFlippedContext { c in
c.draw(dataImage, in: CGRect(origin: CGPoint(), size: imageContextSize)) c.draw(dataImage, in: CGRect(origin: CGPoint(), size: imageContextSize))

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import UIKit import UIKit
import Accelerate import Accelerate
import AsyncDisplayKit
public let deviceColorSpace: CGColorSpace = { public let deviceColorSpace: CGColorSpace = {
if #available(iOSApplicationExtension 9.3, iOS 9.3, *) { if #available(iOSApplicationExtension 9.3, iOS 9.3, *) {
@ -19,38 +20,20 @@ private let grayscaleColorSpace = CGColorSpaceCreateDeviceGray()
let deviceScale = UIScreen.main.scale let deviceScale = UIScreen.main.scale
public func generateImagePixel(_ size: CGSize, scale: CGFloat, pixelGenerator: (CGSize, UnsafeMutablePointer<UInt8>, Int) -> Void) -> UIImage? { public func generateImagePixel(_ size: CGSize, scale: CGFloat, pixelGenerator: (CGSize, UnsafeMutablePointer<UInt8>, Int) -> Void) -> UIImage? {
let scaledSize = CGSize(width: size.width * scale, height: size.height * scale) let context = DrawingContext(size: size, scale: scale, opaque: false, clear: false)
let bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15) pixelGenerator(CGSize(width: size.width * scale, height: size.height * scale), context.bytes.assumingMemoryBound(to: UInt8.self), context.bytesPerRow)
let length = bytesPerRow * Int(scaledSize.height) return context.generateImage()
let bytes = malloc(length)!.assumingMemoryBound(to: UInt8.self)
guard let provider = CGDataProvider(dataInfo: bytes, data: bytes, size: length, releaseData: { bytes, _, _ in
free(bytes)
})
else {
return nil
}
pixelGenerator(scaledSize, bytes, bytesPerRow)
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
guard let image = CGImage(width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo, provider: provider, decode: nil, shouldInterpolate: false, intent: .defaultIntent)
else {
return nil
}
return UIImage(cgImage: image, scale: scale, orientation: .up)
} }
private func withImageBytes(image: UIImage, _ f: (UnsafePointer<UInt8>, Int, Int, Int) -> Void) { private func withImageBytes(image: UIImage, _ f: (UnsafePointer<UInt8>, Int, Int, Int) -> Void) {
let selectedScale = image.scale let selectedScale = image.scale
let scaledSize = CGSize(width: image.size.width * selectedScale, height: image.size.height * selectedScale) let scaledSize = CGSize(width: image.size.width * selectedScale, height: image.size.height * selectedScale)
let bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15) let bytesPerRow = DeviceGraphicsContextSettings.shared.bytesPerRow(forWidth: Int(scaledSize.width))
let length = bytesPerRow * Int(scaledSize.height) let length = bytesPerRow * Int(scaledSize.height)
let bytes = malloc(length)!.assumingMemoryBound(to: UInt8.self) let bytes = malloc(length)!.assumingMemoryBound(to: UInt8.self)
memset(bytes, 0, length) memset(bytes, 0, length)
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue) let bitmapInfo = DeviceGraphicsContextSettings.shared.transparentBitmapInfo
guard let context = CGContext(data: bytes, width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo.rawValue) else { guard let context = CGContext(data: bytes, width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo.rawValue) else {
return return
@ -65,7 +48,7 @@ private func withImageBytes(image: UIImage, _ f: (UnsafePointer<UInt8>, Int, Int
public func generateGrayscaleAlphaMaskImage(image: UIImage) -> UIImage? { public func generateGrayscaleAlphaMaskImage(image: UIImage) -> UIImage? {
let selectedScale = image.scale let selectedScale = image.scale
let scaledSize = CGSize(width: image.size.width * selectedScale, height: image.size.height * selectedScale) let scaledSize = CGSize(width: image.size.width * selectedScale, height: image.size.height * selectedScale)
let bytesPerRow = (1 * Int(scaledSize.width) + 15) & (~15) let bytesPerRow = (1 * Int(scaledSize.width) + 31) & (~31)
let length = bytesPerRow * Int(scaledSize.height) let length = bytesPerRow * Int(scaledSize.height)
let bytes = malloc(length)!.assumingMemoryBound(to: UInt8.self) let bytes = malloc(length)!.assumingMemoryBound(to: UInt8.self)
memset(bytes, 0, length) memset(bytes, 0, length)
@ -111,69 +94,25 @@ public func generateGrayscaleAlphaMaskImage(image: UIImage) -> UIImage? {
} }
public func generateImage(_ size: CGSize, contextGenerator: (CGSize, CGContext) -> Void, opaque: Bool = false, scale: CGFloat? = nil) -> UIImage? { public func generateImage(_ size: CGSize, contextGenerator: (CGSize, CGContext) -> Void, opaque: Bool = false, scale: CGFloat? = nil) -> UIImage? {
let selectedScale = scale ?? deviceScale if size.width.isZero || size.height.isZero {
let scaledSize = CGSize(width: size.width * selectedScale, height: size.height * selectedScale)
let bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15)
let length = bytesPerRow * Int(scaledSize.height)
let bytes = malloc(length)!.assumingMemoryBound(to: Int8.self)
guard let provider = CGDataProvider(dataInfo: bytes, data: bytes, size: length, releaseData: { bytes, _, _ in
free(bytes)
})
else {
return nil return nil
} }
let context = DrawingContext(size: size, scale: scale ?? 0.0, opaque: opaque, clear: false)
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | (opaque ? CGImageAlphaInfo.noneSkipFirst.rawValue : CGImageAlphaInfo.premultipliedFirst.rawValue)) context.withFlippedContext { c in
contextGenerator(context.size, c)
guard let context = CGContext(data: bytes, width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo.rawValue) else {
return nil
} }
return context.generateImage()
context.scaleBy(x: selectedScale, y: selectedScale)
contextGenerator(size, context)
guard let image = CGImage(width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo, provider: provider, decode: nil, shouldInterpolate: false, intent: .defaultIntent)
else {
return nil
}
return UIImage(cgImage: image, scale: selectedScale, orientation: .up)
} }
public func generateImage(_ size: CGSize, opaque: Bool = false, scale: CGFloat? = nil, rotatedContext: (CGSize, CGContext) -> Void) -> UIImage? { public func generateImage(_ size: CGSize, opaque: Bool = false, scale: CGFloat? = nil, rotatedContext: (CGSize, CGContext) -> Void) -> UIImage? {
let selectedScale = scale ?? deviceScale if size.width.isZero || size.height.isZero {
let scaledSize = CGSize(width: size.width * selectedScale, height: size.height * selectedScale)
let bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15)
let length = bytesPerRow * Int(scaledSize.height)
let bytes = malloc(length)!.assumingMemoryBound(to: Int8.self)
guard let provider = CGDataProvider(dataInfo: bytes, data: bytes, size: length, releaseData: { bytes, _, _ in
free(bytes)
}) else {
return nil return nil
} }
let context = DrawingContext(size: size, scale: scale ?? 0.0, opaque: opaque, clear: false)
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | (opaque ? CGImageAlphaInfo.noneSkipFirst.rawValue : CGImageAlphaInfo.premultipliedFirst.rawValue)) context.withContext { c in
rotatedContext(context.size, c)
guard let context = CGContext(data: bytes, width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo.rawValue) else {
return nil
} }
return context.generateImage()
context.scaleBy(x: selectedScale, y: selectedScale)
context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
context.scaleBy(x: 1.0, y: -1.0)
context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0)
rotatedContext(size, context)
guard let image = CGImage(width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo, provider: provider, decode: nil, shouldInterpolate: false, intent: .defaultIntent)
else {
return nil
}
return UIImage(cgImage: image, scale: selectedScale, orientation: .up)
} }
public func generateFilledCircleImage(diameter: CGFloat, color: UIColor?, strokeColor: UIColor? = nil, strokeWidth: CGFloat? = nil, backgroundColor: UIColor? = nil) -> UIImage? { public func generateFilledCircleImage(diameter: CGFloat, color: UIColor?, strokeColor: UIColor? = nil, strokeWidth: CGFloat? = nil, backgroundColor: UIColor? = nil) -> UIImage? {
@ -433,6 +372,47 @@ public enum DrawingContextBltMode {
case Alpha case Alpha
} }
public struct DeviceGraphicsContextSettings {
public static let shared: DeviceGraphicsContextSettings = {
UIGraphicsBeginImageContextWithOptions(CGSize(width: 1.0, height: 1.0), true, 1.0)
let refContext = UIGraphicsGetCurrentContext()!
let bytesPerRow = refContext.bytesPerRow
let bitsPerPixel = refContext.bitsPerPixel
let bitsPerComponent = refContext.bitsPerComponent
let opaqueBitmapInfo = refContext.bitmapInfo
let image = UIGraphicsGetImageFromCurrentImageContext()!
let colorSpace = image.cgImage!.colorSpace!
assert(bytesPerRow == 32)
UIGraphicsEndImageContext()
UIGraphicsBeginImageContextWithOptions(CGSize(width: 1.0, height: 1.0), false, 1.0)
let refCtxTransparent = UIGraphicsGetCurrentContext()!
let transparentBitmapInfo = refCtxTransparent.bitmapInfo
UIGraphicsEndImageContext()
return DeviceGraphicsContextSettings(
rowAlignment: bytesPerRow,
bitsPerPixel: bitsPerPixel,
bitsPerComponent: bitsPerComponent,
opaqueBitmapInfo: opaqueBitmapInfo,
transparentBitmapInfo: transparentBitmapInfo,
colorSpace: colorSpace
)
}()
public let rowAlignment: Int
public let bitsPerPixel: Int
public let bitsPerComponent: Int
public let opaqueBitmapInfo: CGBitmapInfo
public let transparentBitmapInfo: CGBitmapInfo
public let colorSpace: CGColorSpace
public func bytesPerRow(forWidth width: Int) -> Int {
let baseValue = self.bitsPerPixel * width / 8
return (baseValue + 31) & ~0x1F
}
}
public class DrawingContext { public class DrawingContext {
public let size: CGSize public let size: CGSize
public let scale: CGFloat public let scale: CGFloat
@ -440,46 +420,36 @@ public class DrawingContext {
public let bytesPerRow: Int public let bytesPerRow: Int
private let bitmapInfo: CGBitmapInfo private let bitmapInfo: CGBitmapInfo
public let length: Int public let length: Int
public let bytes: UnsafeMutableRawPointer private let imageBuffer: ASCGImageBuffer
let provider: CGDataProvider? public var bytes: UnsafeMutableRawPointer {
if self.hasGeneratedImage {
preconditionFailure()
}
return self.imageBuffer.mutableBytes
}
private let context: CGContext
private var _context: CGContext? private var hasGeneratedImage = false
public func withContext(_ f: (CGContext) -> ()) { public func withContext(_ f: (CGContext) -> ()) {
if self._context == nil { let context = self.context
if let c = CGContext(data: bytes, width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: self.bitmapInfo.rawValue) {
c.scaleBy(x: scale, y: scale)
self._context = c
}
}
if let _context = self._context { context.translateBy(x: self.size.width / 2.0, y: self.size.height / 2.0)
_context.translateBy(x: self.size.width / 2.0, y: self.size.height / 2.0) context.scaleBy(x: 1.0, y: -1.0)
_context.scaleBy(x: 1.0, y: -1.0) context.translateBy(x: -self.size.width / 2.0, y: -self.size.height / 2.0)
_context.translateBy(x: -self.size.width / 2.0, y: -self.size.height / 2.0)
f(_context) f(context)
_context.translateBy(x: self.size.width / 2.0, y: self.size.height / 2.0) context.translateBy(x: self.size.width / 2.0, y: self.size.height / 2.0)
_context.scaleBy(x: 1.0, y: -1.0) context.scaleBy(x: 1.0, y: -1.0)
_context.translateBy(x: -self.size.width / 2.0, y: -self.size.height / 2.0) context.translateBy(x: -self.size.width / 2.0, y: -self.size.height / 2.0)
}
} }
public func withFlippedContext(_ f: (CGContext) -> ()) { public func withFlippedContext(_ f: (CGContext) -> ()) {
if self._context == nil { f(self.context)
if let c = CGContext(data: bytes, width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: self.bitmapInfo.rawValue) {
c.scaleBy(x: scale, y: scale)
self._context = c
}
}
if let _context = self._context {
f(_context)
}
} }
public init(size: CGSize, scale: CGFloat = 0.0, premultiplied: Bool = true, opaque: Bool = false, clear: Bool = false) { public init(size: CGSize, scale: CGFloat = 0.0, opaque: Bool = false, clear: Bool = false) {
let actualScale: CGFloat let actualScale: CGFloat
if scale.isZero { if scale.isZero {
actualScale = deviceScale actualScale = deviceScale
@ -490,35 +460,61 @@ public class DrawingContext {
self.scale = actualScale self.scale = actualScale
self.scaledSize = CGSize(width: size.width * actualScale, height: size.height * actualScale) self.scaledSize = CGSize(width: size.width * actualScale, height: size.height * actualScale)
self.bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15) self.bytesPerRow = DeviceGraphicsContextSettings.shared.bytesPerRow(forWidth: Int(scaledSize.width))
self.length = bytesPerRow * Int(scaledSize.height) self.length = bytesPerRow * Int(scaledSize.height)
self.imageBuffer = ASCGImageBuffer(length: UInt(self.length))
if opaque { if opaque {
self.bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.noneSkipFirst.rawValue) self.bitmapInfo = DeviceGraphicsContextSettings.shared.opaqueBitmapInfo
} else if premultiplied {
self.bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
} else { } else {
self.bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.first.rawValue) self.bitmapInfo = DeviceGraphicsContextSettings.shared.transparentBitmapInfo
} }
self.bytes = malloc(length)! self.context = CGContext(
data: self.imageBuffer.mutableBytes,
width: Int(self.scaledSize.width),
height: Int(self.scaledSize.height),
bitsPerComponent: DeviceGraphicsContextSettings.shared.bitsPerComponent,
bytesPerRow: self.bytesPerRow,
space: DeviceGraphicsContextSettings.shared.colorSpace,
bitmapInfo: self.bitmapInfo.rawValue,
releaseCallback: nil,
releaseInfo: nil
)!
self.context.scaleBy(x: self.scale, y: self.scale)
if clear { if clear {
memset(self.bytes, 0, self.length) memset(self.bytes, 0, self.length)
} }
self.provider = CGDataProvider(dataInfo: bytes, data: bytes, size: length, releaseData: { bytes, _, _ in
free(bytes)
})
assert(self.bytesPerRow % 16 == 0)
assert(Int64(Int(bitPattern: self.bytes)) % 16 == 0)
} }
public func generateImage() -> UIImage? { public func generateImage() -> UIImage? {
if self.scaledSize.width.isZero || self.scaledSize.height.isZero { if self.scaledSize.width.isZero || self.scaledSize.height.isZero {
return nil return nil
} }
if let image = CGImage(width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo, provider: provider!, decode: nil, shouldInterpolate: false, intent: .defaultIntent) { if self.hasGeneratedImage {
return UIImage(cgImage: image, scale: scale, orientation: .up) preconditionFailure()
return nil
}
self.hasGeneratedImage = true
let dataProvider = self.imageBuffer.createDataProviderAndInvalidate()
if let image = CGImage(
width: Int(self.scaledSize.width),
height: Int(self.scaledSize.height),
bitsPerComponent: self.context.bitsPerComponent,
bitsPerPixel: self.context.bitsPerPixel,
bytesPerRow: self.context.bytesPerRow,
space: DeviceGraphicsContextSettings.shared.colorSpace,
bitmapInfo: self.context.bitmapInfo,
provider: dataProvider,
decode: nil,
shouldInterpolate: true,
intent: .defaultIntent
) {
return UIImage(cgImage: image, scale: self.scale, orientation: .up)
} else { } else {
return nil return nil
} }

View File

@ -56,7 +56,7 @@ var deviceScale: CGFloat {
func generateImage(_ size: CGSize, contextGenerator: (CGSize, CGContext) -> Void, opaque: Bool = false, scale: CGFloat? = nil) -> GImage? { func generateImage(_ size: CGSize, contextGenerator: (CGSize, CGContext) -> Void, opaque: Bool = false, scale: CGFloat? = nil) -> GImage? {
let selectedScale = scale ?? deviceScale let selectedScale = scale ?? deviceScale
let scaledSize = CGSize(width: size.width * selectedScale, height: size.height * selectedScale) let scaledSize = CGSize(width: size.width * selectedScale, height: size.height * selectedScale)
let bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15) let bytesPerRow = (4 * Int(scaledSize.width) + 31) & (~31)
let length = bytesPerRow * Int(scaledSize.height) let length = bytesPerRow * Int(scaledSize.height)
let bytes = malloc(length)!.assumingMemoryBound(to: Int8.self) let bytes = malloc(length)!.assumingMemoryBound(to: Int8.self)

View File

@ -113,7 +113,7 @@
_offscreenContextWidth = offscreenWidth; _offscreenContextWidth = offscreenWidth;
_offscreenContextHeight = offscreenHeight; _offscreenContextHeight = offscreenHeight;
_offscreenContextStride = ((4 * _offscreenContextWidth + 15) & (~15)); _offscreenContextStride = ((4 * _offscreenContextWidth + 31) & (~31));
_offscreenMemory = malloc(_offscreenContextStride * _offscreenContextHeight); _offscreenMemory = malloc(_offscreenContextStride * _offscreenContextHeight);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

View File

@ -21,7 +21,7 @@ protocol LegacyPaintEntity {
} }
private func render(width: Int, height: Int, bytesPerRow: Int, data: Data, type: AnimationRendererFrameType) -> CIImage? { private func render(width: Int, height: Int, bytesPerRow: Int, data: Data, type: AnimationRendererFrameType) -> CIImage? {
let calculatedBytesPerRow = (4 * Int(width) + 15) & (~15) let calculatedBytesPerRow = (4 * Int(width) + 31) & (~31)
assert(bytesPerRow == calculatedBytesPerRow) assert(bytesPerRow == calculatedBytesPerRow)
let image = generateImagePixel(CGSize(width: CGFloat(width), height: CGFloat(height)), scale: 1.0, pixelGenerator: { _, pixelData, bytesPerRow in let image = generateImagePixel(CGSize(width: CGFloat(width), height: CGFloat(height)), scale: 1.0, pixelGenerator: { _, pixelData, bytesPerRow in

View File

@ -13,6 +13,8 @@ public final class ManagedAnimationState {
public let item: ManagedAnimationItem public let item: ManagedAnimationItem
private let instance: LottieInstance private let instance: LottieInstance
private let displaySize: CGSize
let frameCount: Int let frameCount: Int
let fps: Double let fps: Double
@ -21,15 +23,11 @@ public final class ManagedAnimationState {
public var executedCallbacks = Set<Int>() public var executedCallbacks = Set<Int>()
private let renderContext: DrawingContext
public init?(displaySize: CGSize, item: ManagedAnimationItem, current: ManagedAnimationState?) { public init?(displaySize: CGSize, item: ManagedAnimationItem, current: ManagedAnimationState?) {
let resolvedInstance: LottieInstance let resolvedInstance: LottieInstance
let renderContext: DrawingContext
if let current = current { if let current = current {
resolvedInstance = current.instance resolvedInstance = current.instance
renderContext = current.renderContext
} else { } else {
guard let path = item.source.path else { guard let path = item.source.path else {
return nil return nil
@ -44,20 +42,21 @@ public final class ManagedAnimationState {
return nil return nil
} }
resolvedInstance = instance resolvedInstance = instance
renderContext = DrawingContext(size: displaySize, scale: UIScreenScale, premultiplied: true, clear: true)
} }
self.displaySize = displaySize
self.item = item self.item = item
self.instance = resolvedInstance self.instance = resolvedInstance
self.renderContext = renderContext
self.frameCount = Int(self.instance.frameCount) self.frameCount = Int(self.instance.frameCount)
self.fps = Double(self.instance.frameRate) self.fps = Double(self.instance.frameRate)
} }
func draw() -> UIImage? { func draw() -> UIImage? {
self.instance.renderFrame(with: Int32(self.frameIndex ?? 0), into: self.renderContext.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(self.renderContext.size.width * self.renderContext.scale), height: Int32(self.renderContext.size.height * self.renderContext.scale), bytesPerRow: Int32(self.renderContext.bytesPerRow)) let renderContext = DrawingContext(size: self.displaySize, scale: UIScreenScale, clear: true)
return self.renderContext.generateImage()
self.instance.renderFrame(with: Int32(self.frameIndex ?? 0), into: renderContext.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(renderContext.size.width * renderContext.scale), height: Int32(renderContext.size.height * renderContext.scale), bytesPerRow: Int32(renderContext.bytesPerRow))
return renderContext.generateImage()
} }
} }

View File

@ -222,7 +222,7 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder {
var srcCb = vImage_Buffer(data: frame.data[1], height: vImagePixelCount(frame.height), width: vImagePixelCount(frame.width / 2), rowBytes: Int(frame.lineSize[1])) var srcCb = vImage_Buffer(data: frame.data[1], height: vImagePixelCount(frame.height), width: vImagePixelCount(frame.width / 2), rowBytes: Int(frame.lineSize[1]))
var srcCr = vImage_Buffer(data: frame.data[2], height: vImagePixelCount(frame.height), width: vImagePixelCount(frame.width / 2), rowBytes: Int(frame.lineSize[2])) var srcCr = vImage_Buffer(data: frame.data[2], height: vImagePixelCount(frame.height), width: vImagePixelCount(frame.width / 2), rowBytes: Int(frame.lineSize[2]))
let argbBytesPerRow = (4 * Int(frame.width) + 15) & (~15) let argbBytesPerRow = (4 * Int(frame.width) + 31) & (~31)
let argbLength = argbBytesPerRow * Int(frame.height) let argbLength = argbBytesPerRow * Int(frame.height)
let argb = malloc(argbLength)! let argb = malloc(argbLength)!
guard let provider = CGDataProvider(dataInfo: argb, data: argb, size: argbLength, releaseData: { bytes, _, _ in guard let provider = CGDataProvider(dataInfo: argb, data: argb, size: argbLength, releaseData: { bytes, _, _ in

View File

@ -70,7 +70,7 @@ NSData * _Nullable compressJPEGData(UIImage * _Nonnull sourceImage) {
int width = (int)(sourceImage.size.width * sourceImage.scale); int width = (int)(sourceImage.size.width * sourceImage.scale);
int height = (int)(sourceImage.size.height * sourceImage.scale); int height = (int)(sourceImage.size.height * sourceImage.scale);
int targetBytesPerRow = ((4 * (int)width) + 15) & (~15); int targetBytesPerRow = ((4 * (int)width) + 31) & (~31);
uint8_t *targetMemory = malloc((int)(targetBytesPerRow * height)); uint8_t *targetMemory = malloc((int)(targetBytesPerRow * height));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
@ -86,7 +86,7 @@ NSData * _Nullable compressJPEGData(UIImage * _Nonnull sourceImage) {
UIGraphicsPopContext(); UIGraphicsPopContext();
int bufferBytesPerRow = ((3 * (int)width) + 15) & (~15); int bufferBytesPerRow = ((3 * (int)width) + 31) & (~31);
uint8_t *buffer = malloc(bufferBytesPerRow * height); uint8_t *buffer = malloc(bufferBytesPerRow * height);
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
@ -158,7 +158,7 @@ NSData * _Nullable compressMiniThumbnail(UIImage * _Nonnull image, CGSize size)
int width = (int)fittedSize.width; int width = (int)fittedSize.width;
int height = (int)fittedSize.height; int height = (int)fittedSize.height;
int targetBytesPerRow = ((4 * (int)width) + 15) & (~15); int targetBytesPerRow = ((4 * (int)width) + 31) & (~31);
uint8_t *targetMemory = malloc((int)(targetBytesPerRow * height)); uint8_t *targetMemory = malloc((int)(targetBytesPerRow * height));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
@ -174,7 +174,7 @@ NSData * _Nullable compressMiniThumbnail(UIImage * _Nonnull image, CGSize size)
UIGraphicsPopContext(); UIGraphicsPopContext();
int bufferBytesPerRow = ((3 * (int)width) + 15) & (~15); int bufferBytesPerRow = ((3 * (int)width) + 31) & (~31);
uint8_t *buffer = malloc(bufferBytesPerRow * height); uint8_t *buffer = malloc(bufferBytesPerRow * height);
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {

View File

@ -74,7 +74,7 @@ final class ImageBasedPasscodeBackground: PasscodeBackground {
} }
telegramFastBlurMore(Int32(contextSize.width), Int32(contextSize.height), Int32(backgroundContext.bytesPerRow), backgroundContext.bytes) telegramFastBlurMore(Int32(contextSize.width), Int32(contextSize.height), Int32(backgroundContext.bytesPerRow), backgroundContext.bytes)
telegramFastBlurMore(Int32(contextSize.width), Int32(contextSize.height), Int32(backgroundContext.bytesPerRow), backgroundContext.bytes) telegramFastBlurMore(Int32(contextSize.width), Int32(contextSize.height), Int32(backgroundContext.bytesPerRow), backgroundContext.bytes)
telegramFastBlurMore(Int32(contextSize.width), Int32(contextSize.height), Int32(foregroundContext.bytesPerRow), foregroundContext.bytes) telegramFastBlurMore(Int32(contextSize.width), Int32(contextSize.height), Int32(foregroundContext.bytesPerRow), backgroundContext.bytes)
backgroundContext.withFlippedContext { context in backgroundContext.withFlippedContext { context in
context.setFillColor(UIColor(white: 0.0, alpha: 0.35).cgColor) context.setFillColor(UIColor(white: 0.0, alpha: 0.35).cgColor)

View File

@ -46,7 +46,7 @@ public func qrCode(string: String, color: UIColor, backgroundColor: UIColor? = n
if let output = filter.outputImage { if let output = filter.outputImage {
let size = Int(output.extent.width) let size = Int(output.extent.width)
let bytesPerRow = (4 * Int(size) + 15) & (~15) let bytesPerRow = DeviceGraphicsContextSettings.shared.bytesPerRow(forWidth: Int(size))
let length = bytesPerRow * size let length = bytesPerRow * size
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.noneSkipFirst.rawValue) let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.noneSkipFirst.rawValue)

View File

@ -280,6 +280,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
if existingIds.contains(file.file.fileId) { if existingIds.contains(file.file.fileId) {
return false return false
} else { } else {
print("slug: \(file.slug)")
existingIds.insert(file.file.fileId) existingIds.insert(file.file.fileId)
return true return true
} }
@ -352,8 +353,10 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
} ?? 80 } ?? 80
var selectedFileId: Int64? var selectedFileId: Int64?
var selectedSlug: String?
if let currentWallpaper = self.currentWallpaper, case let .file(file) = currentWallpaper { if let currentWallpaper = self.currentWallpaper, case let .file(file) = currentWallpaper {
selectedFileId = file.id selectedFileId = file.id
selectedSlug = file.slug
} }
for wallpaper in self.wallpapers { for wallpaper in self.wallpapers {
@ -368,7 +371,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
} }
var selected = false var selected = false
if case let .file(file) = wallpaper, file.id == selectedFileId { if case let .file(file) = wallpaper, (file.id == selectedFileId || file.slug == selectedSlug) {
selected = true selected = true
} }

View File

@ -136,7 +136,7 @@ public func experimentalConvertCompressedLottieToCombinedMp4(data: Data, size: C
return return
} }
let bytesPerRow = (4 * Int(size.width) + 15) & (~15) let bytesPerRow = DeviceGraphicsContextSettings.shared.bytesPerRow(forWidth: Int(size.width))
var currentFrame: Int32 = 0 var currentFrame: Int32 = 0

View File

@ -1572,6 +1572,15 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
return return
} }
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.2, curve: .easeInOut) : .immediate
let replyAlpha: CGFloat = item.controllerInteraction.selectionState == nil ? 1.0 : 0.0
if let replyInfoNode = self.replyInfoNode {
transition.updateAlpha(node: replyInfoNode, alpha: replyAlpha)
}
if let replyBackgroundNode = self.replyBackgroundNode {
transition.updateAlpha(node: replyBackgroundNode, alpha: replyAlpha)
}
if let selectionState = item.controllerInteraction.selectionState { if let selectionState = item.controllerInteraction.selectionState {
var selected = false var selected = false
var incoming = true var incoming = true

View File

@ -1088,6 +1088,15 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
isEmoji = true isEmoji = true
} }
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.2, curve: .easeInOut) : .immediate
let replyAlpha: CGFloat = item.controllerInteraction.selectionState == nil ? 1.0 : 0.0
if let replyInfoNode = self.replyInfoNode {
transition.updateAlpha(node: replyInfoNode, alpha: replyAlpha)
}
if let replyBackgroundNode = self.replyBackgroundNode {
transition.updateAlpha(node: replyBackgroundNode, alpha: replyAlpha)
}
if let selectionState = item.controllerInteraction.selectionState { if let selectionState = item.controllerInteraction.selectionState {
let selected = selectionState.selectedIds.contains(item.message.id) let selected = selectionState.selectedIds.contains(item.message.id)

View File

@ -16,7 +16,7 @@ private let motionAmount: CGFloat = 32.0
private func generateBlurredContents(image: UIImage) -> UIImage? { private func generateBlurredContents(image: UIImage) -> UIImage? {
let size = image.size.aspectFitted(CGSize(width: 64.0, height: 64.0)) let size = image.size.aspectFitted(CGSize(width: 64.0, height: 64.0))
let context = DrawingContext(size: size, scale: 1.0, premultiplied: true, opaque: true, clear: false) let context = DrawingContext(size: size, scale: 1.0, opaque: true, clear: false)
context.withFlippedContext { c in context.withFlippedContext { c in
c.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size)) c.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size))
} }

View File

@ -19,7 +19,7 @@
const struct { int width, height; } targetContextSize = { width, height}; const struct { int width, height; } targetContextSize = { width, height};
size_t targetBytesPerRow = ((4 * (int)targetContextSize.width) + 15) & (~15); size_t targetBytesPerRow = ((4 * (int)targetContextSize.width) + 31) & (~31);
void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height)); void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height));