From abbcc604026571c350894213c1d12c01a4d3da98 Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 12 Feb 2026 03:00:18 +0800 Subject: [PATCH 1/2] Update UIKitDIsplayList --- .../Render/DisplayList/UIKitDisplayList.swift | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift b/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift index 4f8db5a10..c70cfbfb8 100644 --- a/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift +++ b/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift @@ -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() } @@ -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 } From 42a1c9ed3e6b1417f8dc37420deb2a52553b9544 Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 12 Feb 2026 03:11:41 +0800 Subject: [PATCH 2/2] Add CAHostingLayerPlatformDefinition --- .../CAHostingLayerPlatformDefinition.swift | 250 ++++++++++++++++++ .../DisplayList/DisplayListViewPlatform.swift | 2 + .../Overlay/QuartzCore/CANullAction.h | 22 ++ .../Overlay/QuartzCore/CANullAction.m | 15 ++ .../Shims/QuartzCore/CALayerPrivate.h | 1 + .../Shims/QuartzCore/CALayerPrivate.m | 10 + Sources/OpenSwiftUI_SPI/module.modulemap | 2 +- 7 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 Sources/OpenSwiftUICore/Render/DisplayList/CAHostingLayerPlatformDefinition.swift create mode 100644 Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CANullAction.h create mode 100644 Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CANullAction.m diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/CAHostingLayerPlatformDefinition.swift b/Sources/OpenSwiftUICore/Render/DisplayList/CAHostingLayerPlatformDefinition.swift new file mode 100644 index 000000000..a2d12922f --- /dev/null +++ b/Sources/OpenSwiftUICore/Render/DisplayList/CAHostingLayerPlatformDefinition.swift @@ -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 diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 8c1add13d..cc2c53913 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -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 } diff --git a/Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CANullAction.h b/Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CANullAction.h new file mode 100644 index 000000000..5f388cb36 --- /dev/null +++ b/Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CANullAction.h @@ -0,0 +1,22 @@ +// +// CANullAction.h +// OpenSwiftUI_SPI +// +// Status: Complete + +#ifndef CANullAction_h +#define CANullAction_h + +#include "OpenSwiftUIBase.h" + +#if __has_include() + +#import + +/// Returns kCFNull as a CAAction to suppress implicit layer animations. +OPENSWIFTUI_EXPORT +id _Nonnull _CANullAction(void); + +#endif /* __has_include() */ + +#endif /* CANullAction_h */ diff --git a/Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CANullAction.m b/Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CANullAction.m new file mode 100644 index 000000000..eff019cbd --- /dev/null +++ b/Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CANullAction.m @@ -0,0 +1,15 @@ +// +// CANullAction.m +// OpenSwiftUI_SPI +// +// Status: Complete + +#import "CANullAction.h" + +#if __has_include() + +id _CANullAction(void) { + return (id)kCFNull; +} + +#endif /* __has_include() */ diff --git a/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.h b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.h index 0b8475a0f..db17afa08 100644 --- a/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.h +++ b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.h @@ -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; diff --git a/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.m b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.m index b8f4e5212..c56cb2179 100644 --- a/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.m +++ b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.m @@ -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; diff --git a/Sources/OpenSwiftUI_SPI/module.modulemap b/Sources/OpenSwiftUI_SPI/module.modulemap index 4655da103..dc26a84a2 100644 --- a/Sources/OpenSwiftUI_SPI/module.modulemap +++ b/Sources/OpenSwiftUI_SPI/module.modulemap @@ -1,5 +1,5 @@ module OpenSwiftUI_SPI { - umbrella "Overlay/CoreGraphics" + umbrella "Overlay" export * module Util {