diff --git a/Example/Shared/ContentView.swift b/Example/Shared/ContentView.swift index 3001dd532..517cbf54f 100644 --- a/Example/Shared/ContentView.swift +++ b/Example/Shared/ContentView.swift @@ -10,6 +10,6 @@ import SwiftUI struct ContentView: View { var body: some View { - TextExample() + AsyncRenderExample() } } 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 } + } + } +} 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 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/Graphic/GraphicsContext.swift b/Sources/OpenSwiftUICore/Graphic/GraphicsContext.swift index ae1bcf36a..fcf38327f 100644 --- a/Sources/OpenSwiftUICore/Graphic/GraphicsContext.swift +++ b/Sources/OpenSwiftUICore/Graphic/GraphicsContext.swift @@ -536,6 +536,10 @@ extension GraphicsContext { #endif } + package func renderMissingPlatformView(size: CGSize) { + _openSwiftUIUnimplementedWarning() + } + // FIXME struct ORBLayerFlags: OptionSet { let rawValue: UInt32 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 a01bfff14..2f9dda039 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,13 +227,63 @@ 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) 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 @@ -260,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 { @@ -299,9 +370,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 +383,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 { @@ -399,16 +477,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) {} @@ -482,26 +581,35 @@ 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 } } - + 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) + } + } } } @@ -552,6 +660,10 @@ extension DisplayList { _openSwiftUIEmptyStub() } + var features: Features { + [] + } + func rewriteDisplayList( _ list: inout DisplayList, time: Attribute