diff --git a/Sources/OpenSwiftUICore/Graphic/Color/ColorRenderingMode.swift b/Sources/OpenSwiftUICore/Graphic/Color/ColorRenderingMode.swift deleted file mode 100644 index c547d337b..000000000 --- a/Sources/OpenSwiftUICore/Graphic/Color/ColorRenderingMode.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// ColorRenderingMode.swift -// OpenSwiftUICore -// -// Audited for 6.0.87 -// Status: Complete - -/// The set of possible working color spaces for color-compositing operations. -/// -/// Each color space guarantees the preservation of a particular range of color -/// values. -public enum ColorRenderingMode: Sendable { - /// The non-linear sRGB working color space. - /// - /// Color component values outside the range `[0, 1]` produce undefined - /// results. This color space is gamma corrected. - case nonLinear - - /// The linear sRGB working color space. - /// - /// Color component values outside the range `[0, 1]` produce undefined - /// results. This color space isn't gamma corrected. - case linear - - /// The extended linear sRGB working color space. - /// - /// Color component values outside the range `[0, 1]` are preserved. - /// This color space isn't gamma corrected. - case extendedLinear -} - -extension ColorRenderingMode: ProtobufEnum { - package var protobufValue: UInt { - switch self { - case .nonLinear: - return 0 - case .linear: - return 1 - case .extendedLinear: - return 2 - } - } - package init?(protobufValue value: UInt) { - switch value { - case 0: - self = .nonLinear - case 1: - self = .linear - case 2: - self = .extendedLinear - default: - return nil - } - } -} diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift index 3a5eb79ef..92e565c29 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift @@ -528,8 +528,3 @@ extension GraphicsImage: ProtobufMessage { } } package struct ResolvedShadowStyle {} - -package struct RasterizationOptions {} -package protocol RBDisplayListContents {} // RenderBox.RBDisplayListContents -public struct PlatformDrawableOptions {} -public protocol PlatformDrawable : AnyObject {} diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 015a9ad22..634a138ee 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -1,5 +1,5 @@ // -// PlatformViewDefinition.swift +// DisplayListViewPlatform.swift // OpenSwiftUICore // // Audited for 6.0.87 diff --git a/Sources/OpenSwiftUICore/Render/PlatformDrawable.swift b/Sources/OpenSwiftUICore/Render/PlatformDrawable.swift new file mode 100644 index 000000000..614d649da --- /dev/null +++ b/Sources/OpenSwiftUICore/Render/PlatformDrawable.swift @@ -0,0 +1,150 @@ +// +// PlatformDrawable.swift +// OpenSwiftUICore +// +// Audited for 6.5.4 +// Status: WIP + +import OpenAttributeGraphShims +import OpenRenderBoxShims +public import OpenCoreGraphicsShims +#if canImport(QuarzCore) +public import QuartzCore +import CoreAnimation_Private +#endif + +// MARK: - PlatformDrawable + +@_spi(DisplayList_ViewSystem) +@available(OpenSwiftUI_v6_0, *) +public protocol PlatformDrawable: AnyObject { + var options: PlatformDrawableOptions { get set } + + static var allowsContentsMultiplyColor: Bool { get } + + func update(content: PlatformDrawableContent?, required: Bool) -> Bool + + #if canImport(QuarzCore) + func makeAsyncUpdate( + content: PlatformDrawableContent, + required: Bool, + layer: CALayer, + bounds: CGRect + ) -> (() -> Void)? + #endif + + func setContentsScale(_ scale: CGFloat) + + func drawForTesting(in: RBDisplayList) -> () +} + +// MARK: - PlatformDrawableContent [WIP] + +@_spi(DisplayList_ViewSystem) +@available(OpenSwiftUI_v6_0, *) +public struct PlatformDrawableContent: @unchecked Sendable { + enum Storage { + case graphicsCallback((inout GraphicsContext, CGSize) -> ()) + case platformCallback((CGSize) -> ()) + case displayList(DisplayList, CGPoint, Time) + case rbDisplayList(RBDisplayListContents, CGPoint) + case rbInterpolator(RBDisplayListInterpolator, Float, CGPoint) + case empty + } + + private var storage: Storage = .empty + + public struct State { + package var mode: DisplayList.GraphicsRenderer.PlatformViewMode + + package var _renderer: DisplayList.GraphicsRenderer? + + package init() { + mode = .unsupported + _renderer = nil + } + + package init(platformViewMode: DisplayList.GraphicsRenderer.PlatformViewMode) { + mode = platformViewMode + _renderer = nil + } + + package mutating func renderer() -> DisplayList.GraphicsRenderer { + guard let _renderer else { + let render = DisplayList.GraphicsRenderer(platformViewMode: mode) + _renderer = render + return render + } + return _renderer + } + } + + public init() { + _openSwiftUIEmptyStub() + } + + #if canImport(CoreGraphics) + public func draw( + in ctx: CGContext, + size: CGSize, + contentsScale: CGFloat, + state: inout PlatformDrawableContent.State + ) { + _openSwiftUIUnimplementedFailure() + } + #endif + + public func draw( + in list: RBDisplayList, + size: CGSize, + state: inout PlatformDrawableContent.State + ) { + _openSwiftUIUnimplementedFailure() + } +} + +@_spi(DisplayList_ViewSystem) +@available(*, unavailable) +extension PlatformDrawableContent.State: Sendable {} + +// MARK: - PlatformDrawableOptions [Blocked by RBLayer] + +@_spi(DisplayList_ViewSystem) +@available(OpenSwiftUI_v6_0, *) +public struct PlatformDrawableOptions: Equatable, Sendable { + var base: RasterizationOptions + + public var isAccelerated: Bool { + base.isAccelerated + } + + public var isOpaque: Bool { + base.isOpaque + } + + public var rendersAsynchronously: Bool { + base.rendersAsynchronously + } + + public var rendersFirstFrameAsynchronously: Bool { + base.rendersFirstFrameAsynchronously + } + + #if canImport(QuarzCore) + public var caLayerContentsFormat: CALayerContentsFormat { + var format = CALayerContentsFormat.automatic + if base.flags.contains(.rgbaContext) { + format = .RGBA8Uint + } + if base.flags.contains(.alphaOnly) { + format = .A8 + } + return format + } + #endif + + public func update(rbLayer: AnyObject) { + // TODO: RBLayer + _openSwiftUIUnimplementedFailure() + } +} diff --git a/Sources/OpenSwiftUICore/Render/RasterizationOptions.swift b/Sources/OpenSwiftUICore/Render/RasterizationOptions.swift new file mode 100644 index 000000000..3e1d24039 --- /dev/null +++ b/Sources/OpenSwiftUICore/Render/RasterizationOptions.swift @@ -0,0 +1,181 @@ +// +// RasterizationOptions.swift +// OpenSwiftUICore +// +// Audited for 6.5.4 +// Status: WIP + +// MARK: - ColorRenderingMode + +/// The set of possible working color spaces for color-compositing operations. +/// +/// Each color space guarantees the preservation of a particular range of color +/// values. +public enum ColorRenderingMode: Sendable { + + /// The non-linear sRGB working color space. + /// + /// Color component values outside the range `[0, 1]` produce undefined + /// results. This color space is gamma corrected. + case nonLinear + + /// The linear sRGB working color space. + /// + /// Color component values outside the range `[0, 1]` produce undefined + /// results. This color space isn't gamma corrected. + case linear + + /// The extended linear sRGB working color space. + /// + /// Color component values outside the range `[0, 1]` are preserved. + /// This color space isn't gamma corrected. + case extendedLinear +} + +extension ColorRenderingMode: ProtobufEnum { + package var protobufValue: UInt { + switch self { + case .nonLinear: return 0 + case .linear: return 1 + case .extendedLinear: return 2 + } + } + + package init?(protobufValue value: UInt) { + switch value { + case 0: self = .nonLinear + case 1: self = .linear + case 2: self = .extendedLinear + default: return nil + } + } +} + +// MARK: - RasterizationOptions [WIP] + +package struct RasterizationOptions: Equatable { + package struct Flags: OptionSet { + package let rawValue: UInt32 + + package init(rawValue: UInt32) { + self.rawValue = rawValue + } + + package static let isAccelerated: RasterizationOptions.Flags = .init(rawValue: 1 << 0) + + package static let isOpaque: RasterizationOptions.Flags = .init(rawValue: 1 << 1) + + package static let rendersAsynchronously: RasterizationOptions.Flags = .init(rawValue: 1 << 2) + + package static let prefersDisplayCompositing: RasterizationOptions.Flags = .init(rawValue: 1 << 3) + + package static let rendersFirstFrameAsync: RasterizationOptions.Flags = .init(rawValue: 1 << 4) + + package static let allowsPackedDrawable: RasterizationOptions.Flags = .init(rawValue: 1 << 5) + + package static let alphaOnly: RasterizationOptions.Flags = .init(rawValue: 1 << 6) + + package static let requiresLayer: RasterizationOptions.Flags = .init(rawValue: 1 << 7) + + package static let rgbaContext: RasterizationOptions.Flags = .init(rawValue: 1 << 8) + + package static let highRes: RasterizationOptions.Flags = .init(rawValue: 1 << 9) + + package static let defaultFlags: RasterizationOptions.Flags = [.allowsPackedDrawable, .requiresLayer] + } + + package var colorMode: ColorRenderingMode + + package var rbColorMode: Int32? + + package var flags: RasterizationOptions.Flags + + package var maxDrawableCount: Int8 + + package init( + colorMode: ColorRenderingMode = .nonLinear, + rbColorMode: Int32? = nil, + flags: RasterizationOptions.Flags = .defaultFlags, + maxDrawableCount: Int8 = 3 + ) { + self.colorMode = colorMode + self.rbColorMode = rbColorMode + self.flags = flags + self.maxDrawableCount = maxDrawableCount + } + + package var isAccelerated: Bool { + get { flags.contains(.isAccelerated) } + set { flags.setValue(newValue, for: .isAccelerated) } + } + + package var isOpaque: Bool { + get { flags.contains(.isOpaque) } + set { flags.setValue(newValue, for: .isOpaque) } + } + + package var rendersAsynchronously: Bool { + get { flags.contains(.rendersAsynchronously) } + set { flags.setValue(newValue, for: .rendersAsynchronously) } + } + + package var rendersFirstFrameAsynchronously: Bool { + get { flags.contains(.rendersFirstFrameAsync) } + set { flags.setValue(newValue, for: .rendersFirstFrameAsync) } + } + + package var prefersDisplayCompositing: Bool { + get { flags.contains(.prefersDisplayCompositing) } + set { flags.setValue(newValue, for: .prefersDisplayCompositing) } + } + + package var allowsPackedDrawable: Bool { + get { flags.contains(.allowsPackedDrawable) } + set { flags.setValue(newValue, for: .allowsPackedDrawable) } + } + + package var resolvedColorMode: RBColorMode { + _openSwiftUIUnimplementedFailure() + } + + package var colorSpace: RBColorSpace { + _openSwiftUIUnimplementedFailure() + } + + package var alphaOnly: Bool { + get { flags.contains(.alphaOnly) } + set { flags.setValue(newValue, for: .alphaOnly) } + } + + package var requiresLayer: Bool { + get { flags.contains(.requiresLayer) } + set { flags.setValue(newValue, for: .requiresLayer) } + } +} + +extension RasterizationOptions: ProtobufMessage { + package func encode(to encoder: inout ProtobufEncoder) { + encoder.enumField(1, colorMode, defaultValue: .nonLinear) + if let rbColorMode { + encoder.intField(2, Int(rbColorMode)) + } + encoder.intField(3, Int(flags.rawValue)) + encoder.intField(4, Int(maxDrawableCount)) + } + + package init(from decoder: inout ProtobufDecoder) throws { + var options = RasterizationOptions() + while let field = try decoder.nextField() { + switch field.tag { + case 1: options.colorMode = try decoder.enumField(field) ?? .nonLinear + case 2: options.rbColorMode = Int32(try decoder.intField(field)) + case 3: options.flags = Flags(rawValue: UInt32(try decoder.intField(field))) + case 4: options.maxDrawableCount = Int8(try decoder.intField(field)) + default: try decoder.skipField(field) + } + } + self = options + } +} + +// TODO: DrawingGroupEffect diff --git a/Sources/OpenSwiftUICore/Render/RendererConfiguration.swift b/Sources/OpenSwiftUICore/Render/RendererConfiguration.swift index ee5b31c08..9a34bf030 100644 --- a/Sources/OpenSwiftUICore/Render/RendererConfiguration.swift +++ b/Sources/OpenSwiftUICore/Render/RendererConfiguration.swift @@ -2,34 +2,74 @@ // RendererConfiguration.swift // OpenSwiftUICore // -// Audited for 6.0.87 +// Audited for 6.5.4 // Status: Complete +/// Renderer configuration for a hosting view. public struct _RendererConfiguration { + + /// The available renderer kind and their configuration. public enum Renderer { + /// The default renderer for the current platform. case `default` + + /// An alternative renderer that rasterizes everything in the + /// local process. indirect case rasterized(_ options: _RendererConfiguration.RasterizationOptions = .init()) } - + + /// The renderer kind and its specific configuration. public var renderer: _RendererConfiguration.Renderer + + /// The minimum time between display updates. Zero means to attempt + /// to match the natural display update rate, infinity means to + /// disable animations, values in between clamp the delay between + /// animation updates. public var minFrameInterval: Double + public init(renderer: _RendererConfiguration.Renderer = .default) { self.renderer = renderer self.minFrameInterval = .zero } - + + /// Returns a configuration to render as a rasterized bitmap. public static func rasterized(_ options: _RendererConfiguration.RasterizationOptions = .init()) -> _RendererConfiguration { _RendererConfiguration(renderer: .rasterized(options)) } - + + /// Options for the `rasterized` renderer. public struct RasterizationOptions { + + /// The color mode to use when rendering the view. public var colorMode: ColorRenderingMode = .nonLinear - public var rbColorMode: Int32? = nil + + /// When non-nil overrides colorMode with a member of the + /// `RBColorMode` enum, specified as its raw integer value. + public var rbColorMode: Int32? + + /// When true the view will build and submit its command buffer + /// asynchronously. public var rendersAsynchronously: Bool = false + + /// When true no alpha component is created for the view’s + /// content. Setting this value will often require less memory. public var isOpaque: Bool = true + + /// When true native platform views that have been inserted + /// into the view hierarchy (e.g. via UIViewRepresentable) will + /// be drawn via their CALayer’s -renderInContext: method + /// (after updating their view bounds). public var drawsPlatformViews: Bool = true + + /// Set this to true to avoid using buffer formats that would + /// disable display compositing; doing so may increase memory + /// requirements. public var prefersDisplayCompositing: Bool = false + + /// The maximum number of surfaces that will be allocated by + /// the view, will currently be clamped to the range [2, 3]. public var maxDrawableCount: Int = 3 + public init() {} } } diff --git a/Sources/OpenSwiftUICore/Util/RenderBoxShims.swift b/Sources/OpenSwiftUICore/Util/RenderBoxShims.swift new file mode 100644 index 000000000..1a4ca4902 --- /dev/null +++ b/Sources/OpenSwiftUICore/Util/RenderBoxShims.swift @@ -0,0 +1,13 @@ +// +// RenderBoxShims.swift +// OpenSwiftUI + +package protocol RBDisplayListContents {} // RenderBox.RBDisplayListContents + +class RBDisplayListInterpolator {} + +public enum RBDisplayList {} + +package enum RBColorSpace {} + +package enum RBColorMode {} diff --git a/Sources/OpenSwiftUI_SPI/Shims/CoreAnimation/CoreAnimation_Private.h b/Sources/OpenSwiftUI_SPI/Shims/CoreAnimation/CoreAnimation_Private.h index 4c99301a6..855b984d2 100644 --- a/Sources/OpenSwiftUI_SPI/Shims/CoreAnimation/CoreAnimation_Private.h +++ b/Sources/OpenSwiftUI_SPI/Shims/CoreAnimation/CoreAnimation_Private.h @@ -46,6 +46,9 @@ typedef struct CAColorMatrix CAColorMatrix; - (void)setHighFrameRateReasons_openswiftui_safe_wrapper:(const uint32_t *)reasons count:(NSInteger)count OPENSWIFTUI_SWIFT_NAME(setHighFrameRateReasons(_:count:)); @end +CA_EXTERN CALayerContentsFormat const kCAContentsFormatAutomatic OPENSWIFTUI_SWIFT_NAME(automatic); +CA_EXTERN CALayerContentsFormat const kCAContentsFormatA8 OPENSWIFTUI_SWIFT_NAME(A8); + OPENSWIFTUI_ASSUME_NONNULL_END #endif /* CoreAnimation.h */