From 1b12bdde396c00a3499fdb4c7c5f8547004f1fda Mon Sep 17 00:00:00 2001 From: Kyle Date: Fri, 24 Apr 2026 00:04:38 +0800 Subject: [PATCH 01/58] Add Path.isEmpty --- Sources/OpenSwiftUICore/Shape/Path.swift | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Sources/OpenSwiftUICore/Shape/Path.swift b/Sources/OpenSwiftUICore/Shape/Path.swift index 790e37720..40da04f7a 100644 --- a/Sources/OpenSwiftUICore/Shape/Path.swift +++ b/Sources/OpenSwiftUICore/Shape/Path.swift @@ -451,7 +451,20 @@ public struct Path: Equatable, LosslessStringConvertible, @unchecked Sendable { /// A Boolean value indicating whether the path contains zero elements. public var isEmpty: Bool { - _openSwiftUIUnimplementedFailure() + switch storage { + case .empty: + true + case let .rect(rect): + rect.isNull + case let .ellipse(rect): + rect.isNull + case let .roundedRect(fixedRoundedRect): + fixedRoundedRect.rect.isNull + case .stroked, .trimmed: + _openSwiftUIUnreachableCode() + case let .path(pathBox): + pathBox.rbPath.isEmpty + } } /// A rectangle containing all path segments. From 2299a4d04b2bc95566c36297594c1429e59543bc Mon Sep 17 00:00:00 2001 From: Kyle Date: Fri, 24 Apr 2026 00:52:20 +0800 Subject: [PATCH 02/58] Add DisplayListViewModel --- .../DisplayList/DisplayListViewModel.swift | 149 ++++++++++++++++++ .../DisplayList/DisplayListViewUpdater.swift | 73 --------- 2 files changed, 149 insertions(+), 73 deletions(-) create mode 100644 Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift new file mode 100644 index 000000000..32abf7c25 --- /dev/null +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift @@ -0,0 +1,149 @@ +// +// DisplayListViewModel.swift +// OpenSwiftUICore +// +// Audited for 6.5.4 +// Status: Complete +// ID: CA3A65C294B7CEBAC4D3EE28C528C257 (SwiftUICore) + +import OpenCoreGraphicsShims + +// MARK: - DisplayList.ViewUpdater.Model + +extension DisplayList.ViewUpdater { + enum Model { + static func merge( + item: inout DisplayList.Item, + index: DisplayList.Index, + into: inout Model.State + ) -> MergedViewRequirements { + _openSwiftUIUnimplementedFailure() + } + + // FIXME + struct MergedViewRequirements: OptionSet { + let rawValue: UInt8 + + init(rawValue: UInt8) { + self.rawValue = rawValue + } + } + + // MARK: - DisplayList.ViewUpdater.Clip + + struct Clip { + var path: Path + var transform: CGAffineTransform? + var style: FillStyle + + var isEmpty: Bool { + path.isEmpty + } + + func clipRect() -> FixedRoundedRect? { + guard transform == nil else { + return nil + } + switch path.storage { + case let .rect(rect): + return FixedRoundedRect(rect, cornerSize: .zero, style: .circular) + case let .ellipse(rect): + // OpenSwiftUI Addition: + // SwiftUI 6.5.1 Buggy implementation: guard rect.width == rect.height + // SwiftUI 7.2.5 Fixed: guard abs(rect.width - rect.height) < 0.001 + guard abs(rect.width - rect.height) < 0.001 else { + return nil + } + let radius = rect.width * 0.5 + return FixedRoundedRect(rect, cornerRadius: radius, style: .circular) + case let .roundedRect(roundedRect): + return roundedRect + default: + return nil + } + } + } + + // MARK: - DisplayList.ViewUpdater.State + + struct State { + struct Globals { + var updater: DisplayList.ViewUpdater + var time: Time + var maxVersion: DisplayList.Version + var environment: DisplayList.ViewRenderer.Environment + } + var globals: UnsafePointer + var opacity: Float = 1.0 + var blend: GraphicsBlendMode = .normal + var transform: CGAffineTransform = .identity + var clips: [Clip] = [] + var filters: [GraphicsFilter] = [] + var shadow: Indirect? + var properties: DisplayList.Properties = [] + var rewriteVibrantColorMatrix: Bool = false + var compositingGroup: Bool = false + var backdropGroupID: UInt32 = .zero + var stateHashes: [StrongHash] = [] + var platformState: PlatformState = .init() + struct Versions { + var opacity: DisplayList.Version = .init() + var blend: DisplayList.Version = .init() + var transform: DisplayList.Version = .init() + var clips: DisplayList.Version = .init() + var filters: DisplayList.Version = .init() + var shadow: DisplayList.Version = .init() + var properties: DisplayList.Version = .init() + } + var versions: Versions = .init() + + var hasDODEffects: Bool { + guard shadow == nil else { + return true + } + return filters.contains { filter in + switch filter { + case let .blur(blurStyle): + !blurStyle.isOpaque + case let .variableBlur(variableBlurStyle): + !variableBlurStyle.isOpaque + case .shadow: + true + default: + false + } + } + } + + mutating func reset() { + opacity = 1.0 + blend = .normal + transform = .identity + clips = [] + filters = [] + shadow = nil + properties = [] + stateHashes = [] + versions = .init() + } + + func clipRect() -> FixedRoundedRect? { + guard clips.count == 1, + let rect = clips[0].clipRect(), + transform.isRectilinear + else { + return nil + } + return rect.applying(transform.inverted()) + } + + fileprivate func adjust(for transform: CGAffineTransform) { + // TODO + } + + fileprivate mutating func addClip(_ path: Path, style: FillStyle) { + // TODO + } + } + } +} diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift index 7ec92cae6..fd871ba84 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift @@ -279,76 +279,3 @@ extension DisplayList.ViewUpdater { } } } - -// MARK: - DisplayList.ViewUpdater.Model [WIP] - -extension DisplayList.ViewUpdater { - enum Model { - struct Clip { - var path: Path - var transform: CGAffineTransform? - var style: FillStyle - - var isEmpty: Bool { - // TODO - false - } - } - - struct State { - struct Versions { - var opacity: DisplayList.Version - var blend: DisplayList.Version - var transform: DisplayList.Version - var clips: DisplayList.Version - var filters: DisplayList.Version - var shadow: DisplayList.Version - var properties: DisplayList.Version - } - - struct Globals { - var updater: DisplayList.ViewUpdater - var time: Time - var maxVersion: DisplayList.Version - var environment: DisplayList.ViewRenderer.Environment - } - - var globals: UnsafePointer - var opacity: Float - var blend: GraphicsBlendMode - var transform: CGAffineTransform - var clips: [Clip] - var filters: [GraphicsFilter] - var shadow: Indirect - var properties: DisplayList.Properties - var rewriteVibrantColorMatrix: Bool - var compositingGroup: Bool - var backdropGroupID: UInt32 - var stateHashes: [StrongHash] - var platformState: PlatformState - var versions: Versions - - var hasDODEffects: Bool { - // TODO - false - } - - func reset() { - // TODO - } - - func clipRect() -> FixedRoundedRect? { - // TODO - nil - } - - func adjust(for transform: CGAffineTransform) { - // TODO - } - - mutating func addClip(_ path: Path, style: FillStyle) { - // TODO - } - } - } -} From bd17d4763bd543e9419460d260b4b6fec8ce6b34 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 27 Apr 2026 23:55:05 +0800 Subject: [PATCH 03/58] Add adjust impl --- .../DisplayList/DisplayListViewModel.swift | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift index 32abf7c25..15c16221c 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift @@ -137,8 +137,28 @@ extension DisplayList.ViewUpdater { return rect.applying(transform.inverted()) } - fileprivate func adjust(for transform: CGAffineTransform) { - // TODO + fileprivate mutating func adjust(for transform: CGAffineTransform) { + guard shadow != nil || !filters.isEmpty else { + return + } + let transformedWidth = CGSize(width: 1.0, height: 1.0).applying(transform).width + guard abs(transformedWidth - 1.0) > 0.001 else { + return + } + let scale = 1.0 / transformedWidth + if let shadow { + var value = shadow.value + value.radius *= scale + value.offset *= scale + self.shadow = Indirect(value) + } + for (index, filter) in filters.enumerated() { + guard case var .blur(blurStyle) = filter else { + continue + } + blurStyle.radius *= scale + filters[index] = .blur(blurStyle) + } } fileprivate mutating func addClip(_ path: Path, style: FillStyle) { From 6ea54aef69efc94d792a5f704a2b26fea31da8eb Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 27 Apr 2026 23:58:34 +0800 Subject: [PATCH 04/58] Add addClip impl --- .../DisplayList/DisplayListViewModel.swift | 133 +++++++++++++++++- 1 file changed, 131 insertions(+), 2 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift index 15c16221c..37a3fd5b0 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift @@ -3,7 +3,7 @@ // OpenSwiftUICore // // Audited for 6.5.4 -// Status: Complete +// Status: Blocked by MergedViewRequirements // ID: CA3A65C294B7CEBAC4D3EE28C528C257 (SwiftUICore) import OpenCoreGraphicsShims @@ -162,8 +162,137 @@ extension DisplayList.ViewUpdater { } fileprivate mutating func addClip(_ path: Path, style: FillStyle) { - // TODO + guard transform.isRectilinear else { + appendClip(path, transform: transform, style: style) + return + } + switch path.storage { + case .empty: + clips = [Clip(path: path, transform: nil, style: style)] + case let .rect(rect): + appendClip( + Path(rect.applying(transform)), + transform: nil, + style: style + ) + case let .ellipse(rect): + appendClip( + Path(ellipseIn: rect.applying(transform)), + transform: nil, + style: style + ) + case let .roundedRect(roundedRect): + appendClip( + Path(storage: .roundedRect(roundedRect.applying(transform))), + transform: nil, + style: style + ) + default: + appendClip( + path, + transform: transform, + style: style + ) + } + } + + @inline(__always) + private mutating func appendClip(_ path: Path, transform: CGAffineTransform?, style: FillStyle) { + if transform == nil { + for (index, clip) in clips.enumerated() where clip.transform == nil { + var existingPath = clip.path + if existingPath.intersectRoundedRects(path) { + clips[index].path = existingPath + return + } + } + } + clips.append(Clip(path: path, transform: transform, style: style)) + } + } + } +} + +// MARK: - Path + intersectRoundedRects [WIP] + +@available(OpenSwiftUI_v1_0, *) +extension Path { + fileprivate mutating func intersectRoundedRects(_ other: Path) -> Bool { + guard let lhs = roundedRect(), let rhs = other.roundedRect() else { + return false + } + guard lhs.cornerSize != .zero || rhs.cornerSize != .zero else { + self = Path(lhs.rect.intersection(rhs.rect)) + return true + } + if lhs.cornerSize == rhs.cornerSize && lhs.style == rhs.style { + if lhs.rect.minX.approximates(rhs.rect.minX, epsilon: 0.001), + lhs.rect.width.approximates(rhs.rect.width, epsilon: 0.001) { + let minY = max(lhs.rect.minY, rhs.rect.minY) + let maxY = min(lhs.rect.maxY, rhs.rect.maxY) + guard minY < maxY else { + self = Path() + return true + } + self = Path( + roundedRect: CGRect( + x: lhs.rect.minX, + y: minY, + width: lhs.rect.width, + height: maxY - minY + ), + cornerSize: lhs.cornerSize, + style: lhs.style + ) + return true + } + if lhs.rect.minY.approximates(rhs.rect.minY, epsilon: 0.001), + lhs.rect.height.approximates(rhs.rect.height, epsilon: 0.001) { + let minX = max(lhs.rect.minX, rhs.rect.minX) + let maxX = min(lhs.rect.maxX, rhs.rect.maxX) + guard minX < maxX else { + self = Path() + return true + } + self = Path( + roundedRect: CGRect( + x: minX, + y: lhs.rect.minY, + width: maxX - minX, + height: lhs.rect.height + ), + cornerSize: lhs.cornerSize, + style: lhs.style + ) + return true } } + if lhs.contains(rhs) { + self = Path(storage: .roundedRect(rhs)) + return true + } + if rhs.contains(lhs) { + self = Path(storage: .roundedRect(lhs)) + return true + } + return false + } +} + +// MARK: - DisplayList.Item helper [WIP] + +extension DisplayList.Item { + fileprivate func rewriteVibrancyFilterAsBackdrop( + matrix: _ColorMatrix, + list: DisplayList + ) { + _openSwiftUIUnimplementedWarning() + } + + fileprivate func discardContainingClips( + state: inout DisplayList.ViewUpdater.Model.State + ) -> Bool { + _openSwiftUIUnimplementedWarning() + return false } } From 46270ceaaa0fb5807eb5084c9bf13617083264dd Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 28 Apr 2026 01:55:58 +0800 Subject: [PATCH 05/58] Optimize approximates call --- .../DisplayList/DisplayListViewModel.swift | 54 +++++++------------ 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift index 37a3fd5b0..da3c1177e 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift @@ -51,7 +51,7 @@ extension DisplayList.ViewUpdater { // OpenSwiftUI Addition: // SwiftUI 6.5.1 Buggy implementation: guard rect.width == rect.height // SwiftUI 7.2.5 Fixed: guard abs(rect.width - rect.height) < 0.001 - guard abs(rect.width - rect.height) < 0.001 else { + guard rect.width.approximates(rect.height, epsilon: 0.001) else { return nil } let radius = rect.width * 0.5 @@ -213,7 +213,7 @@ extension DisplayList.ViewUpdater { } } -// MARK: - Path + intersectRoundedRects [WIP] +// MARK: - Path + intersectRoundedRects @available(OpenSwiftUI_v1_0, *) extension Path { @@ -226,56 +226,40 @@ extension Path { return true } if lhs.cornerSize == rhs.cornerSize && lhs.style == rhs.style { - if lhs.rect.minX.approximates(rhs.rect.minX, epsilon: 0.001), + if lhs.rect.x.approximates(rhs.rect.x, epsilon: 0.001), lhs.rect.width.approximates(rhs.rect.width, epsilon: 0.001) { - let minY = max(lhs.rect.minY, rhs.rect.minY) - let maxY = min(lhs.rect.maxY, rhs.rect.maxY) - guard minY < maxY else { - self = Path() - return true - } - self = Path( - roundedRect: CGRect( - x: lhs.rect.minX, - y: minY, - width: lhs.rect.width, - height: maxY - minY - ), + let y = max(lhs.rect.y, rhs.rect.y) + let height = min(lhs.rect.y + lhs.rect.height, rhs.rect.y + rhs.rect.height) - y + let storage: Path.Storage = height > 0 ? .roundedRect(FixedRoundedRect( + CGRect(x: lhs.rect.x, y: y, width: lhs.rect.width, height: height), cornerSize: lhs.cornerSize, style: lhs.style - ) + )) : .empty + self = Path(storage: storage) return true } - if lhs.rect.minY.approximates(rhs.rect.minY, epsilon: 0.001), + if lhs.rect.y.approximates(rhs.rect.y, epsilon: 0.001), lhs.rect.height.approximates(rhs.rect.height, epsilon: 0.001) { - let minX = max(lhs.rect.minX, rhs.rect.minX) - let maxX = min(lhs.rect.maxX, rhs.rect.maxX) - guard minX < maxX else { - self = Path() - return true - } - self = Path( - roundedRect: CGRect( - x: minX, - y: lhs.rect.minY, - width: maxX - minX, - height: lhs.rect.height - ), + let x = max(lhs.rect.x, rhs.rect.x) + let width = min(lhs.rect.x + lhs.rect.width, rhs.rect.x + rhs.rect.width) - x + let storage: Path.Storage = width > 0 ? .roundedRect(FixedRoundedRect( + CGRect(x: x, y: lhs.rect.y, width: width, height: lhs.rect.height), cornerSize: lhs.cornerSize, style: lhs.style - ) + )) : .empty + self = Path(storage: storage) return true } } if lhs.contains(rhs) { self = Path(storage: .roundedRect(rhs)) return true - } - if rhs.contains(lhs) { + } else if rhs.contains(lhs) { self = Path(storage: .roundedRect(lhs)) return true + } else { + return false } - return false } } From e690bf8080108a71a883e9a2306ed0e79441634d Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 28 Apr 2026 23:03:05 +0800 Subject: [PATCH 06/58] Fix ID --- .../Render/DisplayList/DisplayListAnimations.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAnimations.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAnimations.swift index 295a63870..87ad53368 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAnimations.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAnimations.swift @@ -4,7 +4,7 @@ // // Audited for 6.5.4 // Status: Complete -// ID: B86250B2E056EB47628ECF46032DFA4C (SwiftUICore) +// ID: 25E61DBD3DDB4AD4C9A82B4C3137A7B6 (SwiftUICore) import Foundation From 17a5fde62d75c1b12f5f3357be80b4186c9a8f87 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 28 Apr 2026 23:12:26 +0800 Subject: [PATCH 07/58] Update rewriteVibrancyFilterAsBackdrop --- .../Graphic/BackdropEffect.swift | 9 ++- .../DisplayList/DisplayListViewModel.swift | 59 ++++++++++++++++--- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/Sources/OpenSwiftUICore/Graphic/BackdropEffect.swift b/Sources/OpenSwiftUICore/Graphic/BackdropEffect.swift index dad000af7..310db2f39 100644 --- a/Sources/OpenSwiftUICore/Graphic/BackdropEffect.swift +++ b/Sources/OpenSwiftUICore/Graphic/BackdropEffect.swift @@ -2,7 +2,7 @@ // BackdropEffect.swift // OpenSwiftUICore // -// Audited for 6.0.87 +// Audited for 6.5.4 // Status: WIP package struct BackdropEffect { @@ -12,7 +12,12 @@ package struct BackdropEffect { package var filters: [GraphicsFilter] - package init(scale: Float = 1, color: Color.Resolved = .black, filters: [GraphicsFilter] = [], captureOnly: Bool = false) { + package init( + scale: Float = 1, + color: Color.Resolved = .black, + filters: [GraphicsFilter] = [], + captureOnly: Bool = false + ) { self.scale = scale self.color = color self.filters = filters diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift index da3c1177e..bd9556253 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift @@ -263,20 +263,61 @@ extension Path { } } -// MARK: - DisplayList.Item helper [WIP] +// MARK: - DisplayList.Item helper extension DisplayList.Item { - fileprivate func rewriteVibrancyFilterAsBackdrop( + fileprivate mutating func rewriteVibrancyFilterAsBackdrop( matrix: _ColorMatrix, list: DisplayList ) { - _openSwiftUIUnimplementedWarning() + let backdropItem = DisplayList.Item( + .content( + DisplayList.Content( + .backdrop(BackdropEffect(color: .clear)), + seed: .init() + ) + ), + frame: CGRect(origin: .zero, size: size), + identity: .none, + version: version + ) + let filterItem = DisplayList.Item( + .effect( + .filter(.colorMatrix(matrix, premultiplied: false)), + DisplayList(backdropItem) + ), + frame: CGRect(origin: .zero, size: size), + identity: .none, + version: version + ) + value = .effect(.mask(list), DisplayList(filterItem)) } - fileprivate func discardContainingClips( - state: inout DisplayList.ViewUpdater.Model.State - ) -> Bool { - _openSwiftUIUnimplementedWarning() - return false - } + #if OPENSWIFTUI_SUPPORT_2025_API + // 7.2.5 +// fileprivate mutating func rewriteVibrancyFilterAsBackdrop( +// _ matrix: GraphicsFilter.VibrantColorMatrix, +// list: DisplayList +// ) { +// guard matrix.options == [], matrix.maxColorComponent == .inf else { +// return +// } +// let backdropItem = DisplayList.Item( +// .content(DisplayList.Content(.backdrop(BackdropEffect(color: .clear)), seed: .init())), +// frame: CGRect(origin: .zero, size: size), +// identity: .none, +// version: version +// ) +// let filterItem = DisplayList.Item( +// .effect( +// .filter(.colorMatrix(matrix, premultiplied: false)), +// DisplayList(backdropItem) +// ), +// frame: CGRect(origin: .zero, size: size), +// identity: .none, +// version: version +// ) +// value = .effect(.mask(list), DisplayList(filterItem)) +// } + #endif } From d96a6e926300f1012ac2589c39e697b53fcc6f04 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 28 Apr 2026 23:30:17 +0800 Subject: [PATCH 08/58] Add Path.boundingRect implemnentation --- Sources/OpenSwiftUICore/Shape/Path.swift | 30 +++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/Sources/OpenSwiftUICore/Shape/Path.swift b/Sources/OpenSwiftUICore/Shape/Path.swift index 40da04f7a..af3334d63 100644 --- a/Sources/OpenSwiftUICore/Shape/Path.swift +++ b/Sources/OpenSwiftUICore/Shape/Path.swift @@ -161,6 +161,21 @@ public struct Path: Equatable, LosslessStringConvertible, @unchecked Sendable { return ORBPath(storage: storage, callbacks: Self.bufferCallbacks) } } + + @inline(__always) + fileprivate var boundingRect: CGRect { + switch kind { + case .cgPath: + return data.cgPath.takeUnretainedValue().boundingBoxOfPath + case .rbPath: + _openSwiftUIUnimplementedWarning() + // return data.rbPath.boundingBox // FIXME: RB API + return .zero + case .buffer: + let storage = unsafeBitCast(self, to: ORBPath.Storage.self) + return storage.boundingRect + } + } @inline(__always) fileprivate func retainRBPath() -> ORBPath { @@ -473,7 +488,20 @@ public struct Path: Equatable, LosslessStringConvertible, @unchecked Sendable { /// in the path but not including control points for Bézier /// curves. public var boundingRect: CGRect { - _openSwiftUIUnimplementedFailure() + switch storage { + case .empty: + .null + case let .rect(rect): + rect + case let .ellipse(rect): + rect + case let .roundedRect(fixedRoundedRect): + fixedRoundedRect.rect + case .stroked, .trimmed: + _openSwiftUIUnreachableCode() + case let .path(pathBox): + pathBox.boundingRect + } } /// Returns true if the path contains a specified point. From 2281ad5789ab3d68efef8db76741e73b685a78d7 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 28 Apr 2026 23:43:11 +0800 Subject: [PATCH 09/58] Add discardContainingClips --- .../DisplayList/DisplayListViewModel.swift | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift index bd9556253..ee8748468 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift @@ -320,4 +320,88 @@ extension DisplayList.Item { // value = .effect(.mask(list), DisplayList(filterItem)) // } #endif + + fileprivate func discardContainingClips( + state: inout DisplayList.ViewUpdater.Model.State + ) -> Bool { + guard !state.clips.isEmpty else { + return true + } + guard !state.clips[0].isEmpty else { + return false + } + guard case let .content(content) = value, + state.transform.isRectilinear else { + return true + } + let inverseTransform = state.transform.inverted() + var effectOutset: CGFloat? + var index = 0 + while index < state.clips.endIndex { + guard let clipRect = state.clips[index].clipRect() else { + index &+= 1 + continue + } + var localClipRect = clipRect.applying(inverseTransform) + let sectionRect: CGRect + switch content.value { + case .backdrop, .color, .chameleonColor, .image, .text, .flattened, .drawing: + sectionRect = frame + case let .shape(path, _, _): + sectionRect = path.boundingRect.offsetBy(dx: frame.origin.x, dy: frame.origin.y) + case .shadow, .platformView, .platformLayer, .view, .placeholder: + return true + } + guard localClipRect.hasIntersection(sectionRect) else { + return false + } + let resolvedEffectOutset = effectOutset ?? state.clipDiscardEffectOutset + effectOutset = resolvedEffectOutset + if resolvedEffectOutset != 0 { + guard let insetClipRect = localClipRect.insetBy(dx: resolvedEffectOutset, dy: resolvedEffectOutset) else { + index &+= 1 + continue + } + localClipRect = insetClipRect + } + guard localClipRect.contains(rect: sectionRect) else { + index &+= 1 + continue + } + state.clips.remove(at: index) + } + return true + } +} + +// MARK: - DisplayList.ViewUpdater.Model.State helper + +extension DisplayList.ViewUpdater.Model.State { + @inline(__always) + fileprivate var clipDiscardEffectOutset: CGFloat { + var outset: CGFloat = 0 + if let shadow { + outset += shadow.value.clipDiscardOutset + } + for filter in filters { + switch filter { + case let .blur(blurStyle): + if !blurStyle.isOpaque { + outset += blurStyle.radius * 2.8 + } + default: + break + } + } + return outset + } +} + +// MARK: - ResolvedShadowStyle helper + +extension ResolvedShadowStyle { + @inline(__always) + fileprivate var clipDiscardOutset: CGFloat { + radius * 2.8 + max(abs(offset.width), abs(offset.height)) + } } From 26c7ed515f7ceaaebf39400596265d286241a7d8 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 28 Apr 2026 23:54:43 +0800 Subject: [PATCH 10/58] Update ViewUpdater.renderAsync --- .../DisplayList/DisplayListViewCache.swift | 9 +- .../DisplayList/DisplayListViewUpdater.swift | 127 +++++++----------- 2 files changed, 57 insertions(+), 79 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewCache.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewCache.swift index 178e80bd6..586d2b7af 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewCache.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewCache.swift @@ -99,6 +99,12 @@ extension DisplayList.ViewUpdater { asyncModifierGroup = nil } + @inline(__always) + mutating func clearPendingAsyncValues() { + pendingAsyncValues = [:] + pendingAsyncUpdates = [] + } + mutating func reclaim(time: Time) { removed.forEach { key in guard let info = map[key], info.isRemoved else { return } @@ -197,8 +203,7 @@ extension DisplayList.ViewUpdater { update() } // Reset state - pendingAsyncValues = [:] - pendingAsyncUpdates = [] + clearPendingAsyncValues() #else _openSwiftUIPlatformUnimplementedWarning() #endif diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift index fd871ba84..757dd4fee 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift @@ -2,7 +2,7 @@ // DisplayListViewUpdater.swift // OpenSwiftUICore // -// Audited for 6.0.87 +// Audited for 6.5.4 // Status: WIP // ID: B86250B2E056EB47628ECF46032DFA4C (SwiftUICore) @@ -82,95 +82,68 @@ extension DisplayList { version: DisplayList.Version, maxVersion: DisplayList.Version ) -> Time? { - // Phase 1: Version hash early return - let newAsyncSeed = DisplayList.Seed(version) - if newAsyncSeed == asyncSeed, lastTime >= time { + if isValid, DisplayList.Seed(version) == asyncSeed, nextUpdate >= time { return nextUpdate } - - // Phase 2: Debug print if printTree == nil { printTree = ProcessEnvironment.bool(forKey: "OPENSWIFTUI_PRINT_TREE") } if let printTree, printTree { print("Async view at \(time):\n\(list.description)") } - - // Phase 3: Save state and call updateAsync - wasValid = isValid - let oldList = viewCache.currentList - - guard let resultTime = updateAsync(oldList: oldList, newList: list) else { - // Cancelled: rollback - isValid = wasValid - return nil - } - - // Phase 4: Commit - viewCache.commitAsyncValues(targetTimestamp: targetTimestamp) - viewCache.currentList = list - asyncSeed = newAsyncSeed - lastTime = time - nextUpdate = resultTime - isValid = true - - return resultTime - } - - private func updateAsync(oldList: DisplayList, newList: DisplayList) -> Time? { - let oldItems = oldList.items - let newItems = newList.items - guard oldItems.count == newItems.count else { - return nil - } - - var nextTime: Time = .infinity - - for i in 0 ..< oldItems.count { - let oldItem = oldItems[i] - let newItem = newItems[i] - - guard oldItem.matchesTopLevelStructure(of: newItem) else { - return nil - } - - switch (oldItem.value, newItem.value) { - case let (.effect(_, oldChild), .effect(_, newChild)): - guard let childTime = updateAsync(oldList: oldChild, newList: newChild) else { - return nil - } - nextTime = min(nextTime, childTime) - case let (.states(oldStates), .states(newStates)): - guard oldStates.count == newStates.count else { - return nil - } - for j in 0 ..< oldStates.count { - let (oldHash, oldChild) = oldStates[j] - let (newHash, newChild) = newStates[j] - guard oldHash == newHash else { - return nil - } - guard let stateTime = updateAsync( - oldList: oldChild, - newList: newChild - ) else { - return nil + let newGlobals = Model.State.Globals( + updater: self, + time: time, + maxVersion: maxVersion, + environment: lastEnv + ) + let oldGlobals = Model.State.Globals( + updater: self, + time: lastTime, + maxVersion: maxVersion, + environment: lastEnv + ) + return withUnsafePointer(to: newGlobals) { newGlobalsPtr in + withUnsafePointer(to: oldGlobals) { oldGlobalsPtr in + let oldParentState = Model.State(globals: oldGlobalsPtr) + let newParentState = Model.State(globals: newGlobalsPtr) + viewCache.index = .init() + wasValid = isValid + isValid = true + let oldList = lastList + let resultTime = withUnsafePointer(to: oldParentState) { oldParentStatePtr in + withUnsafePointer(to: newParentState) { newParentStatePtr in + updateAsync( + oldList: oldList, + oldParentState: oldParentStatePtr, + newList: list, + newParentState: newParentStatePtr + ) } - nextTime = min(nextTime, stateTime) } - case (.content, .content): - // TODO: updateItemViewAsync — leaf platform view property update - if oldItem.version != newItem.version { - // Content changed but structure same — would update platform view here + guard let resultTime else { + viewCache.clearPendingAsyncValues() + isValid = wasValid + return nil } - case (.empty, .empty): - break - default: - break + viewCache.commitAsyncValues(targetTimestamp: targetTimestamp) + lastList = list + lastTime = time + asyncSeed = seed + nextUpdate = resultTime + return resultTime } } - - return nextTime + } + + private func updateAsync( + oldList: DisplayList, + oldParentState: UnsafePointer, + newList: DisplayList, + newParentState: UnsafePointer + ) -> Time? { + // FIXME + return nil } func destroy(rootView: AnyObject) { From 4fec95350d466d15623b11cc6dc7a63acc8588d5 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 28 Apr 2026 23:56:56 +0800 Subject: [PATCH 11/58] Update ViewUpdater: ViewRendererBase --- .../DisplayList/DisplayListViewUpdater.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift index 757dd4fee..17213ca11 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift @@ -38,6 +38,14 @@ extension DisplayList { self.wasValid = false } + var platform: Platform { + viewCache.platform + } + + var exportedObject: AnyObject? { + nil + } + func render( rootView: AnyObject, from list: DisplayList, @@ -147,6 +155,7 @@ extension DisplayList { } func destroy(rootView: AnyObject) { + // FIXME: Container isValid = false wasValid = false lastList = DisplayList() @@ -161,15 +170,6 @@ extension DisplayList { var viewCacheIsEmpty: Bool { viewCache.map.isEmpty } - - var platform: Platform { - viewCache.platform - } - - var exportedObject: AnyObject? { - // TODO - nil - } } } From 5c759fb28cd668d39e6780ebe997744103dfc0df Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 29 Apr 2026 00:15:16 +0800 Subject: [PATCH 12/58] Update ViewUpdater.render --- .../DisplayList/DisplayListViewCache.swift | 8 + .../DisplayList/DisplayListViewPlatform.swift | 12 +- .../DisplayList/DisplayListViewUpdater.swift | 189 +++++++++++++----- .../Util/Extension/CGSize+Extension.swift | 5 + .../Shims/QuartzCore/CALayerPrivate.h | 1 + .../Shims/QuartzCore/CALayerPrivate.m | 10 + 6 files changed, 172 insertions(+), 53 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewCache.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewCache.swift index 586d2b7af..fb7b39a3b 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewCache.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewCache.swift @@ -105,6 +105,14 @@ extension DisplayList.ViewUpdater { pendingAsyncUpdates = [] } + mutating func invalidateAll() { + map = map.mapValues { info in + var info = info + info.seeds.invalidate() + return info + } + } + mutating func reclaim(time: Time) { removed.forEach { key in guard let info = map[key], info.isRemoved else { return } diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 6a6a35f22..625dae7f9 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -79,11 +79,17 @@ extension DisplayList.ViewUpdater { var position: CGPoint var size: CGSize let kind: PlatformViewDefinition.ViewKind - var flags: ViewFlags - var platformState: Platform.PlatformState + var flags: ViewFlags = [] + var platformState: Platform.PlatformState = .init() + + mutating func reset() { + position = .infinity + size = .infinity + flags = [] + } } - struct ViewFlags { + struct ViewFlags: OptionSet { let rawValue: UInt8 } } diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift index 17213ca11..76e3d72df 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift @@ -6,13 +6,16 @@ // Status: WIP // ID: B86250B2E056EB47628ECF46032DFA4C (SwiftUICore) -private var printTree: Bool? - import Foundation +import OpenSwiftUI_SPI import OpenQuartzCoreShims +import QuartzCore_Private + +// MARK: - DisplayList.ViewUpdater [WIP] + +private var printTree: Bool? extension DisplayList { - // FIXME final package class ViewUpdater: ViewRendererBase { weak var host: (any ViewRendererHost)? var viewCache: DisplayList.ViewUpdater.ViewCache @@ -54,33 +57,76 @@ extension DisplayList { maxVersion: DisplayList.Version, environment: DisplayList.ViewRenderer.Environment ) -> Time { - viewCache.clearAsyncValues() + if environment != lastEnv { + lastEnv = environment + isValid = false + viewCache.invalidateAll() + seed = .init() + } + if isValid, DisplayList.Seed(version) == seed, nextUpdate >= time { + return nextUpdate + } + #if canImport(QuartzCore) + if lastTime == .zero { + let layer = platform.viewLayer(rootView) + layer.allowsGroupOpacity = false + layer.allowsGroupBlending = false + } + #endif + let newSeed = DisplayList.Seed(version) + seed = newSeed + asyncSeed = newSeed + wasValid = isValid + isValid = true + lastList = list + lastTime = time if printTree == nil { printTree = ProcessEnvironment.bool(forKey: "OPENSWIFTUI_PRINT_TREE") } if let printTree, printTree { print("View \(Unmanaged.passUnretained(rootView).toOpaque()) at \(time):\n\(list.description)") } - - let newSeed = DisplayList.Seed(version) - let seedChanged = newSeed != seed - let envChanged = environment != lastEnv - - wasValid = isValid - - if seedChanged || envChanged || !isValid { - // TODO: Walk display list items and create/update platform views + let globals = Model.State.Globals( + updater: self, + time: time, + maxVersion: maxVersion, + environment: lastEnv + ) + return withUnsafePointer(to: globals) { globalsPtr in + let parentState = Model.State(globals: globalsPtr) + viewCache.index = .init() viewCache.currentList = list - seed = newSeed - lastEnv = environment - isValid = true - } - - lastList = list - lastTime = time - nextUpdate = .infinity + viewCache.clearAsyncValues() + #if canImport(QuartzCore) + let layer = platform.viewLayer(rootView) + let needsLayoutOnGeometryChange = layer.needsLayoutOnGeometryChange + layer.needsLayoutOnGeometryChange = false + #endif + var container = Container(rootView: rootView, platform: viewCache.platform) + withUnsafePointer(to: parentState) { parentStatePtr in + update( + container: &container, + from: list, + parentState: parentStatePtr + ) + } + container.removeRemaining(viewCache: &viewCache) + viewCache.reclaim(time: time) + viewCache.currentList = DisplayList() + if !isValid { + container.nextTime = time + } + if let host, let observer = host.as(ViewGraphRenderObserver.self) { + observer.didRender() + } + let nextTime = container.nextTime + nextUpdate = nextTime - return nextUpdate + #if canImport(QuartzCore) + layer.needsLayoutOnGeometryChange = needsLayoutOnGeometryChange + #endif + return nextTime + } } func renderAsync( @@ -144,16 +190,6 @@ extension DisplayList { } } - private func updateAsync( - oldList: DisplayList, - oldParentState: UnsafePointer, - newList: DisplayList, - newParentState: UnsafePointer - ) -> Time? { - // FIXME - return nil - } - func destroy(rootView: AnyObject) { // FIXME: Container isValid = false @@ -170,22 +206,64 @@ extension DisplayList { var viewCacheIsEmpty: Bool { viewCache.map.isEmpty } + + private func update( + container: inout Container, + from list: DisplayList, + parentState: UnsafePointer + ) { + _openSwiftUIUnimplementedWarning() + } + + private func updateAsync( + oldList: DisplayList, + oldParentState: UnsafePointer, + newList: DisplayList, + newParentState: UnsafePointer + ) -> Time? { + _openSwiftUIUnimplementedWarning() + return nil + } + } +} + +// MARK: - DisplayList.ViewUpdater.Container [TODO] + +extension DisplayList.ViewUpdater { + // FIXME + private struct Container { + var rootView: AnyObject + var platform: Platform + var nextTime: Time + + init(rootView: AnyObject, platform: Platform) { + self.rootView = rootView + self.platform = platform + self.nextTime = .infinity + } + + mutating func removeRemaining(viewCache: inout ViewCache) { + // FIXME + _openSwiftUIUnimplementedWarning() + } } } +// MARK: - DisplayList.ViewUpdater.ViewInfo [TODO] + extension DisplayList.ViewUpdater { struct ViewInfo { struct Seeds { - var item: DisplayList.Seed - var content: DisplayList.Seed - var opacity: DisplayList.Seed - var blend: DisplayList.Seed - var transform: DisplayList.Seed - var clips: DisplayList.Seed - var filters: DisplayList.Seed - var shadow: DisplayList.Seed - var properties: DisplayList.Seed - var platformSeeds: DisplayList.ViewUpdater.PlatformViewInfo.Seeds + var item: DisplayList.Seed = .init() + var content: DisplayList.Seed = .init() + var opacity: DisplayList.Seed = .init() + var blend: DisplayList.Seed = .init() + var transform: DisplayList.Seed = .init() + var clips: DisplayList.Seed = .init() + var filters: DisplayList.Seed = .init() + var shadow: DisplayList.Seed = .init() + var properties: DisplayList.Seed = .init() + var platformSeeds: DisplayList.ViewUpdater.PlatformViewInfo.Seeds = .init() mutating func invalidate() { item.invalidate() @@ -198,6 +276,19 @@ extension DisplayList.ViewUpdater { shadow.invalidate() properties.invalidate() } + + mutating func reset() { + item = .init() + content = .init() + opacity = .init() + blend = .init() + transform = .init() + clips = .init() + filters = .init() + shadow = .init() + properties = .init() + platformSeeds = .init() + } } struct ID: Equatable { @@ -228,12 +319,7 @@ extension DisplayList.ViewUpdater { self.state = state self.id = ID(value: 0) self.parentID = ID(value: 0) - self.seeds = Seeds( - item: .init(), content: .init(), opacity: .init(), - blend: .init(), transform: .init(), clips: .init(), - filters: .init(), shadow: .init(), properties: .init(), - platformSeeds: .init() - ) + self.seeds = .init() self.cacheSeed = 0 self.isRemoved = false self.isInvalid = false @@ -247,8 +333,11 @@ extension DisplayList.ViewUpdater { _openSwiftUIUnimplementedFailure() } - func reset() { - _openSwiftUIUnimplementedFailure() + mutating func reset(platform: Platform) { + layer = platform.viewLayer(view) + seeds.reset() + state.reset() + nextUpdate = .infinity } } } diff --git a/Sources/OpenSwiftUICore/Util/Extension/CGSize+Extension.swift b/Sources/OpenSwiftUICore/Util/Extension/CGSize+Extension.swift index 6a7141f02..29e5811e9 100644 --- a/Sources/OpenSwiftUICore/Util/Extension/CGSize+Extension.swift +++ b/Sources/OpenSwiftUICore/Util/Extension/CGSize+Extension.swift @@ -113,6 +113,11 @@ extension CGSize { } extension CGSize { + @inlinable + package static var infinity: CGSize { + CGSize(width: CGFloat.infinity, height: CGFloat.infinity) + } + package static let invalidValue: CGSize = CGSize(width: Double.nan, height: Double.nan) } diff --git a/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.h b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.h index 1116dcb57..23d07971b 100644 --- a/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.h +++ b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.h @@ -22,6 +22,7 @@ typedef NSString *CALayerContentsScaling NS_TYPED_ENUM; @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) BOOL needsLayoutOnGeometryChange_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(needsLayoutOnGeometryChange); /// Private property to control contents alpha channel swizzling. /// When set to kCALayerContentsSwizzleAAAA, the alpha channel is replicated to all channels. diff --git a/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.m b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.m index 95599e258..ad57642b1 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)needsLayoutOnGeometryChange_openswiftui_safe_wrapper { + OPENSWIFTUI_SAFE_WRAPPER_IMP(BOOL, @"needsLayoutOnGeometryChange", NO); + return func(self, selector); +} + +- (void)setNeedsLayoutOnGeometryChange_openswiftui_safe_wrapper:(BOOL)needsLayout { + OPENSWIFTUI_SAFE_WRAPPER_IMP(void, @"setNeedsLayoutOnGeometryChange:", , BOOL); + func(self, selector, needsLayout); +} + - (BOOL)allowsHitTesting_openswiftui_safe_wrapper { OPENSWIFTUI_SAFE_WRAPPER_IMP(BOOL, @"allowsHitTesting", YES); return func(self, selector); From acae1c92ebaffb26c9854671d946028003df99e6 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 29 Apr 2026 00:43:39 +0800 Subject: [PATCH 13/58] Update ViewUpdater.destroy --- .../DisplayList/DisplayListViewUpdater.swift | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift index 76e3d72df..e31efd273 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift @@ -121,7 +121,6 @@ extension DisplayList { } let nextTime = container.nextTime nextUpdate = nextTime - #if canImport(QuartzCore) layer.needsLayoutOnGeometryChange = needsLayoutOnGeometryChange #endif @@ -191,16 +190,9 @@ extension DisplayList { } func destroy(rootView: AnyObject) { - // FIXME: Container - isValid = false - wasValid = false - lastList = DisplayList() - lastEnv = .invalid - seed = DisplayList.Seed() - asyncSeed = DisplayList.Seed() - nextUpdate = .infinity - viewCache.currentList = DisplayList() - viewCache.pendingAsyncUpdates.removeAll() + var container = Container(rootView: rootView, platform: viewCache.platform) + container.removeRemaining(viewCache: &viewCache) + viewCache.reclaim(time: .infinity) } var viewCacheIsEmpty: Bool { @@ -234,12 +226,16 @@ extension DisplayList.ViewUpdater { private struct Container { var rootView: AnyObject var platform: Platform + var id: ViewInfo.ID var nextTime: Time + var count: Int init(rootView: AnyObject, platform: Platform) { self.rootView = rootView self.platform = platform + self.id = .init(value: 0) self.nextTime = .infinity + self.count = 0 } mutating func removeRemaining(viewCache: inout ViewCache) { From c1c3afc2b5e64e990e0fa84db984f4dc3026a9b5 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 29 Apr 2026 00:57:04 +0800 Subject: [PATCH 14/58] Update Platform --- .../DisplayList/DisplayListViewPlatform.swift | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 625dae7f9..b6d825d68 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -119,6 +119,24 @@ extension DisplayList.ViewUpdater.Platform { _openSwiftUIPlatformUnimplementedFailure() #endif } + + @inline(__always) + package func subviews(_ view: AnyObject) -> [AnyObject] { + #if canImport(QuartzCore) + CoreViewSubviews(system: viewSystem, view: view) as [AnyObject] + #else + _openSwiftUIPlatformUnimplementedFailure() + #endif + } + + @inline(__always) + package func maskView(_ view: AnyObject) -> AnyObject? { + #if canImport(QuartzCore) + CoreViewMaskView(system: viewSystem, view: view) as AnyObject? + #else + _openSwiftUIPlatformUnimplementedFailure() + #endif + } func updateDrawingView( _ drawingView: inout AnyObject, @@ -150,13 +168,13 @@ extension DisplayList.ViewUpdater.Platform { #if canImport(Darwin) let kind = viewInfo.state.kind if kind.isContainer { - for subview in CoreViewSubviews(system: viewSystem, view: viewInfo.container) { - body(subview as AnyObject) + for subview in subviews(viewInfo.container) { + body(subview) } } if kind == .mask, - let maskView = CoreViewMaskView(system: viewSystem, view: viewInfo.view) { - for subview in CoreViewSubviews(system: viewSystem, view: maskView) { + let maskView = maskView(viewInfo.view) { + for subview in subviews(maskView) { body(subview as AnyObject) } } From c1fa4e564bb0cf6ac4c9800901a06ec2d6af32ee Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 29 Apr 2026 01:41:13 +0800 Subject: [PATCH 15/58] Update removeRemaining --- .../DisplayList/DisplayListViewPlatform.swift | 9 +++++++ .../DisplayList/DisplayListViewUpdater.swift | 25 +++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index b6d825d68..5cb1a69a3 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -129,6 +129,15 @@ extension DisplayList.ViewUpdater.Platform { #endif } + @inline(__always) + package func removeFromSuperview(_ view: AnyObject) { + #if canImport(QuartzCore) + CoreViewRemoveFromSuperview(system: viewSystem, view: view) + #else + _openSwiftUIPlatformUnimplementedFailure() + #endif + } + @inline(__always) package func maskView(_ view: AnyObject) -> AnyObject? { #if canImport(QuartzCore) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift index e31efd273..5d1bc5544 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift @@ -219,14 +219,13 @@ extension DisplayList { } } -// MARK: - DisplayList.ViewUpdater.Container [TODO] +// MARK: - DisplayList.ViewUpdater.Container extension DisplayList.ViewUpdater { - // FIXME private struct Container { var rootView: AnyObject var platform: Platform - var id: ViewInfo.ID + var id: ViewInfo.ID // FIXME var nextTime: Time var count: Int @@ -239,8 +238,24 @@ extension DisplayList.ViewUpdater { } mutating func removeRemaining(viewCache: inout ViewCache) { - // FIXME - _openSwiftUIUnimplementedWarning() + let subviews = platform.subviews(rootView) + guard count < subviews.count else { + return + } + for index in (count.. Date: Wed, 29 Apr 2026 01:56:10 +0800 Subject: [PATCH 16/58] Update DisplayList.ViewUpdater.ViewInfo --- .../DisplayList/DisplayListViewPlatform.swift | 4 +- .../DisplayList/DisplayListViewUpdater.swift | 69 ++++++++++++------- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 5cb1a69a3..020b0bd92 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -76,8 +76,8 @@ extension DisplayList.ViewUpdater { let rawValue: UInt struct State { - var position: CGPoint - var size: CGSize + var position: CGPoint = .infinity + var size: CGSize = .infinity let kind: PlatformViewDefinition.ViewKind var flags: ViewFlags = [] var platformState: Platform.PlatformState = .init() diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift index 5d1bc5544..fb3f38abb 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift @@ -260,21 +260,45 @@ extension DisplayList.ViewUpdater { } } -// MARK: - DisplayList.ViewUpdater.ViewInfo [TODO] +// MARK: - DisplayList.ViewUpdater.ViewInfo extension DisplayList.ViewUpdater { struct ViewInfo { struct Seeds { - var item: DisplayList.Seed = .init() - var content: DisplayList.Seed = .init() - var opacity: DisplayList.Seed = .init() - var blend: DisplayList.Seed = .init() - var transform: DisplayList.Seed = .init() - var clips: DisplayList.Seed = .init() - var filters: DisplayList.Seed = .init() - var shadow: DisplayList.Seed = .init() - var properties: DisplayList.Seed = .init() - var platformSeeds: DisplayList.ViewUpdater.PlatformViewInfo.Seeds = .init() + var item: DisplayList.Seed + var content: DisplayList.Seed + var opacity: DisplayList.Seed + var blend: DisplayList.Seed + var transform: DisplayList.Seed + var clips: DisplayList.Seed + var filters: DisplayList.Seed + var shadow: DisplayList.Seed + var properties: DisplayList.Seed + var platformSeeds: DisplayList.ViewUpdater.PlatformViewInfo.Seeds + + init(_ seed: DisplayList.Seed = .init()) { + item = seed + content = seed + opacity = seed + blend = seed + transform = seed + clips = seed + filters = seed + shadow = seed + properties = .init() + platformSeeds = .init() + } + + @inline(__always) + init(kind: PlatformViewDefinition.ViewKind) { + let seed: DisplayList.Seed = switch kind { + case .platformView, .platformGroup: + .undefined + default: + .init() + } + self.init(seed) + } mutating func invalidate() { item.invalidate() @@ -288,17 +312,9 @@ extension DisplayList.ViewUpdater { properties.invalidate() } + @inline(__always) mutating func reset() { - item = .init() - content = .init() - opacity = .init() - blend = .init() - transform = .init() - clips = .init() - filters = .init() - shadow = .init() - properties = .init() - platformSeeds = .init() + self = .init() } } @@ -328,9 +344,9 @@ extension DisplayList.ViewUpdater { self.layer = layer self.container = container self.state = state - self.id = ID(value: 0) - self.parentID = ID(value: 0) - self.seeds = .init() + self.id = ID(value: UniqueID().value) + self.parentID = ID(value: -1) + self.seeds = Seeds(kind: state.kind) self.cacheSeed = 0 self.isRemoved = false self.isInvalid = false @@ -341,7 +357,10 @@ extension DisplayList.ViewUpdater { platform: Platform, kind: PlatformViewDefinition.ViewKind ) { - _openSwiftUIUnimplementedFailure() + let view = platform.definition.makeView(kind: kind) + let layer = platform.viewLayer(view) + let state = Platform.State(kind: kind) + self.init(view: view, layer: layer, container: view, state: state) } mutating func reset(platform: Platform) { From eb9ae8ad2bb7c1a2da98942ad800af8fe0dc1a2d Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 30 Apr 2026 01:07:53 +0800 Subject: [PATCH 17/58] Add DisplayListAsyncLayer --- .../DisplayList/DisplayListAsyncLayer.swift | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift new file mode 100644 index 000000000..e928ec67b --- /dev/null +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift @@ -0,0 +1,117 @@ +// +// DisplayListAsyncLayer.swift +// OpenSwiftUICore +// +// Audited for 6.5.4 +// Status: Complete + +import Foundation +import OpenQuartzCoreShims + +protocol _DisplayList_ViewUpdater_AsyncLayerProperty { + associatedtype Value + + static var keyPath: String { get } + static var supportsPresentationModifier: Bool { get } + static func boxValue(_ value: Value) -> NSObject +} + +extension _DisplayList_ViewUpdater_AsyncLayerProperty { + static var supportsPresentationModifier: Bool { true } +} + +extension DisplayList.ViewUpdater { + struct AsyncLayer { + typealias Property = _DisplayList_ViewUpdater_AsyncLayerProperty + + var layer: CALayer + let cache: UnsafeMutablePointer + let kind: PlatformViewDefinition.ViewKind + let flags: DisplayList.ViewUpdater.Platform.ViewFlags + var nextUpdate: Time + var isInvalid: Bool + } +} + +// FIXME: ShapeLayerShadowHelper & ShapeLayerAsyncShadowHelper + +extension DisplayList.ViewUpdater.AsyncLayer { + @discardableResult + mutating func updateShadowStyle( + oldShadow: ResolvedShadowStyle?, + newShadow: ResolvedShadowStyle? + ) -> Bool { + switch (oldShadow, newShadow) { + case (nil, nil): + return true + case let (oldShadow?, newShadow?): + guard oldShadow.kind == newShadow.kind else { + return false + } + update(ShadowOffsetProperty.self, from: oldShadow.offset, to: newShadow.offset) + update(ShadowRadiusProperty.self, from: oldShadow.radius, to: newShadow.radius) + update(ShadowColorProperty.self, from: oldShadow.color, to: newShadow.color) + return !isInvalid + default: + return false + } + } + + private mutating func update

( + _ property: P.Type, + from oldValue: P.Value, + to newValue: P.Value + ) where P: Property, P.Value: Equatable { + guard oldValue != newValue else { + return + } + setValue(newValue, for: property) + } + + private mutating func setValue

( + _ value: P.Value, + for property: P.Type + ) where P: Property { + guard !isInvalid else { + return + } + cache.pointee.setAsyncValue( + P.boxValue(value), + for: P.keyPath, + in: layer, + usingPresentationModifier: P.supportsPresentationModifier + ) + } +} + +private struct ShadowColorProperty: DisplayList.ViewUpdater.AsyncLayer.Property { + static let keyPath = "shadowColor" + + static func boxValue(_ value: Color.Resolved) -> NSObject { + #if canImport(Darwin) + return value.cgColor as! NSObject + #else + return NSObject() + #endif + } +} + +private struct ShadowRadiusProperty: DisplayList.ViewUpdater.AsyncLayer.Property { + static let keyPath = "shadowRadius" + + static func boxValue(_ value: CGFloat) -> NSObject { + NSNumber(value: Double(value)) + } +} + +private struct ShadowOffsetProperty: DisplayList.ViewUpdater.AsyncLayer.Property { + static let keyPath = "shadowOffset" + + static func boxValue(_ value: CGSize) -> NSObject { + #if canImport(Darwin) + return NSValue(size: value) + #else + return NSObject() + #endif + } +} From fa2103c3211f6a2da3dd4ecb0db6163569e10ea5 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 6 May 2026 23:01:07 +0800 Subject: [PATCH 18/58] Fix platform API issue --- .../DisplayList/DisplayListViewCache.swift | 8 +--- .../DisplayList/DisplayListViewPlatform.swift | 41 +++++++++++++++++++ .../DisplayList/DisplayListViewRenderer.swift | 31 ++------------ 3 files changed, 47 insertions(+), 33 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewCache.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewCache.swift index fb7b39a3b..714d79a99 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewCache.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewCache.swift @@ -133,9 +133,7 @@ extension DisplayList.ViewUpdater { let newInfo = map.removeValue(forKey: key) { removeRecursively(newInfo as AnyObject) } - #if canImport(Darwin) - CoreViewRemoveFromSuperview(system: platform.viewSystem, view: view) - #endif + platform.removeFromSuperview(view) } } @@ -303,9 +301,7 @@ extension DisplayList.ViewUpdater { } if info.view !== oldView { reverseMap.removeValue(forKey: unsafeBitCast(oldView, to: OpaquePointer.self)) - #if canImport(Darwin) - CoreViewRemoveFromSuperview(system: platform.viewSystem, view: oldView) - #endif + platform.removeFromSuperview(oldView) reverseMap[unsafeBitCast(info.view, to: OpaquePointer.self)] = key #if canImport(QuartzCore) if index.archiveIdentity == .none, item.identity != .none { diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 020b0bd92..836136fb5 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -138,6 +138,47 @@ extension DisplayList.ViewUpdater.Platform { #endif } + @inline(__always) + package func addSubview(_ child: AnyObject, to parent: AnyObject, at index: Int) { + #if canImport(QuartzCore) + CoreViewAddSubview( + system: viewSystem, + parent: parent, + child: child, + index: UInt(index) + ) + #else + _openSwiftUIPlatformUnimplementedFailure() + #endif + } + + @inline(__always) + package func setFrame(_ frame: CGRect, of view: AnyObject) { + #if canImport(QuartzCore) + CoreViewSetFrame(system: viewSystem, view: view, frame: frame) + #else + _openSwiftUIPlatformUnimplementedFailure() + #endif + } + + @inline(__always) + package func frame(of view: AnyObject) -> CGRect? { + #if canImport(QuartzCore) + CoreViewGetFrame(system: viewSystem, view: view) + #else + _openSwiftUIPlatformUnimplementedFailure() + #endif + } + + @inline(__always) + package func bounds(of view: AnyObject) -> CGRect? { + #if canImport(Darwin) + view.bounds + #else + _openSwiftUIPlatformUnimplementedFailure() + #endif + } + @inline(__always) package func maskView(_ view: AnyObject) -> AnyObject? { #if canImport(QuartzCore) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewRenderer.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewRenderer.swift index b3ebcace6..556403f10 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewRenderer.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewRenderer.swift @@ -256,16 +256,7 @@ extension DisplayList { self.options = options self.renderer = DisplayList.GraphicsRenderer(platformViewMode: options.drawsPlatformViews ? .rendered(update: true) : .unsupported) self.drawingView = platform.definition.makeDrawingView(options: .init(base: .init(options))) - #if canImport(Darwin) - CoreViewAddSubview( - system: platform.viewSystem, - parent: rootView, - child: drawingView!, - index: 0 - ) - #else - _openSwiftUIPlatformUnimplementedWarning() - #endif + platform.addSubview(drawingView!, to: rootView, at: 0) } var exportedObject: AnyObject? { @@ -288,17 +279,10 @@ extension DisplayList { lastContentsScale = contentsScale seed = .init() } - #if canImport(Darwin) - let drawingViewFrame = drawingView!.frame - if let rootViewBounds = rootView.bounds, drawingViewFrame != rootViewBounds { - CoreViewSetFrame( - system: platform.viewSystem, - view: drawingView!, - frame: rootView.bounds! - ) + if platform.frame(of: drawingView!) != platform.bounds(of: rootView) { + platform.setFrame(platform.bounds(of: rootView)!, of: drawingView!) seed = .init() } - #endif let newSeed = DisplayList.Seed(version) if newSeed == seed, renderer.nextTime >= time { return renderer.nextTime @@ -352,14 +336,7 @@ extension DisplayList { } func destroy(rootView: AnyObject) { - #if canImport(Darwin) - CoreViewRemoveFromSuperview( - system: platform.viewSystem, - view: drawingView! - ) - #else - _openSwiftUIPlatformUnimplementedWarning() - #endif + platform.removeFromSuperview(drawingView!) } var viewCacheIsEmpty: Bool { From f8e1e76ac04692a0656e39930790198ec0742aab Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 6 May 2026 23:11:54 +0800 Subject: [PATCH 19/58] Fix compiler issue --- .../Render/DisplayList/DisplayListAsyncLayer.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift index e928ec67b..e6260df77 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift @@ -109,7 +109,9 @@ private struct ShadowOffsetProperty: DisplayList.ViewUpdater.AsyncLayer.Property static func boxValue(_ value: CGSize) -> NSObject { #if canImport(Darwin) - return NSValue(size: value) +// return NSValue(size: value) + // FIXME + return NSObject() #else return NSObject() #endif From e6ee47dace0b593fc4793cfade6eedfc3b27f451 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 6 May 2026 23:36:57 +0800 Subject: [PATCH 20/58] Implement DisplayList index skip helpers --- .../Render/DisplayList/DisplayList.swift | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift index a01bfff14..53942b51b 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift @@ -399,16 +399,37 @@ extension DisplayList { } package mutating func skip(list: DisplayList) { - _openSwiftUIUnimplementedFailure() + for item in list.items { + skip(item: item) + } } package mutating func skip(item: Item) { - _openSwiftUIUnimplementedFailure() + guard item.identity == .none else { return } + let saved = enter(identity: item.identity) + defer { leave(index: saved) } + switch item.value { + case let .content(content): + if case let .flattened(list, _, _) = content.value { + skip(list: list) + } + case let .effect(effect, list): + skip(list: list) + skip(effect: effect) + default: + break + } } package mutating func skip(effect: Effect) { - - _openSwiftUIUnimplementedFailure() + switch effect { + case let .archive(archiveIDs): + updateArchive(entering: archiveIDs != nil) + case let .mask(list, _): + skip(list: list) + default: + break + } } package func assertItem(_ item: Item) {} From bf048e3f0c3d1510a84e0676cdd729ef04dd6abc Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 6 May 2026 23:57:22 +0800 Subject: [PATCH 21/58] Implement ViewUpdater.update --- .../DisplayList/DisplayListViewUpdater.swift | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift index fb3f38abb..bf79a2a96 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift @@ -204,7 +204,20 @@ extension DisplayList { from list: DisplayList, parentState: UnsafePointer ) { - _openSwiftUIUnimplementedWarning() + guard !list.items.isEmpty else { + return + } + for var item in list.items { + let savedIndex = viewCache.index.enter(identity: item.identity) + defer { viewCache.index.leave(index: savedIndex) } + let nextTime = viewCache.prepare(item: &item, parentState: parentState) + container.nextTime = min(container.nextTime, nextTime) + updateInheritedView( + container: &container, + from: item, + parentState: parentState + ) + } } private func updateAsync( From 05725f13320be8e20b2569532f081d25e1cde18f Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 7 May 2026 00:24:24 +0800 Subject: [PATCH 22/58] Fix OpenSwiftUISymbolDualTestsSupport import issue --- .../Integration/Hosting/UIKit/View/UIHostingView.swift | 2 ++ Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift | 2 ++ Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift | 2 ++ 3 files changed, 6 insertions(+) diff --git a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift index 823a95eab..90e49a971 100644 --- a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift +++ b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift @@ -12,7 +12,9 @@ import OpenAttributeGraphShims @_spi(ForOpenSwiftUIOnly) @_spi(Private) public import OpenSwiftUICore +#if _OPENSWIFTUI_SWIFTUI_RENDER import OpenSwiftUISymbolDualTestsSupport +#endif import COpenSwiftUI /// A UIView which hosts an OpenSwiftUI View hierarchy. diff --git a/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift b/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift index 0699156b7..4e8d16410 100644 --- a/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift +++ b/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift @@ -11,7 +11,9 @@ @_spi(DisplayList_ViewSystem) import OpenSwiftUICore import AppKit +#if _OPENSWIFTUI_SWIFTUI_RENDER import OpenSwiftUISymbolDualTestsSupport +#endif import COpenSwiftUI import QuartzCore_Private import OpenRenderBoxShims diff --git a/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift b/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift index c022482c9..164aa721b 100644 --- a/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift +++ b/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift @@ -10,7 +10,9 @@ import COpenSwiftUI @_spi(DisplayList_ViewSystem) import OpenSwiftUICore import UIKit +#if _OPENSWIFTUI_SWIFTUI_RENDER import OpenSwiftUISymbolDualTestsSupport +#endif import QuartzCore_Private import OpenRenderBoxShims import OpenSwiftUI_SPI From 563f250f24d41d6f82453254e05095030537ccd6 Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 7 May 2026 01:06:02 +0800 Subject: [PATCH 23/58] Match DisplayList item structure checks --- .../Render/DisplayList/DisplayList.swift | 15 +- .../Render/DisplayList/DisplayListTests.swift | 141 ++++++++++++++++++ 2 files changed, 148 insertions(+), 8 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift index 53942b51b..1572acd9a 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift @@ -503,18 +503,17 @@ extension DisplayList.Item { // TODO eg. .opacity(1.0) -> .identity } - // TBA package func matchesTopLevelStructure(of other: DisplayList.Item) -> Bool { - guard identity == other.identity else { return false } switch (value, other.value) { case (.empty, .empty): return true - case (.content, .content): - return true - case (.effect, .effect): - return true - case (.states, .states): - return true + case let (.content(lhs), .content(rhs)): + return compareEnumTags(lhs.value, rhs.value) + case let (.effect(lhs, _), .effect(rhs, _)): + return compareEnumTags(lhs, rhs) + case let (.states(lhs), .states(rhs)): + guard lhs.count == rhs.count else { return false } + return zip(lhs, rhs).allSatisfy { $0.0 == $1.0 } default: return false } diff --git a/Tests/OpenSwiftUICoreTests/Render/DisplayList/DisplayListTests.swift b/Tests/OpenSwiftUICoreTests/Render/DisplayList/DisplayListTests.swift index d58ff17f4..d809d6bbf 100644 --- a/Tests/OpenSwiftUICoreTests/Render/DisplayList/DisplayListTests.swift +++ b/Tests/OpenSwiftUICoreTests/Render/DisplayList/DisplayListTests.swift @@ -7,6 +7,7 @@ import OpenSwiftUICore import Testing @MainActor +@Suite struct DisplayListTests { @Test func version() { @@ -24,4 +25,144 @@ struct DisplayListTests { combineVersion.combine(with: v1) #expect(combineVersion.value == 999) } + + @Suite + struct DisplayListItemMatchesTopLevelStructureTests { + enum TestCase { + case emptyWithDifferentIdentity + case sameColorContent + case samePlaceholderContent + case differentContentKinds + case sameOpacityEffect + case sameStateEffect + case differentEffectKinds + case sameStateKeys + case reorderedStateKeys + case shorterStateKeys + case differentItemKinds + } + + private func itemStructureFixture( + for testCase: TestCase + ) -> (lhs: DisplayList.Item, rhs: DisplayList.Item, expected: Bool) { + func item( + _ value: DisplayList.Item.Value, + identity: DisplayList.Identity = .init(decodedValue: 1) + ) -> DisplayList.Item { + DisplayList.Item( + value, + frame: .zero, + identity: identity, + version: .init(decodedValue: 0) + ) + } + + let redContent = item(.content(.init( + .color(.init(red: 1, green: 0, blue: 0, opacity: 1)), + seed: .init(decodedValue: 1) + ))) + let greenContent = item(.content(.init( + .color(.init(red: 0, green: 1, blue: 0, opacity: 1)), + seed: .init(decodedValue: 2) + ))) + let placeholder1 = item(.content(.init( + .placeholder(id: .init(decodedValue: 1)), + seed: .init(decodedValue: 1) + ))) + let placeholder2 = item(.content(.init( + .placeholder(id: .init(decodedValue: 2)), + seed: .init(decodedValue: 2) + ))) + let key1 = StrongHash(of: 1) + let key2 = StrongHash(of: 2) + + switch testCase { + case .emptyWithDifferentIdentity: + return ( + item(.empty), + item(.empty, identity: .init(decodedValue: 2)), + true + ) + case .sameColorContent: + return (redContent, greenContent, true) + case .samePlaceholderContent: + return (placeholder1, placeholder2, true) + case .differentContentKinds: + return (redContent, placeholder1, false) + case .sameOpacityEffect: + return ( + item(.effect(.opacity(1), .init())), + item(.effect(.opacity(0.5), DisplayList(redContent))), + true + ) + case .sameStateEffect: + return ( + item(.effect(.state(StrongHash(of: 1)), .init())), + item(.effect(.state(StrongHash(of: 2)), DisplayList(redContent))), + true + ) + case .differentEffectKinds: + return ( + item(.effect(.opacity(1), .init())), + item(.effect(.identity, .init())), + false + ) + case .sameStateKeys: + return ( + item(.states([ + (key1, .init()), + (key2, DisplayList(redContent)), + ])), + item(.states([ + (key1, DisplayList(placeholder1)), + (key2, .init()), + ])), + true + ) + case .reorderedStateKeys: + return ( + item(.states([ + (key1, .init()), + (key2, DisplayList(redContent)), + ])), + item(.states([ + (key2, .init()), + (key1, DisplayList(redContent)), + ])), + false + ) + case .shorterStateKeys: + return ( + item(.states([ + (key1, .init()), + (key2, DisplayList(redContent)), + ])), + item(.states([ + (key1, .init()), + ])), + false + ) + case .differentItemKinds: + return (item(.empty), redContent, false) + } + } + + @Test(arguments: [ + TestCase.emptyWithDifferentIdentity, + .sameColorContent, + .samePlaceholderContent, + .differentContentKinds, + .sameOpacityEffect, + .sameStateEffect, + .differentEffectKinds, + .sameStateKeys, + .reorderedStateKeys, + .shorterStateKeys, + .differentItemKinds, + ]) + func itemMatchesTopLevelStructure(_ testCase: TestCase) { + let fixture = itemStructureFixture(for: testCase) + #expect(fixture.lhs.matchesTopLevelStructure(of: fixture.rhs) == fixture.expected) + } + } } From cbac89c342396ddc5ba265dbd1107906fce96dff Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 7 May 2026 23:04:20 +0800 Subject: [PATCH 24/58] Implement DisplayList.Item.features --- .../Render/DisplayList/DisplayList.swift | 73 ++++++++++++++++++- .../View/Text/Text/Text+View.swift | 13 +++- .../View/Text/Util/String+Extension.swift | 4 + 3 files changed, 82 insertions(+), 8 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift index 1572acd9a..178cfc82c 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift @@ -178,10 +178,28 @@ extension DisplayList { indirect case view(any _DisplayList_ViewFactory) case placeholder(id: Identity) } + package init(_ value: Content.Value, seed: Seed) { self.value = value self.seed = seed } + + @inline(__always) + var features: DisplayList.Features { + switch value { + case let .platformView(factory): + return factory.features + case let .text(view, _): + let resolved = view.text + return resolved.isDynamic && resolved.archiveOptions.isArchived ? .dynamicContent : [] + case let .flattened(list, _, _): + return list.features.union(.flattened) + case .view, .placeholder: + return .views + default: + return [] + } + } } package typealias ViewFactory = _DisplayList_ViewFactory @@ -209,8 +227,34 @@ extension DisplayList { indirect case interpolatorRoot(InterpolatorGroup, contentOrigin: CGPoint, contentOffset: CGSize) case interpolatorLayer(InterpolatorGroup, serial: UInt32) indirect case interpolatorAnimation(InterpolatorAnimation) - } + @inline(__always) + var features: DisplayList.Features { + switch self { + case let .properties(properties): + return properties.features + case let .platformGroup(factory): + return factory.features + case .mask(let list, _): + return list.features + case .animation: + return .animations + case .view: + return .views + case let .platform(platformEffect): + return platformEffect.features + case .state: + return .stateEffects + case .interpolatorRoot: + return .interpolatorRoots + case let .interpolatorLayer(group, _): + return group.features.union([.interpolatorLayers, .required]) + default: + return [] + } + } + } + package enum Transform { case affine(CGAffineTransform) case projection(ProjectionTransform) @@ -299,9 +343,11 @@ extension DisplayList { package struct Properties: OptionSet { package let rawValue: UInt8 + package init(rawValue: UInt8) { self.rawValue = rawValue } + package static let foregroundLayer = Properties(rawValue: 1 << 0) package static let ignoresEvents = Properties(rawValue: 1 << 1) package static let privacySensitive = Properties(rawValue: 1 << 2) @@ -310,6 +356,11 @@ extension DisplayList { package static let tertiaryForegroundLayer = Properties(rawValue: 1 << 5) package static let quaternaryForegroundLayer = Properties(rawValue: 1 << 6) package static let screencaptureProhibited = Properties(rawValue: 1 << 7) + + @inline(__always) + var features: DisplayList.Features { + contains(.privacySensitive) ? .required : [] + } } package struct Key: PreferenceKey { @@ -518,10 +569,20 @@ extension DisplayList.Item { return false } } - + package var features: DisplayList.Features { - // TODO - [] + switch value { + case .empty: + return [] + case let .content(content): + return content.features + case let .effect(effect, list): + return effect.features.union(list.features) + case let .states(states): + return states.reduce(into: [.states]) { features, state in + features.formUnion(state.1.features) + } + } } } @@ -572,6 +633,10 @@ extension DisplayList { _openSwiftUIEmptyStub() } + var features: Features { + [] + } + func rewriteDisplayList( _ list: inout DisplayList, time: Attribute

(_ paint: P) where P: ResolvedPaint { + _openSwiftUIUnimplementedFailure() + } +} diff --git a/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.h b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.h index b3b720d75..03285321d 100644 --- a/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.h +++ b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.h @@ -24,6 +24,7 @@ typedef NSString *CALayerContentsScaling NS_TYPED_ENUM; @property (nonatomic, assign) BOOL allowsHitTesting_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(allowsHitTesting); @property (nonatomic, assign) BOOL needsLayoutOnGeometryChange_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(needsLayoutOnGeometryChange); @property (nonatomic, assign) uint32_t disableUpdateMask_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(disableUpdateMask); +@property (nonatomic, assign) BOOL shadowPathIsBounds_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(shadowPathIsBounds); /// Private property to control contents alpha channel swizzling. /// When set to kCALayerContentsSwizzleAAAA, the alpha channel is replicated to all channels. diff --git a/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.m b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.m index 098c8dff5..ede41df9d 100644 --- a/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.m +++ b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CALayerPrivate.m @@ -61,6 +61,16 @@ - (void)setDisableUpdateMask_openswiftui_safe_wrapper:(uint32_t)mask { func(self, selector, mask); } +- (BOOL)shadowPathIsBounds_openswiftui_safe_wrapper { + OPENSWIFTUI_SAFE_WRAPPER_IMP(BOOL, @"shadowPathIsBounds", NO); + return func(self, selector); +} + +- (void)setShadowPathIsBounds_openswiftui_safe_wrapper:(BOOL)value { + OPENSWIFTUI_SAFE_WRAPPER_IMP(void, @"setShadowPathIsBounds:", , BOOL); + func(self, selector, value); +} + - (BOOL)allowsHitTesting_openswiftui_safe_wrapper { OPENSWIFTUI_SAFE_WRAPPER_IMP(BOOL, @"allowsHitTesting", YES); return func(self, selector); From b7f4b9773ee4ab5e63e216919ae5ed6f96d5aa45 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 13 May 2026 01:44:34 +0800 Subject: [PATCH 45/58] Update Platform.updateDrawingViewAsync --- .../DisplayList/DisplayListViewPlatform.swift | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 7a102c871..caef0dcdc 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -91,6 +91,8 @@ extension DisplayList.ViewUpdater { struct ViewFlags: OptionSet { let rawValue: UInt8 + + static var _3: ViewFlags { .init(rawValue: 1 << 3) } } } } @@ -390,7 +392,7 @@ extension DisplayList.ViewUpdater.Platform { } private func updateDrawingViewAsync( - _ layer: inout DisplayList.ViewUpdater.AsyncLayer, + _ asyncLayer: inout DisplayList.ViewUpdater.AsyncLayer, oldOptions: RasterizationOptions, newOptions: RasterizationOptions, content: PlatformDrawableContent.Storage, @@ -398,7 +400,30 @@ extension DisplayList.ViewUpdater.Platform { newSize: CGSize, newState: UnsafePointer ) -> Bool { - _openSwiftUIUnimplementedFailure() + guard oldOptions == newOptions, + let delegate = asyncLayer.layer.delegate, + let drawable = delegate as? PlatformDrawable + else { + return false + } + let bounds: CGRect + if asyncLayer.flags.contains(._3), let clipRect = newState.pointee.clipRect() { + bounds = clipRect.rect + } else { + bounds = CGRect(origin: .zero, size: newSize) + } + var drawableContent = PlatformDrawableContent() + drawableContent.storage = content + guard let update = drawable.makeAsyncUpdate( + content: drawableContent, + required: sizeChanged, + layer: asyncLayer.layer, + bounds: bounds + ) else { + return false + } + asyncLayer.cache.pointee.pendingAsyncUpdates.append(update) + return true } private func updateClipShapes( @@ -444,7 +469,7 @@ extension DisplayList.ViewUpdater.Platform { } private func updateClipShapesAsync( - layer: inout DisplayList.ViewUpdater.AsyncLayer, + asyncLayer: inout DisplayList.ViewUpdater.AsyncLayer, oldState: UnsafePointer, newState: UnsafePointer ) -> Bool { @@ -452,7 +477,7 @@ extension DisplayList.ViewUpdater.Platform { } private func updateGeometryAsync( - layer: inout DisplayList.ViewUpdater.AsyncLayer, + asyncLayer: inout DisplayList.ViewUpdater.AsyncLayer, oldItem: DisplayList.Item, oldSize: CGSize, oldState: UnsafePointer, @@ -464,7 +489,7 @@ extension DisplayList.ViewUpdater.Platform { } private func updateShadowAsync( - layer: inout DisplayList.ViewUpdater.AsyncLayer, + asyncLayer: inout DisplayList.ViewUpdater.AsyncLayer, oldState: UnsafePointer, oldItem: DisplayList.Item, newState: UnsafePointer, From 653663ffbe2efff68f42f3d03acdb092cb1d30e2 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 13 May 2026 23:03:32 +0800 Subject: [PATCH 46/58] Update Platform.updateClipShapes --- .../DisplayList/DisplayListViewModel.swift | 2 +- .../DisplayList/DisplayListViewPlatform.swift | 55 ++++++++++++++++++- .../QuartzCore/CALayer+OpenSwiftUIAdditions.h | 2 +- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift index 07e462eff..1f4d0bc46 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift @@ -228,7 +228,7 @@ extension DisplayList.ViewUpdater { // MARK: - DisplayList.ViewUpdater.Clip - struct Clip { + struct Clip: Equatable { var path: Path var transform: CGAffineTransform? var style: FillStyle diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index caef0dcdc..eb3fc4d0b 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -7,6 +7,7 @@ // ID: 8BBC66CBE42B8A65F8A2F3799C81A349 (SwiftUICore) public import OpenQuartzCoreShims +import Foundation import OpenSwiftUI_SPI // MARK: - PlatformViewDefinition @@ -89,10 +90,12 @@ extension DisplayList.ViewUpdater { } } + // TODO: Optimize the case name and add inline helper in State to do contains/insert/remove logic struct ViewFlags: OptionSet { let rawValue: UInt8 static var _3: ViewFlags { .init(rawValue: 1 << 3) } + static var _4: ViewFlags { .init(rawValue: 1 << 4) } } } } @@ -430,7 +433,57 @@ extension DisplayList.ViewUpdater.Platform { _ viewInfo: inout DisplayList.ViewUpdater.ViewInfo, state: UnsafePointer ) { - _openSwiftUIUnimplementedFailure() + #if canImport(QuartzCore) + if let clipRect = state.pointee.clipRect() { + setClipsToBounds(true, of: viewInfo.view, onLayer: false) + let layer = viewInfo.layer + layer.cornerRadius = clipRect.clampedCornerRadius + layer.cornerCurve = clipRect.style == .continuous ? .continuous : .circular + viewInfo.state.flags.insert(._3) + if viewInfo.state.flags.contains(._4) { + layer.mask = nil + viewInfo.state.flags.remove(._4) + } + + } else { + if viewInfo.state.flags.contains(._3) { + viewInfo.state.flags.remove(._3) + setClipsToBounds(false, of: viewInfo.view, onLayer: false) + let layer = viewInfo.layer + var bounds = layer.bounds + bounds.origin = .zero + layer.bounds = bounds + layer.cornerRadius = 0 + layer.cornerCurve = .circular + } + let clips = state.pointee.clips + guard !clips.isEmpty else { + if viewInfo.state.flags.contains(._4) { + let layer = viewInfo.layer + layer.mask = nil + viewInfo.state.flags.remove(._4) + } + return + } + let layer = viewInfo.layer + let maskLayer: MaskLayer + if let mask = layer.mask as? MaskLayer { + maskLayer = mask + } else { + maskLayer = MaskLayer() + maskLayer.anchorPoint = .zero + maskLayer.setNoAnimationDelegate() + layer.mask = maskLayer + } + viewInfo.state.flags.insert(._4) + let transform = state.pointee.transform.inverted() + if maskLayer.clips != clips || maskLayer.clipTransform != transform { + maskLayer.setClips(clips, transform: transform) + } + } + #else + _openSwiftUIPlatformUnimplementedWarning() + #endif } private func updateGeometry( diff --git a/Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CALayer+OpenSwiftUIAdditions.h b/Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CALayer+OpenSwiftUIAdditions.h index 86e580618..a34d2567c 100644 --- a/Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CALayer+OpenSwiftUIAdditions.h +++ b/Sources/OpenSwiftUI_SPI/Overlay/QuartzCore/CALayer+OpenSwiftUIAdditions.h @@ -22,7 +22,7 @@ @property (nonatomic, assign) int64_t openSwiftUI_displayListID; -- (void)openSwiftUI_setNoAnimationDelegate; +- (void)openSwiftUI_setNoAnimationDelegate OPENSWIFTUI_SWIFT_NAME(setNoAnimationDelegate()); @end From 89d72725853a7bb04c2732a90be0042d36e6e6d0 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 13 May 2026 23:14:02 +0800 Subject: [PATCH 47/58] Add MaskLayer implementation --- Sources/OpenSwiftUICore/Shape/MaskLayer.swift | 117 ++++++++++++++++++ .../OpenSwiftUICore/Shape/ShapeLayer.swift | 30 +++++ 2 files changed, 147 insertions(+) create mode 100644 Sources/OpenSwiftUICore/Shape/MaskLayer.swift diff --git a/Sources/OpenSwiftUICore/Shape/MaskLayer.swift b/Sources/OpenSwiftUICore/Shape/MaskLayer.swift new file mode 100644 index 000000000..fbafcbc53 --- /dev/null +++ b/Sources/OpenSwiftUICore/Shape/MaskLayer.swift @@ -0,0 +1,117 @@ +// +// MaskLayer.swift +// OpenSwiftUICore +// +// Audited for 6.5.4 +// Status: WIP (Async) +// ID: A60BC6C4EC21A2F308B4F151783AE2A3 (SwiftUICore) + +import Foundation +import OpenQuartzCoreShims +import OpenSwiftUI_SPI + +#if canImport(QuartzCore) + +// MARK: - MaskLayer + +final class MaskLayer: CAShapeLayer { + var clips: [DisplayList.ViewUpdater.Model.Clip] = [] + var clipTransform: CGAffineTransform = .init() + + override init() { + super.init() + } + + override init(layer: Any) { + super.init(layer: layer) + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + } + + func setClips(_ clips: [DisplayList.ViewUpdater.Model.Clip], transform: CGAffineTransform) { + self.clips = clips + clipTransform = transform + switch clips.count { + case 0: + path = nil + sublayers = [] + case 1: + Self.update(layer: self, clip: clips[0], transform: transform) + sublayers = [] + default: + path = nil + var newSublayers = sublayers ?? [] + var sublayersChanged = false + for (index, clip) in clips.enumerated() { + let layer: CAShapeLayer + if index < newSublayers.count { + layer = newSublayers[index] as! CAShapeLayer + } else { + layer = CAShapeLayer() + layer.anchorPoint = .zero + layer.setNoAnimationDelegate() + newSublayers.append(layer) + sublayersChanged = true + } + Self.update(layer: layer, clip: clip, transform: transform) + layer.compositingFilter = index == 0 ? nil : "sourceIn" + } + if newSublayers.count > clips.count { + newSublayers.removeSubrange(clips.count.. +// ) { +// _openSwiftUIUnimplementedFailure() +// } +// +// private func initFromStroked( +// type: ORBPathShapeType, +// shape: UnsafePointer, +// style: StrokeStyle +// ) { +// _openSwiftUIUnimplementedFailure() +// } +} From 402ee19c1aae78677bab803633642647c101e47b Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 13 May 2026 23:35:15 +0800 Subject: [PATCH 48/58] Update Transform.transform API --- .../Render/DisplayList/DisplayList.swift | 24 +++++++++++++++++++ .../DisplayList/DisplayListViewModel.swift | 20 +++------------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift index 178cfc82c..07cf0055c 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift @@ -260,6 +260,30 @@ extension DisplayList { case projection(ProjectionTransform) case rotation(_RotationEffect.Data) case rotation3D(_Rotation3DEffect.Data) + + @inline(__always) + package var affineTransform: CGAffineTransform? { + switch self { + case let .affine(transform): + return transform + case let .rotation(data): + return data.transform + case .projection, .rotation3D: + return nil + } + } + + @inline(__always) + package var projectionTransform: ProjectionTransform? { + switch self { + case let .projection(transform): + return transform + case let .rotation3D(data): + return data.transform + case .affine, .rotation: + return nil + } + } } package typealias AnyEffectAnimation = _DisplayList_AnyEffectAnimation diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift index 1f4d0bc46..19b47c137 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewModel.swift @@ -503,16 +503,10 @@ extension DisplayList.Item { case .platformGroup, .mask: return false case let .transform(transform): - switch transform { - case let .affine(transform): - return transform == .identity - case .projection: - return false - case let .rotation(data): - return data.transform == .identity - case .rotation3D: + guard let affineTransform = transform.affineTransform else { return false } + return affineTransform == .identity case .animation, .view: _openSwiftUIUnreachableCode() default: @@ -602,15 +596,7 @@ extension DisplayList.Item { case .clip, .platformGroup, .mask: return false case let .transform(transform): - let affineTransform: CGAffineTransform - switch transform { - case let .affine(transform): - affineTransform = transform - case .projection: - return false - case let .rotation(data): - affineTransform = data.transform - case .rotation3D: + guard let affineTransform = transform.affineTransform else { return false } return affineTransform.isUniform From d17dd5494c4ff9dadc232a5abe7b7884d488bf2e Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 14 May 2026 00:16:50 +0800 Subject: [PATCH 49/58] Add CABackdropLayer --- .../DisplayList/DisplayListViewPlatform.swift | 5 +++-- .../DisplayList/DisplayListViewUpdater.swift | 2 ++ .../Shims/QuartzCore/CABackdropLayer.h | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CABackdropLayer.h diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index eb3fc4d0b..c30307c58 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -9,6 +9,9 @@ public import OpenQuartzCoreShims import Foundation import OpenSwiftUI_SPI +#if canImport(QuartzCore) +import QuartzCore_Private +#endif // MARK: - PlatformViewDefinition @@ -57,9 +60,7 @@ open class PlatformViewDefinition: @unchecked Sendable { open class func makeView(kind: PlatformViewDefinition.ViewKind, item: Any) -> AnyObject { _openSwiftUIBaseClassAbstractMethod() } #endif open class func makeView(kind: PlatformViewDefinition.ViewKind) -> AnyObject { _openSwiftUIBaseClassAbstractMethod() } - #if canImport(Darwin) open class func makeLayerView(type: CALayer.Type, kind: PlatformViewDefinition.ViewKind) -> AnyObject { _openSwiftUIBaseClassAbstractMethod() } - #endif open class func makePlatformView(view: AnyObject, kind: PlatformViewDefinition.ViewKind) { _openSwiftUIBaseClassAbstractMethod() } open class func makeDrawingView(options: PlatformDrawableOptions) -> any PlatformDrawable { _openSwiftUIBaseClassAbstractMethod() } open class func setPath(_ path: Path, shapeView: AnyObject) { _openSwiftUIBaseClassAbstractMethod() } diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift index 1751a69de..8a2040ebf 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewUpdater.swift @@ -9,7 +9,9 @@ import Foundation import OpenSwiftUI_SPI import OpenQuartzCoreShims +#if canImport(QuartzCore) import QuartzCore_Private +#endif // MARK: - DisplayList.ViewUpdater diff --git a/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CABackdropLayer.h b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CABackdropLayer.h new file mode 100644 index 000000000..95326c8cf --- /dev/null +++ b/Sources/OpenSwiftUI_SPI/Shims/QuartzCore/CABackdropLayer.h @@ -0,0 +1,16 @@ +// CABackdropLayer.h +// OpenSwiftUI_SPI + +#ifndef CABackdropLayer_h +#define CABackdropLayer_h + +#if __has_include() + +#import + +@interface CABackdropLayer : CALayer +@end + +#endif /* __has_include() */ + +#endif /* CABackdropLayer_h */ From 78da05602d9dc9d5a19525e5971a4efa13522892 Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 14 May 2026 00:16:56 +0800 Subject: [PATCH 50/58] Update ShapeLayer API --- .../DisplayList/DisplayListAsyncLayer.swift | 85 ----------- .../OpenSwiftUICore/Shape/ShapeLayer.swift | 142 +++++++++++++++++- 2 files changed, 141 insertions(+), 86 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift index e6260df77..238fe99f5 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift @@ -32,88 +32,3 @@ extension DisplayList.ViewUpdater { var isInvalid: Bool } } - -// FIXME: ShapeLayerShadowHelper & ShapeLayerAsyncShadowHelper - -extension DisplayList.ViewUpdater.AsyncLayer { - @discardableResult - mutating func updateShadowStyle( - oldShadow: ResolvedShadowStyle?, - newShadow: ResolvedShadowStyle? - ) -> Bool { - switch (oldShadow, newShadow) { - case (nil, nil): - return true - case let (oldShadow?, newShadow?): - guard oldShadow.kind == newShadow.kind else { - return false - } - update(ShadowOffsetProperty.self, from: oldShadow.offset, to: newShadow.offset) - update(ShadowRadiusProperty.self, from: oldShadow.radius, to: newShadow.radius) - update(ShadowColorProperty.self, from: oldShadow.color, to: newShadow.color) - return !isInvalid - default: - return false - } - } - - private mutating func update

( - _ property: P.Type, - from oldValue: P.Value, - to newValue: P.Value - ) where P: Property, P.Value: Equatable { - guard oldValue != newValue else { - return - } - setValue(newValue, for: property) - } - - private mutating func setValue

( - _ value: P.Value, - for property: P.Type - ) where P: Property { - guard !isInvalid else { - return - } - cache.pointee.setAsyncValue( - P.boxValue(value), - for: P.keyPath, - in: layer, - usingPresentationModifier: P.supportsPresentationModifier - ) - } -} - -private struct ShadowColorProperty: DisplayList.ViewUpdater.AsyncLayer.Property { - static let keyPath = "shadowColor" - - static func boxValue(_ value: Color.Resolved) -> NSObject { - #if canImport(Darwin) - return value.cgColor as! NSObject - #else - return NSObject() - #endif - } -} - -private struct ShadowRadiusProperty: DisplayList.ViewUpdater.AsyncLayer.Property { - static let keyPath = "shadowRadius" - - static func boxValue(_ value: CGFloat) -> NSObject { - NSNumber(value: Double(value)) - } -} - -private struct ShadowOffsetProperty: DisplayList.ViewUpdater.AsyncLayer.Property { - static let keyPath = "shadowOffset" - - static func boxValue(_ value: CGSize) -> NSObject { - #if canImport(Darwin) -// return NSValue(size: value) - // FIXME - return NSObject() - #else - return NSObject() - #endif - } -} diff --git a/Sources/OpenSwiftUICore/Shape/ShapeLayer.swift b/Sources/OpenSwiftUICore/Shape/ShapeLayer.swift index f40bdbf66..482491658 100644 --- a/Sources/OpenSwiftUICore/Shape/ShapeLayer.swift +++ b/Sources/OpenSwiftUICore/Shape/ShapeLayer.swift @@ -3,12 +3,42 @@ // OpenSwiftUICore // // Audited for 6.5.4 -// Status: Empty +// Status: WIP // ID: E19F490D25D5E0EC8A24903AF958E341 (SwiftUICore) +import Foundation import OpenQuartzCoreShims +import OpenSwiftUI_SPI // import OpenRenderBoxShims +// MARK: - ShapeLayerHelper [WIP] + +struct ShapeLayerHelper: ResolvedPaintVisitor { + struct Visitor: ResolvedPaintVisitor { + var shapeType: ShapeType + var mayClip: Bool + var requiredType: CALayer.Type? + + mutating func visitPaint

(_ paint: P) where P: ResolvedPaint { + _openSwiftUIUnimplementedFailure() + } + } + + var layer: CALayer + var layerType: CALayer.Type + var path: Path + var origin: CGPoint + var paint: AnyResolvedPaint + var paintBounds: CGRect + var style: FillStyle + var contentsScale: CGFloat + var mayClip: Bool + + mutating func visitPaint

(_ paint: P) where P: ResolvedPaint { + _openSwiftUIUnimplementedFailure() + } +} + // MARK: - ShapeLayerShadowHelper [WIP] struct ShapeLayerShadowHelper: ResolvedPaintVisitor { @@ -24,6 +54,116 @@ struct ShapeLayerShadowHelper: ResolvedPaintVisitor { } } +// MARK: - Async Shape Helpers + +private struct ShapeLayerAsyncHelper: ResolvedPaintVisitor { + var layer: UnsafeMutablePointer + var old: UnsafeMutablePointer + var new: UnsafeMutablePointer + var result: Bool + + mutating func visitPaint

(_ paint: P) where P: ResolvedPaint { + _openSwiftUIUnimplementedFailure() + } +} + +private struct ShapeLayerAsyncShadowHelper: ResolvedPaintVisitor { + var layer: UnsafeMutablePointer + var old: UnsafeMutablePointer + var new: UnsafeMutablePointer + var newPaint: AnyResolvedPaint + var result: Bool + + mutating func visitPaint

(_ paint: P) where P: ResolvedPaint { + _openSwiftUIUnimplementedFailure() + } +} + +// FIXME: ShapeLayerShadowHelper & ShapeLayerAsyncShadowHelper + +extension DisplayList.ViewUpdater.AsyncLayer { + @discardableResult + mutating func updateShadowStyle( + oldShadow: ResolvedShadowStyle?, + newShadow: ResolvedShadowStyle? + ) -> Bool { + switch (oldShadow, newShadow) { + case (nil, nil): + return true + case let (oldShadow?, newShadow?): + guard oldShadow.kind == newShadow.kind else { + return false + } + update(ShadowOffsetProperty.self, from: oldShadow.offset, to: newShadow.offset) + update(ShadowRadiusProperty.self, from: oldShadow.radius, to: newShadow.radius) + update(ShadowColorProperty.self, from: oldShadow.color, to: newShadow.color) + return !isInvalid + default: + return false + } + } + + private mutating func update

( + _ property: P.Type, + from oldValue: P.Value, + to newValue: P.Value + ) where P: Property, P.Value: Equatable { + guard oldValue != newValue else { + return + } + setValue(newValue, for: property) + } + + private mutating func setValue

( + _ value: P.Value, + for property: P.Type + ) where P: Property { + guard !isInvalid else { + return + } + cache.pointee.setAsyncValue( + P.boxValue(value), + for: P.keyPath, + in: layer, + usingPresentationModifier: P.supportsPresentationModifier + ) + } +} + +private struct ShadowColorProperty: DisplayList.ViewUpdater.AsyncLayer.Property { + static let keyPath = "shadowColor" + + static func boxValue(_ value: Color.Resolved) -> NSObject { + #if canImport(Darwin) + return value.cgColor as! NSObject + #else + return NSObject() + #endif + } +} + +private struct ShadowRadiusProperty: DisplayList.ViewUpdater.AsyncLayer.Property { + static let keyPath = "shadowRadius" + + static func boxValue(_ value: CGFloat) -> NSObject { + NSNumber(value: Double(value)) + } +} + +private struct ShadowOffsetProperty: DisplayList.ViewUpdater.AsyncLayer.Property { + static let keyPath = "shadowOffset" + + static func boxValue(_ value: CGSize) -> NSObject { + #if canImport(Darwin) +// return NSValue(size: value) + // FIXME + return NSObject() + #else + return NSObject() + #endif + } +} + // MARK: - ShapeType [WIP] enum ShapeType { From 8554c2d11fd4fcde0732b433d4f49a36a2e7ce9c Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 14 May 2026 00:35:49 +0800 Subject: [PATCH 51/58] Update Platform._makeItemView --- .../DisplayList/DisplayListAsyncLayer.swift | 25 ++ .../DisplayList/DisplayListViewPlatform.swift | 364 ++++++++++-------- .../Render/PlatformViewFactory.swift | 8 +- 3 files changed, 239 insertions(+), 158 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift index 238fe99f5..318760f6c 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift @@ -30,5 +30,30 @@ extension DisplayList.ViewUpdater { let flags: DisplayList.ViewUpdater.Platform.ViewFlags var nextUpdate: Time var isInvalid: Bool + + @inline(__always) + var isBoundsOriginEnabled: Bool { + flags.contains(.boundsOrigin) + } + + @inline(__always) + var isAffineTransformEnabled: Bool { + flags.contains(.affineTransform) + } + + @inline(__always) + var isProjectionGeometryEnabled: Bool { + flags.contains(.projectionGeometry) + } + + @inline(__always) + var isClipRectEnabled: Bool { + flags.contains(.clipRect) + } + + @inline(__always) + var isMaskLayerEnabled: Bool { + flags.contains(.maskLayer) + } } } diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index c30307c58..764d7e094 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -89,14 +89,85 @@ extension DisplayList.ViewUpdater { size = .infinity flags = [] } + + @inline(__always) + var isBoundsOriginEnabled: Bool { + get { flags.contains(.boundsOrigin) } + set { + if newValue { + flags.insert(.boundsOrigin) + } else { + flags.remove(.boundsOrigin) + } + } + } + + @inline(__always) + var isAffineTransformEnabled: Bool { + get { flags.contains(.affineTransform) } + set { + if newValue { + flags.insert(.affineTransform) + } else { + flags.remove(.affineTransform) + } + } + } + + @inline(__always) + var isProjectionGeometryEnabled: Bool { + get { flags.contains(.projectionGeometry) } + set { + if newValue { + flags.insert(.projectionGeometry) + } else { + flags.remove(.projectionGeometry) + } + } + } + + @inline(__always) + var isClipRectEnabled: Bool { + get { flags.contains(.clipRect) } + set { + if newValue { + flags.insert(.clipRect) + } else { + flags.remove(.clipRect) + } + } + } + + @inline(__always) + var isMaskLayerEnabled: Bool { + get { flags.contains(.maskLayer) } + set { + if newValue { + flags.insert(.maskLayer) + } else { + flags.remove(.maskLayer) + } + } + } } - // TODO: Optimize the case name and add inline helper in State to do contains/insert/remove logic struct ViewFlags: OptionSet { let rawValue: UInt8 - - static var _3: ViewFlags { .init(rawValue: 1 << 3) } - static var _4: ViewFlags { .init(rawValue: 1 << 4) } + + @inline(__always) + static var boundsOrigin: ViewFlags { .init(rawValue: 1 << 0) } + + @inline(__always) + static var affineTransform: ViewFlags { .init(rawValue: 1 << 1) } + + @inline(__always) + static var projectionGeometry: ViewFlags { .init(rawValue: 1 << 2) } + + @inline(__always) + static var clipRect: ViewFlags { .init(rawValue: 1 << 3) } + + @inline(__always) + static var maskLayer: ViewFlags { .init(rawValue: 1 << 4) } } } } @@ -299,7 +370,135 @@ extension DisplayList.ViewUpdater.Platform { item: DisplayList.Item, state: UnsafePointer ) -> DisplayList.ViewUpdater.ViewInfo { - _openSwiftUIUnimplementedFailure() + switch item.value { + case let .content(content): + switch content.value { + case .backdrop: + #if canImport(QuartzCore) + let view = definition.makeLayerView(type: CABackdropLayer.self, kind: .backdrop) + #else + let view = definition.makeLayerView(type: CALayer.self, kind: .backdrop) + _openSwiftUIPlatformUnimplementedWarning() + #endif + return DisplayList.ViewUpdater.ViewInfo( + view: view, + layer: viewLayer(view), + container: view, + state: .init(kind: .backdrop) + ) + case .color: + return DisplayList.ViewUpdater.ViewInfo( + platform: self, + kind: .color + ) + case .chameleonColor: + return DisplayList.ViewUpdater.ViewInfo( + platform: self, + kind: .chameleonColor + ) + case .image: + let view = definition.makeLayerView(type: ImageLayer.self, kind: .image) + return DisplayList.ViewUpdater.ViewInfo( + view: view, + layer: viewLayer(view), + container: view, + state: .init(kind: .image) + ) + case let .shape(path, paint, _): + var visitor = ShapeLayerHelper.Visitor( + shapeType: ShapeType(path), + mayClip: !state.pointee.hasDODEffects, + requiredType: nil + ) + paint.visit(&visitor) + let view = definition.makeLayerView(type: visitor.requiredType!, kind: .shape) + return DisplayList.ViewUpdater.ViewInfo( + view: view, + layer: viewLayer(view), + container: view, + state: .init(kind: .shape) + ) + case .shadow: + return DisplayList.ViewUpdater.ViewInfo( + platform: self, + kind: .shadow + ) + case let .platformView(factory): + let view = factory.makePlatformView() ?? missingPlatformView() + definition.makePlatformView(view: view, kind: .platformView) + return DisplayList.ViewUpdater.ViewInfo( + view: view, + layer: viewLayer(view), + container: view, + state: .init(kind: .platformView) + ) + case let .platformLayer(factory): + let layerType = factory.platformLayerType + let view = definition.makeLayerView(type: layerType, kind: .platformLayer) + return DisplayList.ViewUpdater.ViewInfo( + view: view, + layer: viewLayer(view), + container: view, + state: .init(kind: .platformLayer) + ) + case .text: + let view = definition.makeDrawingView(options: .init(base: .init())) as AnyObject + return DisplayList.ViewUpdater.ViewInfo( + view: view, + layer: viewLayer(view), + container: view, + state: .init(kind: .drawing) + ) + case let .flattened(_, _, options), let .drawing(_, _, options): + let view = definition.makeDrawingView(options: .init(base: options)) as AnyObject + return DisplayList.ViewUpdater.ViewInfo( + view: view, + layer: viewLayer(view), + container: view, + state: .init(kind: .drawing) + ) + case .view, .placeholder: + _openSwiftUIUnreachableCode() + } + case let .effect(effect, _): + switch effect { + case .geometryGroup: + return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .geometry) + case .compositingGroup: + let info = DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .compositing) + #if canImport(QuartzCore) + let layer = info.layer + info.layer.allowsGroupOpacity = true + info.layer.allowsGroupBlending = true + #else + _openSwiftUIPlatformUnimplementedWarning() + #endif + return info + case let .platformGroup(factory): + let view = factory.makePlatformGroup() ?? missingPlatformView() + definition.makePlatformView(view: view, kind: .platformGroup) + return DisplayList.ViewUpdater.ViewInfo( + view: view, + layer: viewLayer(view), + container: factory.platformGroupContainer(view), + state: .init(kind: .platformGroup) + ) + case .mask: + return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .mask) + case let .transform(transform) where transform.projectionTransform != nil: + var info = DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .projection) + info.state.isProjectionGeometryEnabled = true + return info + case .transform: + _openSwiftUIUnreachableCode() + case .platform: + return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .platformEffect) + default: + _openSwiftUIUnreachableCode() + } + case .empty, .states: + _openSwiftUIUnreachableCode() + } } private func missingPlatformView() -> AnyObject { @@ -411,7 +610,7 @@ extension DisplayList.ViewUpdater.Platform { return false } let bounds: CGRect - if asyncLayer.flags.contains(._3), let clipRect = newState.pointee.clipRect() { + if asyncLayer.isClipRectEnabled, let clipRect = newState.pointee.clipRect() { bounds = clipRect.rect } else { bounds = CGRect(origin: .zero, size: newSize) @@ -440,15 +639,15 @@ extension DisplayList.ViewUpdater.Platform { let layer = viewInfo.layer layer.cornerRadius = clipRect.clampedCornerRadius layer.cornerCurve = clipRect.style == .continuous ? .continuous : .circular - viewInfo.state.flags.insert(._3) - if viewInfo.state.flags.contains(._4) { + viewInfo.state.isClipRectEnabled = true + if viewInfo.state.isMaskLayerEnabled { layer.mask = nil - viewInfo.state.flags.remove(._4) + viewInfo.state.isMaskLayerEnabled = false } } else { - if viewInfo.state.flags.contains(._3) { - viewInfo.state.flags.remove(._3) + if viewInfo.state.isClipRectEnabled { + viewInfo.state.isClipRectEnabled = false setClipsToBounds(false, of: viewInfo.view, onLayer: false) let layer = viewInfo.layer var bounds = layer.bounds @@ -459,10 +658,10 @@ extension DisplayList.ViewUpdater.Platform { } let clips = state.pointee.clips guard !clips.isEmpty else { - if viewInfo.state.flags.contains(._4) { + if viewInfo.state.isMaskLayerEnabled { let layer = viewInfo.layer layer.mask = nil - viewInfo.state.flags.remove(._4) + viewInfo.state.isMaskLayerEnabled = false } return } @@ -476,7 +675,7 @@ extension DisplayList.ViewUpdater.Platform { maskLayer.setNoAnimationDelegate() layer.mask = maskLayer } - viewInfo.state.flags.insert(._4) + viewInfo.state.isMaskLayerEnabled = true let transform = state.pointee.transform.inverted() if maskLayer.clips != clips || maskLayer.clipTransform != transform { maskLayer.setClips(clips, transform: transform) @@ -572,100 +771,6 @@ extension DisplayList.ViewUpdater.Platform { return drawable } - // TBA - @inline(__always) - private func makeContentView( - _ content: DisplayList.Content, - state: UnsafePointer - ) -> DisplayList.ViewUpdater.ViewInfo { - switch content.value { - case .backdrop: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .backdrop) - case .color: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .color) - case .chameleonColor: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .chameleonColor) - case .image: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .image) - case .shape: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .shape) - case .shadow: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .shadow) - case let .platformView(factory): - let view = factory.makePlatformView() ?? missingItemView() - definition.makePlatformView(view: view, kind: .platformView) - return makeViewInfo(view: view, kind: .platformView) - case let .platformLayer(factory): - #if canImport(QuartzCore) - let view = definition.makeLayerView( - type: factory.platformLayerType, - kind: .platformLayer - ) - return makeViewInfo(view: view, kind: .platformLayer) - #else - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .platformLayer) - #endif - case .text, .flattened, .drawing: - let view = definition.makeDrawingView( - options: .init(base: drawingOptions(for: content, state: state)) - ) as AnyObject - return makeViewInfo(view: view, kind: .drawing) - case let .view(factory): - let view = makeHostedPlatformView(factory: factory) ?? missingItemView() - definition.makePlatformView(view: view, kind: .platformView) - return makeViewInfo(view: view, kind: .platformView) - case .placeholder: - return makeViewInfo(view: missingItemView(), kind: .platformView) - } - } - - // TBA - @inline(__always) - private func makeEffectView( - _ effect: DisplayList.Effect, - state: UnsafePointer - ) -> DisplayList.ViewUpdater.ViewInfo { - switch effect { - case .identity, .opacity, .blendMode, .clip, .filter, .contentTransition: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .compositing) - case .geometryGroup: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .geometry) - case .compositingGroup, .backdropGroup: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .compositing) - case .archive, .properties, .accessibility, .state: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .compositing) - case let .platformGroup(factory): - let view = factory.makePlatformGroup() ?? missingItemView() - definition.makePlatformView(view: view, kind: .platformGroup) - var info = makeViewInfo(view: view, kind: .platformGroup) - info.container = factory.platformGroupContainer(view) - return info - case .mask: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .mask) - case let .transform(transform): - let kind: PlatformViewDefinition.ViewKind - switch transform { - case .affine, .rotation: - kind = .geometry - case .projection: - kind = .projection - case .rotation3D: - kind = .affine3D - } - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: kind) - case .animation: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .compositing) - case let .view(factory): - let view = makeHostedPlatformView(factory: factory) ?? missingItemView() - definition.makePlatformView(view: view, kind: .platformView) - return makeViewInfo(view: view, kind: .platformView) - case .platform: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .platformEffect) - case .interpolatorRoot, .interpolatorLayer, .interpolatorAnimation: - return DisplayList.ViewUpdater.ViewInfo(platform: self, kind: .drawing) - } - } - // TBA @inline(__always) private func updateContentView( @@ -764,22 +869,6 @@ extension DisplayList.ViewUpdater.Platform { ) } - // TBA - @inline(__always) - private func makeViewInfo( - view: AnyObject, - kind: PlatformViewDefinition.ViewKind - ) -> DisplayList.ViewUpdater.ViewInfo { - let layer = viewLayer(view) - let state = DisplayList.ViewUpdater.Platform.State(kind: kind) - return DisplayList.ViewUpdater.ViewInfo( - view: view, - layer: layer, - container: view, - state: state - ) - } - // TBA @inline(__always) private func updateViewReference( @@ -795,33 +884,6 @@ extension DisplayList.ViewUpdater.Platform { viewInfo.reset(platform: self) } - // TBA - @inline(__always) - private func drawingOptions( - for content: DisplayList.Content, - state: UnsafePointer - ) -> RasterizationOptions { - switch content.value { - case let .flattened(_, _, options), let .drawing(_, _, options): - return options - default: - return RasterizationOptions() - } - } - - // TBA - @inline(__always) - private func makeHostedPlatformView(factory: any DisplayList.ViewFactory) -> AnyObject? { - _openSwiftUIUnimplementedWarning() - return nil - } - - // TBA - @inline(__always) - private func missingItemView() -> AnyObject { - definition.makeView(kind: .platformView) - } - func forEachChild( of viewInfo: DisplayList.ViewUpdater.ViewInfo, do body: (AnyObject) -> Void diff --git a/Sources/OpenSwiftUICore/Render/PlatformViewFactory.swift b/Sources/OpenSwiftUICore/Render/PlatformViewFactory.swift index 78de96ec7..f1d2931cc 100644 --- a/Sources/OpenSwiftUICore/Render/PlatformViewFactory.swift +++ b/Sources/OpenSwiftUICore/Render/PlatformViewFactory.swift @@ -6,9 +6,7 @@ // ID: 7A45621CE16223183E03CAC88E8C5E60 (SwiftUICore) package import Foundation -#if canImport(QuartzCore) -package import QuartzCore -#endif +package import OpenQuartzCoreShims // MARK: - AnyViewFactory @@ -33,11 +31,9 @@ extension AnyViewFactory where Self: View { // MARK: - PlatformLayerFactory [TODO] package protocol PlatformLayerFactory: AnyViewFactory { - #if canImport(QuartzCore) var platformLayerType: CALayer.Type { get } func updatePlatformLayer(_ layer: CALayer) - #endif func renderPlatformLayer( in ctx: GraphicsContext, @@ -198,7 +194,6 @@ package struct EmptyViewFactory: AnyViewFactory { } } -#if canImport(QuartzCore) extension EmptyViewFactory: PlatformLayerFactory { private class MissingLayer: CALayer { required init?(coder: NSCoder) { @@ -245,7 +240,6 @@ extension EmptyViewFactory: PlatformLayerFactory { _openSwiftUIUnimplementedFailure() } } -#endif extension EmptyViewFactory: PlatformViewFactory { package func makePlatformView() -> AnyObject? { From 7db611f3b2dcf6607b8d6c9302df3e4053259f45 Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 14 May 2026 01:13:18 +0800 Subject: [PATCH 52/58] Update Platform.updateGeometry --- .../DisplayList/DisplayListViewPlatform.swift | 143 +++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 764d7e094..2be3ed484 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -278,6 +278,41 @@ extension DisplayList.ViewUpdater.Platform { _openSwiftUIPlatformUnimplementedWarning() #endif } + + @inline(__always) + package func setGeometry( + of view: AnyObject, + useViewAPIs: Bool, + positionChanged: Bool, + boundsOriginChanged: Bool, + boundsSizeChanged: Bool, + position: CGPoint, + bounds: CGRect + ) { + #if canImport(QuartzCore) + CoreViewSetGeometry( + system: viewSystem, + view: view, + useViewAPIs: useViewAPIs, + positionChanged: positionChanged, + boundsOriginChanged: boundsOriginChanged, + boundsSizeChanged: boundsSizeChanged, + position: position, + bounds: bounds + ) + #else + _openSwiftUIPlatformUnimplementedWarning() + #endif + } + + @inline(__always) + package func setMaskGeometry(of view: AnyObject, bounds: CGRect) { + #if canImport(QuartzCore) + CoreViewSetMaskGeometry(system: viewSystem, view: view, bounds: bounds) + #else + _openSwiftUIPlatformUnimplementedWarning() + #endif + } package func setShadow(_ shadow: ResolvedShadowStyle?, layer: CALayer) { #if canImport(QuartzCore) @@ -693,7 +728,113 @@ extension DisplayList.ViewUpdater.Platform { state: UnsafePointer, clipRectChanged: Bool ) -> Bool { - _openSwiftUIUnimplementedFailure() + #if canImport(QuartzCore) + let modelState = state.pointee + let sizeChanged = viewInfo.state.size != size + let transformSeed = DisplayList.Seed(modelState.versions.transform) + let transformChanged = viewInfo.seeds.transform != transformSeed + viewInfo.seeds.transform = transformSeed + guard sizeChanged || transformChanged || clipRectChanged else { + return false + } + // TBA + let hadBoundsOrigin = viewInfo.state.isBoundsOriginEnabled + let hadAffineTransform = viewInfo.state.isAffineTransformEnabled + let usesProjection = viewInfo.state.isProjectionGeometryEnabled + let usesClipRect = viewInfo.state.isClipRectEnabled + + var clipRectPresent = false + var bounds = CGRect(origin: .zero, size: size) + var position = CGPoint(x: modelState.transform.tx, y: modelState.transform.ty) + if usesClipRect, let clipRect = modelState.clipRect() { + clipRectPresent = true + bounds = clipRect.rect + position.x += bounds.origin.x + position.y += bounds.origin.y + } + + let shouldComparePosition = transformChanged || (clipRectPresent && clipRectChanged) + let positionChanged = shouldComparePosition && viewInfo.state.position != position + if positionChanged { + viewInfo.state.position = position + } + + let boundsSizeChanged = viewInfo.state.size != bounds.size + if boundsSizeChanged { + viewInfo.state.size = bounds.size + } + + let hasBoundsOrigin = bounds.origin != .zero + let boundsOriginChanged = hadBoundsOrigin || hasBoundsOrigin + let boundsChanged = boundsOriginChanged || boundsSizeChanged + + if boundsOriginChanged { + viewInfo.state.isBoundsOriginEnabled = hasBoundsOrigin + } + + if usesProjection { + if boundsChanged { + CoreViewSetSize(system: viewSystem, view: viewInfo.view, size: bounds.size) + } + viewLayer(viewInfo.view).contentsScale = modelState.globals.pointee.environment.contentsScale + if boundsChanged, viewInfo.state.kind == .mask { + setMaskGeometry(of: viewInfo.view, bounds: bounds) + } + return boundsChanged + } + + var affineTransform = modelState.transform + affineTransform.tx = 0 + affineTransform.ty = 0 + let hasAffineTransform = affineTransform != .identity + if transformChanged && (hadAffineTransform || hasAffineTransform) { + CoreViewSetTransform( + system: viewSystem, + view: viewInfo.view, + transform: affineTransform + ) + if hasAffineTransform { + viewInfo.state.isAffineTransformEnabled = true + } else { + viewInfo.state.isAffineTransformEnabled = false + } + } + + let useViewAPIs: Bool + switch viewInfo.state.kind { + case .platformView, .platformGroup, .platformLayer: + useViewAPIs = true + default: + useViewAPIs = false + } + let sanitizedPosition = CGPoint( + x: position.x.mappingNaN(to: 0), + y: position.y.mappingNaN(to: 0) + ) + let sanitizedBounds = CGRect( + x: bounds.origin.x.mappingNaN(to: 0), + y: bounds.origin.y.mappingNaN(to: 0), + width: bounds.size.width.mappingNaN(to: 0), + height: bounds.size.height.mappingNaN(to: 0) + ) + setGeometry( + of: viewInfo.view, + useViewAPIs: useViewAPIs, + positionChanged: positionChanged, + boundsOriginChanged: boundsOriginChanged, + boundsSizeChanged: boundsSizeChanged, + position: sanitizedPosition, + bounds: sanitizedBounds + ) + + if boundsChanged, viewInfo.state.kind == .mask { + setMaskGeometry(of: viewInfo.view, bounds: bounds) + } + return boundsChanged + #else + _openSwiftUIPlatformUnimplementedWarning() + return false + #endif } private func updateShadow( From 2d02b38136d494b7acfc1f3cd01e23fc90efd1ac Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 14 May 2026 01:22:34 +0800 Subject: [PATCH 53/58] Update Platform.updateShadow --- .../DisplayList/DisplayListViewPlatform.swift | 68 ++++++++++++++++++- .../OpenSwiftUICore/Shape/ShapeLayer.swift | 9 +++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 2be3ed484..6df596b32 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -842,7 +842,73 @@ extension DisplayList.ViewUpdater.Platform { state: UnsafePointer, item: DisplayList.Item ) { - _openSwiftUIUnimplementedFailure() + #if canImport(QuartzCore) + guard let shadow = state.pointee.shadow?.value else { + let shadowSeed = DisplayList.Seed(state.pointee.versions.shadow) + guard viewInfo.seeds.shadow != shadowSeed else { + return + } + switch viewInfo.state.kind { + case .platformView, .platformGroup, .platformLayer: + return + default: + CoreViewSetShadow( + system: viewSystem, + view: viewInfo.view, + color: nil, + radius: 0, + offset: .zero + ) + return + } + } + guard viewInfo.state.kind != .inherited, + case let .content(content) = item.value + else { + CoreViewSetShadow( + system: viewSystem, + view: viewInfo.view, + color: shadow.color.cgColor, + radius: shadow.radius, + offset: shadow.offset + ) + return + } + switch content.value { + case let .color(color): + var colorShadow = shadow + colorShadow.color = shadow.color.multiplyingOpacity(by: color.opacity) + viewInfo.layer.shadowPathIsBounds = true + viewInfo.layer.shadowPath = nil + setShadow(colorShadow, layer: viewInfo.layer) + case let .shape(path, paint, _): + let bounds = ShapeLayerHelper.makeLayerBounds( + size: item.size, + path: path, + layerType: type(of: viewInfo.layer), + contentsScale: state.pointee.globals.pointee.environment.contentsScale + ) + var helper = ShapeLayerShadowHelper( + platform: self, + layer: viewInfo.layer, + path: path, + offset: bounds.origin, + shadow: shadow, + updateShape: false + ) + paint.visit(&helper) + default: + CoreViewSetShadow( + system: viewSystem, + view: viewInfo.view, + color: shadow.color.cgColor, + radius: shadow.radius, + offset: shadow.offset + ) + } + #else + _openSwiftUIPlatformUnimplementedWarning() + #endif } private func updateProperties( diff --git a/Sources/OpenSwiftUICore/Shape/ShapeLayer.swift b/Sources/OpenSwiftUICore/Shape/ShapeLayer.swift index 482491658..30a962bbf 100644 --- a/Sources/OpenSwiftUICore/Shape/ShapeLayer.swift +++ b/Sources/OpenSwiftUICore/Shape/ShapeLayer.swift @@ -37,6 +37,15 @@ struct ShapeLayerHelper: ResolvedPaintVisitor { mutating func visitPaint

(_ paint: P) where P: ResolvedPaint { _openSwiftUIUnimplementedFailure() } + + static func makeLayerBounds( + size: CGSize, + path: Path, + layerType: CALayer.Type, + contentsScale: CGFloat + ) -> CGRect { + _openSwiftUIUnimplementedFailure() + } } // MARK: - ShapeLayerShadowHelper [WIP] From 117dea120af02cb8dab4a04740ea2c59c46e2697 Mon Sep 17 00:00:00 2001 From: Kyle Date: Fri, 15 May 2026 00:00:18 +0800 Subject: [PATCH 54/58] Update Platform.updateShapeView --- .../DisplayList/DisplayListAsyncLayer.swift | 5 ++ .../DisplayList/DisplayListViewPlatform.swift | 76 ++++++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift index 318760f6c..8f89b0653 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListAsyncLayer.swift @@ -55,5 +55,10 @@ extension DisplayList.ViewUpdater { var isMaskLayerEnabled: Bool { flags.contains(.maskLayer) } + + @inline(__always) + var isContentGeometryEnabled: Bool { + flags.contains(.contentGeometry) + } } } diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 6df596b32..99a843b28 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -149,6 +149,18 @@ extension DisplayList.ViewUpdater { } } } + + @inline(__always) + var isContentGeometryEnabled: Bool { + get { flags.contains(.contentGeometry) } + set { + if newValue { + flags.insert(.contentGeometry) + } else { + flags.remove(.contentGeometry) + } + } + } } struct ViewFlags: OptionSet { @@ -168,6 +180,9 @@ extension DisplayList.ViewUpdater { @inline(__always) static var maskLayer: ViewFlags { .init(rawValue: 1 << 4) } + + @inline(__always) + static var contentGeometry: ViewFlags { .init(rawValue: 1 << 5) } } } } @@ -557,7 +572,66 @@ extension DisplayList.ViewUpdater.Platform { style: FillStyle, contentsChanged: Bool ) { - _openSwiftUIUnimplementedFailure() + let currentLayerType = type(of: viewInfo.layer) + let originalSize = size + let contentsScale = state.globals.pointee.environment.contentsScale + var bounds = ShapeLayerHelper.makeLayerBounds( + size: originalSize, + path: path, + layerType: currentLayerType, + contentsScale: contentsScale + ) + + if contentsChanged { + var helper = ShapeLayerHelper( + layer: viewInfo.layer, + layerType: currentLayerType, + path: path, + origin: bounds.origin, + paint: paint, + paintBounds: CGRect( + origin: CGPoint(x: -bounds.origin.x, y: -bounds.origin.y), + size: originalSize + ), + style: style, + contentsScale: contentsScale, + mayClip: !state.hasDODEffects + ) + paint.visit(&helper) + if helper.layerType != currentLayerType { + bounds = ShapeLayerHelper.makeLayerBounds( + size: originalSize, + path: path, + layerType: helper.layerType, + contentsScale: contentsScale + ) + helper.origin = bounds.origin + helper.paintBounds = CGRect( + origin: CGPoint(x: -bounds.origin.x, y: -bounds.origin.y), + size: originalSize + ) + let view = definition.makeLayerView(type: helper.layerType, kind: .shape) + viewInfo = DisplayList.ViewUpdater.ViewInfo( + view: view, + layer: viewLayer(view), + container: view, + state: .init(kind: .shape) + ) + helper.layer = viewInfo.layer + paint.visit(&helper) + } + let shapePath: Path + if bounds.origin.y == 0 { + shapePath = path + } else { + let offset = -bounds.origin.y + shapePath = path.applying(CGAffineTransform(translationX: offset, y: offset)) + } + definition.setPath(shapePath, shapeView: viewInfo.view) + viewInfo.state.isContentGeometryEnabled = true + } + state.transform = state.transform.translatedBy(x: bounds.origin.x, y: bounds.origin.y) + size = bounds.size } private func updateShadowView( From 4e200109dfe5164f6da8f4b630d57995b5d37a7e Mon Sep 17 00:00:00 2001 From: Kyle Date: Fri, 15 May 2026 00:17:32 +0800 Subject: [PATCH 55/58] Fix Model.State getter issue --- .../DisplayList/DisplayListViewPlatform.swift | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 99a843b28..6e003f9f5 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -415,7 +415,7 @@ extension DisplayList.ViewUpdater.Platform { ) -> Bool { _openSwiftUIUnimplementedFailure() } - + func _makeItemView( item: DisplayList.Item, state: UnsafePointer @@ -803,9 +803,8 @@ extension DisplayList.ViewUpdater.Platform { clipRectChanged: Bool ) -> Bool { #if canImport(QuartzCore) - let modelState = state.pointee let sizeChanged = viewInfo.state.size != size - let transformSeed = DisplayList.Seed(modelState.versions.transform) + let transformSeed = DisplayList.Seed(state.pointee.versions.transform) let transformChanged = viewInfo.seeds.transform != transformSeed viewInfo.seeds.transform = transformSeed guard sizeChanged || transformChanged || clipRectChanged else { @@ -819,8 +818,8 @@ extension DisplayList.ViewUpdater.Platform { var clipRectPresent = false var bounds = CGRect(origin: .zero, size: size) - var position = CGPoint(x: modelState.transform.tx, y: modelState.transform.ty) - if usesClipRect, let clipRect = modelState.clipRect() { + var position = CGPoint(x: state.pointee.transform.tx, y: state.pointee.transform.ty) + if usesClipRect, let clipRect = state.pointee.clipRect() { clipRectPresent = true bounds = clipRect.rect position.x += bounds.origin.x @@ -850,14 +849,14 @@ extension DisplayList.ViewUpdater.Platform { if boundsChanged { CoreViewSetSize(system: viewSystem, view: viewInfo.view, size: bounds.size) } - viewLayer(viewInfo.view).contentsScale = modelState.globals.pointee.environment.contentsScale + viewLayer(viewInfo.view).contentsScale = state.pointee.globals.pointee.environment.contentsScale if boundsChanged, viewInfo.state.kind == .mask { setMaskGeometry(of: viewInfo.view, bounds: bounds) } return boundsChanged } - var affineTransform = modelState.transform + var affineTransform = state.pointee.transform affineTransform.tx = 0 affineTransform.ty = 0 let hasAffineTransform = affineTransform != .identity @@ -1111,7 +1110,7 @@ extension DisplayList.ViewUpdater.Platform { break } } - + // TBA @inline(__always) private func updateDrawingContent( From 93458f032760d55c8ee0a5022fd551144ee0e026 Mon Sep 17 00:00:00 2001 From: Kyle Date: Fri, 15 May 2026 00:20:47 +0800 Subject: [PATCH 56/58] Update Platform.updateState --- .../Graphic/GraphicsFilter.swift | 15 +- .../Render/DisplayList/DisplayList.swift | 3 + .../DisplayList/DisplayListViewPlatform.swift | 156 ++++++++++++++---- .../OpenSwiftUICoreViewFunctions.h | 1 + 4 files changed, 144 insertions(+), 31 deletions(-) diff --git a/Sources/OpenSwiftUICore/Graphic/GraphicsFilter.swift b/Sources/OpenSwiftUICore/Graphic/GraphicsFilter.swift index 1e3a3dc6f..90c73fd8b 100644 --- a/Sources/OpenSwiftUICore/Graphic/GraphicsFilter.swift +++ b/Sources/OpenSwiftUICore/Graphic/GraphicsFilter.swift @@ -3,7 +3,8 @@ // OpenSwiftUICore // // Audited for 6.0.87 -// WIP +// Status: WIP +// ID: 07401C2C9845FAA2984B0D65D34F2B64 (SwiftUICore) package enum GraphicsFilter { case blur(BlurStyle) @@ -125,4 +126,16 @@ package enum GraphicsBlendMode: Equatable { default: false } } + + @inline(__always) + var filter: Any? { + switch self { + case let .caFilter(filter): + return filter + case let .blendMode(mode): + // TODO: _ORBBlendModeGetCompositingFilter & ORBBlendMode + _openSwiftUIUnimplementedWarning() + return nil + } + } } diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift index 07cf0055c..2f9dda039 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift @@ -328,6 +328,9 @@ extension DisplayList { package static func < (lhs: Version, rhs: Version) -> Bool { lhs.value < rhs.value } + + @inline(__always) + var seed: Seed { .init(self) } } package struct Seed: Hashable { diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 6e003f9f5..32f2a2772 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -401,9 +401,73 @@ extension DisplayList.ViewUpdater.Platform { size: CGSize, state: UnsafePointer ) { - _openSwiftUIUnimplementedFailure() + #if canImport(QuartzCore) + if viewInfo.seeds.opacity != state.pointee.versions.opacity.seed { + CoreViewSetOpacity( + system: viewSystem, + view: viewInfo.view, + opacity: CGFloat(state.pointee.opacity) + ) + viewInfo.seeds.opacity = state.pointee.versions.opacity.seed + } + if viewInfo.seeds.blend != state.pointee.versions.blend.seed { + CoreViewSetCompositingFilter( + system: viewSystem, + view: viewInfo.view, + filter: state.pointee.blend.filter + ) + viewInfo.seeds.blend = state.pointee.versions.blend.seed + } + if viewInfo.seeds.filters != state.pointee.versions.filters.seed { + var filters = state.pointee.filters + if viewInfo.state.kind == .drawing { + let color = filters.popColorMultiply(drawable: viewInfo.view as? PlatformDrawable) + viewInfo.layer.contentsMultiplyColor = color?.cgColor + } + CoreViewSetFilters( + system: viewSystem, + view: viewInfo.view, + filters: filters.caFilters() + ) + viewInfo.seeds.filters = state.pointee.versions.filters.seed + } + + let clipRectChanged: Bool + if viewInfo.seeds.clips != state.pointee.versions.clips.seed || + viewInfo.seeds.transform != state.pointee.versions.transform.seed { + let oldFlags = viewInfo.state.flags + updateClipShapes(&viewInfo, state: state) + viewInfo.seeds.clips = state.pointee.versions.clips.seed + clipRectChanged = oldFlags.union(viewInfo.state.flags).contains(.clipRect) + } else { + clipRectChanged = false + } + let boundsChanged = updateGeometry( + &viewInfo, + item: item, + size: size, + state: state, + clipRectChanged: clipRectChanged + ) + if boundsChanged || viewInfo.seeds.shadow != state.pointee.versions.shadow.seed || viewInfo.seeds.item != item.version.seed { + updateShadow(&viewInfo, state: state, item: item) + viewInfo.seeds.shadow = state.pointee.versions.shadow.seed + } + if viewInfo.seeds.properties != state.pointee.versions.properties.seed { + updateProperties(&viewInfo, state: state) + viewInfo.seeds.properties = state.pointee.versions.properties.seed + } + switch viewInfo.state.kind { + case .image, .drawing, .platformView, .platformGroup, .platformLayer: + break + default: + viewInfo.layer.contentsScale = state.pointee.globals.pointee.environment.contentsScale + } + #else + _openSwiftUIPlatformUnimplementedWarning() + #endif } - + func updateStateAsync( layer: inout DisplayList.ViewUpdater.AsyncLayer, oldItem: DisplayList.Item, @@ -1119,34 +1183,35 @@ extension DisplayList.ViewUpdater.Platform { item: DisplayList.Item, state: UnsafePointer ) { - let contentsScale = state.pointee.globals.pointee.environment.contentsScale - let options = drawingOptions(for: content, state: state) - var view = viewInfo.view - let drawable = updateDrawingView( - &view, - options: options, - contentsScale: contentsScale - ) - updateViewReference(&viewInfo, view: view, kind: .drawing) - var drawableContent = PlatformDrawableContent() - switch content.value { - case let .flattened(list, offset, _): - drawableContent.storage = .displayList( - list, - offset, - state.pointee.globals.pointee.time - ) - case let .drawing(contents, offset, _): - drawableContent.storage = .rbDisplayList(contents, offset) - case .text: - drawableContent.storage = .empty - default: - return - } - _ = drawable.update( - content: drawableContent, - required: item.features.contains(.required) - ) + _openSwiftUIUnimplementedFailure() +// let contentsScale = state.pointee.globals.pointee.environment.contentsScale +// let options = drawingOptions(for: content, state: state) +// var view = viewInfo.view +// let drawable = updateDrawingView( +// &view, +// options: options, +// contentsScale: contentsScale +// ) +// updateViewReference(&viewInfo, view: view, kind: .drawing) +// var drawableContent = PlatformDrawableContent() +// switch content.value { +// case let .flattened(list, offset, _): +// drawableContent.storage = .displayList( +// list, +// offset, +// state.pointee.globals.pointee.time +// ) +// case let .drawing(contents, offset, _): +// drawableContent.storage = .rbDisplayList(contents, offset) +// case .text: +// drawableContent.storage = .empty +// default: +// return +// } +// _ = drawable.update( +// content: drawableContent, +// required: item.features.contains(.required) +// ) } // TBA @@ -1208,3 +1273,34 @@ extension DisplayList.GraphicsRenderer { #endif } } + +// MARK: - GraphicsFilter + Platform Filters + +extension [GraphicsFilter] { + fileprivate mutating func popColorMultiply( + drawable: @autoclosure () -> PlatformDrawable? + ) -> Color.Resolved? { + guard case let .colorMultiply(color) = last, + let drawable = drawable(), + type(of: drawable).allowsContentsMultiplyColor + else { + return nil + } + removeLast() + return color + } + + @inline(__always) + func caFilters() -> [Any]? { + // _CAFilterArrayAppend + makeCAFilter + _openSwiftUIUnimplementedWarning() + return nil + } +} + +//extension GraphicsFilter { +// // 07401C2C9845FAA2984B0D65D34F2B64 +// fileprivate func makeCAFilter() -> CAFilter? { +// _openSwiftUIUnimplementedFailure() +// } +//} diff --git a/Sources/OpenSwiftUI_SPI/Overlay/CoreGraphics/OpenSwiftUICoreViewFunctions.h b/Sources/OpenSwiftUI_SPI/Overlay/CoreGraphics/OpenSwiftUICoreViewFunctions.h index 060f1fe98..28e36826a 100644 --- a/Sources/OpenSwiftUI_SPI/Overlay/CoreGraphics/OpenSwiftUICoreViewFunctions.h +++ b/Sources/OpenSwiftUI_SPI/Overlay/CoreGraphics/OpenSwiftUICoreViewFunctions.h @@ -14,6 +14,7 @@ #include "OpenSwiftUIViewSystem.h" #include +#include OPENSWIFTUI_ASSUME_NONNULL_BEGIN From 5d209c6ac156981f63e7269bf8f8a8f57a873894 Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 14 May 2026 03:31:49 +0800 Subject: [PATCH 57/58] Fix Linux build issue --- .../Render/DisplayList/DisplayListViewPlatform.swift | 9 +++++++++ Sources/OpenSwiftUICore/Render/PlatformViewFactory.swift | 2 ++ Sources/OpenSwiftUICore/Shape/Path.swift | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 32f2a2772..20bb40b06 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -511,7 +511,12 @@ extension DisplayList.ViewUpdater.Platform { kind: .chameleonColor ) case .image: + #if canImport(QuartzCore) let view = definition.makeLayerView(type: ImageLayer.self, kind: .image) + #else + let view = definition.makeLayerView(type: CALayer.self, kind: .image) + _openSwiftUIPlatformUnimplementedWarning() + #endif return DisplayList.ViewUpdater.ViewInfo( view: view, layer: viewLayer(view), @@ -1125,8 +1130,12 @@ extension DisplayList.ViewUpdater.Platform { ) { switch content.value { case let .color(resolved): + #if canImport(QuartzCore) let cgColor = resolved.cgColor viewLayer(viewInfo.view).backgroundColor = cgColor + #else + _openSwiftUIPlatformUnimplementedWarning() + #endif case .backdrop, .chameleonColor, .image, .shadow, .view, .placeholder: break case let .shape(path, _, _): diff --git a/Sources/OpenSwiftUICore/Render/PlatformViewFactory.swift b/Sources/OpenSwiftUICore/Render/PlatformViewFactory.swift index f1d2931cc..623210aec 100644 --- a/Sources/OpenSwiftUICore/Render/PlatformViewFactory.swift +++ b/Sources/OpenSwiftUICore/Render/PlatformViewFactory.swift @@ -196,6 +196,7 @@ package struct EmptyViewFactory: AnyViewFactory { extension EmptyViewFactory: PlatformLayerFactory { private class MissingLayer: CALayer { + #if canImport(QuartzCore) required init?(coder: NSCoder) { super.init(coder: coder) } @@ -222,6 +223,7 @@ extension EmptyViewFactory: PlatformLayerFactory { get { true } set {} } + #endif } package var platformLayerType: CALayer.Type { diff --git a/Sources/OpenSwiftUICore/Shape/Path.swift b/Sources/OpenSwiftUICore/Shape/Path.swift index af3334d63..459a44526 100644 --- a/Sources/OpenSwiftUICore/Shape/Path.swift +++ b/Sources/OpenSwiftUICore/Shape/Path.swift @@ -166,7 +166,12 @@ public struct Path: Equatable, LosslessStringConvertible, @unchecked Sendable { fileprivate var boundingRect: CGRect { switch kind { case .cgPath: + #if canImport(CoreGraphics) return data.cgPath.takeUnretainedValue().boundingBoxOfPath + #else + _openSwiftUIPlatformUnimplementedWarning() + return .zero + #endif case .rbPath: _openSwiftUIUnimplementedWarning() // return data.rbPath.boundingBox // FIXME: RB API From 18541a35d27a1aeba945a7826d559016383bad68 Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 14 May 2026 03:38:54 +0800 Subject: [PATCH 58/58] Update ContentView --- Example/Shared/ContentView.swift | 18 ---------------- .../Render/Async/AsyncRenderExample.swift | 21 +++++++++++++++++++ 2 files changed, 21 insertions(+), 18 deletions(-) create mode 100644 Example/Shared/Render/Async/AsyncRenderExample.swift diff --git a/Example/Shared/ContentView.swift b/Example/Shared/ContentView.swift index 4b1c8f99a..517cbf54f 100644 --- a/Example/Shared/ContentView.swift +++ b/Example/Shared/ContentView.swift @@ -13,21 +13,3 @@ struct ContentView: View { AsyncRenderExample() } } - -struct AsyncRenderExample: View { - @State private var items = [6] - - var body: some View { - VStack(spacing: 10) { - ForEach(items, id: \.self) { item in - Color.blue.opacity(Double(item) / 6.0) - .frame(height: 50) - .transition(.slide) - } - } - .animation(.easeInOut(duration: 2), value: items) - .onAppear { - items.removeAll { $0 == 6 } - } - } -} diff --git a/Example/Shared/Render/Async/AsyncRenderExample.swift b/Example/Shared/Render/Async/AsyncRenderExample.swift new file mode 100644 index 000000000..ff6bb7b87 --- /dev/null +++ b/Example/Shared/Render/Async/AsyncRenderExample.swift @@ -0,0 +1,21 @@ +// +// GeometryEffectExample.swift +// Shared + +struct AsyncRenderExample: View { + @State private var items = [6] + + var body: some View { + VStack(spacing: 10) { + ForEach(items, id: \.self) { item in + Color.blue.opacity(Double(item) / 6.0) + .frame(height: 50) + .transition(.slide) + } + } + .animation(.easeInOut(duration: 2), value: items) + .onAppear { + items.removeAll { $0 == 6 } + } + } +}