Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ final class UIViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen
case .mask:
view = _UIGraphicsView()
view.mask = _UIInheritedView()
initView(view.mask!, kind: kind)
initView(view.mask!, kind: .inherited)
default:
view = kind.isContainer ? _UIInheritedView() : _UIGraphicsView()
}
Expand Down Expand Up @@ -95,13 +95,12 @@ final class UIViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen
view.layer.anchorPoint = .zero
switch kind {
case .color, .image, .shape:
view.layer.allowsEdgeAntialiasing = true
break
case .geometry, .projection, .affine3D, .mask, .platformEffect:
let layer = view.layer
layer.allowsEdgeAntialiasing = true
case .inherited, .geometry, .projection, .affine3D, .mask, .platformEffect:
let layer = view.layer
layer.allowsGroupOpacity = false
layer.allowsGroupBlending = false
break
default:
break
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
//
// CAHostingLayerPlatformDefinition.swift
// OpenSwiftUICore
//
// Audited for 6.5.4
// Status: Complete
// ID: E2A63CF3FB15FAD08FBE4CE6D0C83E51 (SwiftUICore)

#if canImport(QuartzCore)
import OpenSwiftUI_SPI
import QuartzCore
import QuartzCore_Private
import OpenRenderBoxShims

// MARK: - CAHostingLayerPlatformDefinition

final class CAHostingLayerPlatformDefinition: PlatformViewDefinition, @unchecked Sendable {
override static var system: PlatformViewDefinition.System { .caLayer }

override static func makeView(kind: PlatformViewDefinition.ViewKind) -> AnyObject {
let layer = CALayer()
if kind == .mask {
let maskLayer = CALayer()
layer.mask = maskLayer
initLayer(layer.mask!, kind: .inherited)
}
initLayer(layer, kind: kind)
return layer
}

override static func makeLayerView(type: CALayer.Type, kind: PlatformViewDefinition.ViewKind) -> AnyObject {
let layer = type.init()
initLayer(layer, kind: kind)
return layer
}

override static func makePlatformView(view: AnyObject, kind: PlatformViewDefinition.ViewKind) {
let layer = view as! CALayer
Self.initLayer(layer, kind: kind)
}

override static func makeDrawingView(options: PlatformDrawableOptions) -> any PlatformDrawable {
let layer: CALayer & PlatformDrawable
if options.isAccelerated && ORBDevice.isSupported() {
layer = RBDrawingLayer(options: options)
} else {
layer = CGDrawingLayer(options: options)
}
layer.contentsGravity = .topLeft
initLayer(layer, kind: .drawing)
return layer
}

override static func setPath(_ path: Path, shapeView: AnyObject) {
_openSwiftUIEmptyStub()
}

override static func setProjectionTransform(_ transform: ProjectionTransform, projectionView: AnyObject) {
let layer = projectionView as! CALayer
layer.transform = CATransform3D(transform)
}

override static func getRBLayer(drawingView: AnyObject) -> AnyObject? {
drawingView as? ORBLayer
}

override static func setIgnoresEvents(_ state: Bool, of view: AnyObject) {
let layer = unsafeBitCast(view, to: CALayer.self)
layer.allowsHitTesting = !state
}

private static func initLayer(_ layer: CALayer, kind: PlatformViewDefinition.ViewKind) {
layer.delegate = CAPlatformLayerDelegate.shared
layer.anchorPoint = .zero
switch kind {
case .color, .image, .shape:
layer.allowsEdgeAntialiasing = true
case .inherited, .geometry, .projection, .affine3D, .mask:
layer.allowsGroupOpacity = false
layer.allowsGroupBlending = false
default:
break
}
}
}

// MARK: - CAPlatformLayerDelegate

final class CAPlatformLayerDelegate: NSObject, CALayerDelegate {
static let shared = CAPlatformLayerDelegate()

func action(for layer: CALayer, forKey event: String) -> (any CAAction)? {
_CANullAction()
}
}

// MARK: - CGDrawingLayer

private final class CGDrawingLayer: CALayer, PlatformDrawable {
var content: PlatformDrawableContent = .init()
var state: PlatformDrawableContent.State = .init()
var options: PlatformDrawableOptions {
didSet {
guard oldValue != options else { return }
updateOptions()
}
}

init(options: PlatformDrawableOptions) {
self.options = options
super.init()
updateOptions()
}

@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func updateOptions() {
isOpaque = options.isOpaque
contentsFormat = options.caLayerContentsFormat
}

static var allowsContentsMultiplyColor: Bool { true }

func update(content: PlatformDrawableContent?, required: Bool) -> Bool {
if let content {
self.content = content
}
setNeedsDisplay()
return true
}

func makeAsyncUpdate(
content: PlatformDrawableContent,
required: Bool,
layer: CALayer,
bounds: CGRect
) -> (() -> Void)? {
nil
}

func setContentsScale(_ scale: CGFloat) {
contentsScale = scale
}

func drawForTesting(in displayList: ORBDisplayList) {
var state = PlatformDrawableContent.State()
content.draw(in: displayList, size: bounds.size, state: &state)
}

override func draw(in ctx: CGContext) {
content.draw(
in: ctx,
size: bounds.size,
contentsScale: contentsScale,
state: &state
)
}
}

// MARK: - RBDrawingLayer

private final class RBDrawingLayer: ORBLayer, PlatformDrawable {
var options: PlatformDrawableOptions {
didSet {
guard oldValue != options else { return }
updateOptions()
}
}

private struct State {
var content: PlatformDrawableContent = .init()
var renderer: PlatformDrawableContent.State = .init()
}

@AtomicBox
private var state: RBDrawingLayer.State = .init()

init(options: PlatformDrawableOptions) {
self.options = options
super.init()
updateOptions()
}

@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func updateOptions() {
isOpaque = options.isOpaque
options.update(rbLayer: self)
}

static var allowsContentsMultiplyColor: Bool { false }

func update(content: PlatformDrawableContent?, required: Bool) -> Bool {
guard required || !options.rendersAsynchronously || isDrawableAvailable else {
return false
}
if let content {
state.content = content
}
setNeedsDisplay()
return true
}

func makeAsyncUpdate(
content: PlatformDrawableContent,
required: Bool,
layer: CALayer,
bounds: CGRect
) -> (() -> Void)? {
guard required || !options.rendersAsynchronously || isDrawableAvailable else {
return nil
}
return { [self] in
state.content = content
display(withBounds: bounds) { displayList in
self.draw(in: displayList, size: bounds.size)
}
}
}

func setContentsScale(_ scale: CGFloat) {
contentsScale = scale
}

func drawForTesting(in displayList: ORBDisplayList) {
var s = PlatformDrawableContent.State()
state.content.draw(in: displayList, size: bounds.size, state: &s)
}

private func draw(in displayList: ORBDisplayList, size: CGSize) {
var renderer = $state.access { state in
let saved = state.renderer
state.renderer = PlatformDrawableContent.State()
return saved
}
let content = state.content
content.draw(in: displayList, size: size, state: &renderer)
$state.access { state in
state.renderer = renderer
}
}
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ open class PlatformViewDefinition: @unchecked Sendable {
public struct System: Hashable, Sendable {
public static let uiView = PlatformViewDefinition.System(base: .uiView)
public static let nsView = PlatformViewDefinition.System(base: .nsView)
static let caLayer = PlatformViewDefinition.System(base: .caLayer)

var base: ViewSystem
}

Expand Down
22 changes: 22 additions & 0 deletions Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CANullAction.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// CANullAction.h
// OpenSwiftUI_SPI
//
// Status: Complete

#ifndef CANullAction_h
#define CANullAction_h

#include "OpenSwiftUIBase.h"

#if __has_include(<QuartzCore/QuartzCore.h>)

#import <QuartzCore/QuartzCore.h>

/// Returns kCFNull as a CAAction to suppress implicit layer animations.
OPENSWIFTUI_EXPORT
id<CAAction> _Nonnull _CANullAction(void);

#endif /* __has_include(<QuartzCore/QuartzCore.h>) */

#endif /* CANullAction_h */
15 changes: 15 additions & 0 deletions Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CANullAction.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// CANullAction.m
// OpenSwiftUI_SPI
//
// Status: Complete

#import "CANullAction.h"

#if __has_include(<QuartzCore/QuartzCore.h>)

id<CAAction> _CANullAction(void) {
return (id<CAAction>)kCFNull;

Check warning on line 12 in Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CANullAction.m

View workflow job for this annotation

GitHub Actions / Execute compatibility tests for iOS (macos-15, 16.4, 2024, 18.5)

'const CFNullRef' (aka 'const struct __CFNull *const') bridges to NSNull, not 'id<CAAction>' [-Wbridge-cast]

Check warning on line 12 in Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CANullAction.m

View workflow job for this annotation

GitHub Actions / Execute compatibility tests for macOS (macos-15, 16.4, 2024)

'const CFNullRef' (aka 'const struct __CFNull *const') bridges to NSNull, not 'id<CAAction>' [-Wbridge-cast]
}

#endif /* __has_include(<QuartzCore/QuartzCore.h>) */
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ typedef NSString *CALayerContentsScaling NS_TYPED_ENUM;
@property (nonatomic, assign) BOOL allowsDisplayCompositing_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(allowsDisplayCompositing);
@property (nonatomic, assign, readonly) BOOL hasBeenCommitted_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(hasBeenCommitted);
@property (nonatomic, assign) BOOL allowsGroupBlending_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(allowsGroupBlending);
@property (nonatomic, assign) BOOL allowsHitTesting_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(allowsHitTesting);

@property (nonatomic, assign) uint64_t openSwiftUI_viewTestProperties;

Expand Down
10 changes: 10 additions & 0 deletions Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ - (void)setAllowsGroupBlending_openswiftui_safe_wrapper:(BOOL)allows {
func(self, selector, allows);
}

- (BOOL)allowsHitTesting_openswiftui_safe_wrapper {
OPENSWIFTUI_SAFE_WRAPPER_IMP(BOOL, @"allowsHitTesting", YES);
return func(self, selector);
}

- (void)setAllowsHitTesting_openswiftui_safe_wrapper:(BOOL)allows {
OPENSWIFTUI_SAFE_WRAPPER_IMP(void, @"setAllowsHitTesting:", , BOOL);
func(self, selector, allows);
}

- (uint64_t)openSwiftUI_viewTestProperties {
NSNumber *properties = [self valueForKey:@"_viewTestProperties"];
return properties.integerValue;
Expand Down
2 changes: 1 addition & 1 deletion Sources/OpenSwiftUI_SPI/module.modulemap
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module OpenSwiftUI_SPI {
umbrella "Overlay/CoreGraphics"
umbrella "Overlay"
export *

module Util {
Expand Down
Loading