Skip to content

Commit b189546

Browse files
authored
Add initial rendering support for OpenSwiftUI (#271)
1 parent ef893dd commit b189546

File tree

13 files changed

+428
-79
lines changed

13 files changed

+428
-79
lines changed

Package.resolved

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"originHash" : "b9fba48e8675bc3d76b8bb419a70ff1739d473df3240c29e20a4d2bfc78dd1c0",
2+
"originHash" : "8917cbaeeda8db57a8ea78c2771eb811ef20031946167d085ed5773330885409",
33
"pins" : [
44
{
55
"identity" : "darwinprivateframeworks",

Package.swift

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ var sharedSwiftSettings: [SwiftSetting] = [
5151
.swiftLanguageMode(.v5),
5252
]
5353

54-
// MARK: - [env] OPENGRAPH_TARGET_RELEASE
54+
// MARK: - [env] OPENSWIFTUI_TARGET_RELEASE
5555

5656
let releaseVersion = Context.environment["OPENSWIFTUI_TARGET_RELEASE"].flatMap { Int($0) } ?? 2024
5757
sharedCSettings.append(.define("OPENSWIFTUI_RELEASE", to: "\(releaseVersion)"))
@@ -90,6 +90,20 @@ if linkCoreUI {
9090
)
9191
}
9292

93+
// MARK: - [env] OPENGSWIFTUI_SWIFTUI_RENDER
94+
95+
#if os(macOS)
96+
let swiftUIRenderCondition = envEnable("OPENSWIFTUI_SWIFTUI_RENDER", default: true)
97+
#else
98+
let swiftUIRenderCondition = envEnable("OPENSWIFTUI_SWIFTUI_RENDER")
99+
#endif
100+
101+
if swiftUIRenderCondition {
102+
sharedCSettings.append(.define("_OPENSWIFTUI_SWIFTUI_RENDER"))
103+
sharedCxxSettings.append(.define("_OPENSWIFTUI_SWIFTUI_RENDER"))
104+
sharedSwiftSettings.append(.define("_OPENSWIFTUI_SWIFTUI_RENDER"))
105+
}
106+
93107
// MARK: - [env] OPENSWIFTUI_WERROR
94108

95109
let warningsAsErrorsCondition = envEnable("OPENSWIFTUI_WERROR", default: isXcodeEnv && development)
@@ -154,7 +168,7 @@ let openSwiftUICoreTarget = Target.target(
154168
"CoreGraphicsShims",
155169
.product(name: "OpenGraphShims", package: "OpenGraph"),
156170
.product(name: "OpenBoxShims", package: "OpenBox"),
157-
],
171+
] + (swiftUIRenderCondition ? ["OpenSwiftUISymbolDualTestsSupport"] : []),
158172
swiftSettings: sharedSwiftSettings
159173
)
160174

Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public import OpenSwiftUICore
1313
public import UIKit
1414
import OpenSwiftUI_SPI
1515

16+
import OpenSwiftUISymbolDualTestsSupport
17+
1618
final class UIHostingViewDebugLayer: CALayer {
1719
required init?(coder: NSCoder) {
1820
super.init(coder: coder)
@@ -48,19 +50,19 @@ open class _UIHostingView<Content>: UIView, XcodeViewDebugDataProvider where Con
4850
final package let viewGraph: ViewGraph
4951

5052
final package let renderer = DisplayList.ViewRenderer(platform: .init(definition: UIViewPlatformViewDefinition.self))
51-
53+
5254
// final package let eventBindingManager: EventBindingManager
5355

5456
package var currentTimestamp: Time = .zero
55-
57+
5658
package var propertiesNeedingUpdate: ViewRendererHostProperties = .all
5759

5860
package var renderingPhase: ViewRenderingPhase = .none
5961

6062
package var externalUpdateCount: Int = .zero
6163

6264
var parentPhase: _GraphInputs.Phase? = nil
63-
65+
6466
var isRotatingWindow: Bool = false
6567

6668
var allowUIKitAnimations: Int32 = .zero
@@ -109,7 +111,7 @@ open class _UIHostingView<Content>: UIView, XcodeViewDebugDataProvider where Con
109111
}
110112

111113
var initialInheritedEnvironment: EnvironmentValues? = nil
112-
114+
113115
var inheritedEnvironment: EnvironmentValues? = nil {
114116
didSet {
115117
invalidateProperties(.environment)
@@ -144,15 +146,15 @@ open class _UIHostingView<Content>: UIView, XcodeViewDebugDataProvider where Con
144146
var displayLink: DisplayLink? = nil
145147

146148
var lastRenderTime: Time = .zero
147-
149+
148150
var canAdvanceTimeAutomatically = true
149151

150152
var pendingPreferencesUpdate: Bool = false
151153

152154
var pendingPostDisappearPreferencesUpdate: Bool = false
153155

154156
var nextTimerTime: Time? = nil
155-
157+
156158
var updateTimer: Timer? = nil
157159

158160
var colorScheme: ColorScheme? = nil {
@@ -237,6 +239,10 @@ open class _UIHostingView<Content>: UIView, XcodeViewDebugDataProvider where Con
237239
super.init(frame: .zero)
238240
// TODO
239241
initializeViewGraph()
242+
// RepresentableContextValues.current =
243+
244+
renderer.host = self
245+
240246
// TODO
241247
HostingViewRegistry.shared.add(self)
242248
Update.end()
@@ -526,7 +532,31 @@ extension _UIHostingView: ViewRendererHost {
526532
) -> Time {
527533
func render() -> Time {
528534
let scale = window?.screen.scale ?? 1
529-
let environment = DisplayList.ViewRenderer.Environment(contentScale: scale)
535+
let environment = DisplayList.ViewRenderer.Environment(contentsScale: scale)
536+
#if canImport(SwiftUI, _underlyingVersion: 6.0.87) && _OPENSWIFTUI_SWIFTUI_RENDER
537+
return withUnsafePointer(to: list) { list in
538+
withUnsafePointer(to: time) { time in
539+
withUnsafePointer(to: nextTime) { nextTime in
540+
withUnsafePointer(to: version) { version in
541+
withUnsafePointer(to: maxVersion) { maxVersion in
542+
withUnsafePointer(to: environment) { environment in
543+
return renderer
544+
.swiftUI_render(
545+
rootView: self,
546+
from: list,
547+
time: time,
548+
nextTime: nextTime,
549+
version: version,
550+
maxVersion: maxVersion,
551+
environment: environment
552+
)
553+
}
554+
}
555+
}
556+
}
557+
}
558+
}
559+
#else
530560
return renderer.render(
531561
rootView: self,
532562
from: list,
@@ -536,6 +566,7 @@ extension _UIHostingView: ViewRendererHost {
536566
maxVersion: maxVersion,
537567
environment: environment
538568
)
569+
#endif
539570
}
540571

541572
if asynchronously {

Sources/OpenSwiftUI/Integration/Render/AppKit/NSViewPlatformViewDefinition.swift

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,29 @@ import AppKit
1212
// TODO
1313
final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sendable {
1414
override final class var system: PlatformViewDefinition.System { .nsView }
15-
16-
override class func makeView(kind: PlatformViewDefinition.ViewKind) -> AnyObject {
15+
16+
#if _OPENSWIFTUI_SWIFTUI_RENDER
17+
override static func makeView(kind: UnsafePointer<PlatformViewDefinition.ViewKind>) -> AnyObject {
18+
_makeView(kind: kind.pointee)
19+
}
20+
21+
override static func makeLayerView(type: CALayer.Type, kind: UnsafePointer<PlatformViewDefinition.ViewKind>) -> AnyObject {
1722
preconditionFailure("TODO")
1823
}
19-
20-
override class func makeLayerView(type: CALayer.Type, kind: PlatformViewDefinition.ViewKind) -> AnyObject {
24+
#else
25+
override static func makeView(kind: PlatformViewDefinition.ViewKind) -> AnyObject {
26+
_makeView(kind: kind)
27+
}
28+
29+
override static func makeLayerView(type: CALayer.Type, kind: UnsafePointer<PlatformViewDefinition.ViewKind>) -> AnyObject {
2130
preconditionFailure("TODO")
2231
}
32+
#endif
33+
34+
// FIXME: A shim for _OPENSWIFTUI_SWIFTUI_RENDER
35+
private static func _makeView(kind: PlatformViewDefinition.ViewKind) -> AnyObject {
36+
// TODO
37+
return NSView()
38+
}
2339
}
2440
#endif

Sources/OpenSwiftUI/Integration/Render/UIKit/UIViewPlatformViewDefinition.swift

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,69 @@
44
//
55
// Audited for iOS 18.0
66
// Status: WIP
7+
// ID: A34643117F00277B93DEBAB70EC06971 (SwiftUI?)
78

89
#if os(iOS)
910
@_spi(DisplayList_ViewSystem) import OpenSwiftUICore
1011
import UIKit
12+
import OpenSwiftUISymbolDualTestsSupport
1113

1214
// TODO
1315
final class UIViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sendable {
1416
override final class var system: PlatformViewDefinition.System { .uiView }
15-
16-
override class func makeView(kind: PlatformViewDefinition.ViewKind) -> AnyObject {
17+
18+
#if _OPENSWIFTUI_SWIFTUI_RENDER
19+
override static func makeView(kind: UnsafePointer<PlatformViewDefinition.ViewKind>) -> AnyObject {
20+
_makeView(kind: kind.pointee)
21+
}
22+
23+
override static func makeLayerView(type: CALayer.Type, kind: UnsafePointer<PlatformViewDefinition.ViewKind>) -> AnyObject {
1724
preconditionFailure("TODO")
1825
}
19-
20-
override class func makeLayerView(type: CALayer.Type, kind: PlatformViewDefinition.ViewKind) -> AnyObject {
26+
#else
27+
override static func makeView(kind: PlatformViewDefinition.ViewKind) -> AnyObject {
28+
_makeView(kind: kind)
29+
}
30+
31+
override static func makeLayerView(type: CALayer.Type, kind: UnsafePointer<PlatformViewDefinition.ViewKind>) -> AnyObject {
2132
preconditionFailure("TODO")
2233
}
34+
#endif
35+
36+
// FIXME: A shim for _OPENSWIFTUI_SWIFTUI_RENDER
37+
private static func _makeView(kind: PlatformViewDefinition.ViewKind) -> AnyObject {
38+
let view: UIView
39+
switch kind {
40+
case .mask:
41+
view = _UIGraphicsView()
42+
view.mask = _UIInheritedView()
43+
initView(view.mask!, kind: kind)
44+
default:
45+
view = kind.isContainer ? _UIInheritedView() : _UIGraphicsView()
46+
}
47+
initView(view, kind: kind)
48+
return view
49+
}
50+
51+
private static func initView(_ view: UIView, kind: PlatformViewDefinition.ViewKind) {
52+
if kind != .platformView && kind != .platformGroup {
53+
view.autoresizesSubviews = false
54+
if !kind.isContainer {
55+
// view._setFocusInteractionEnabled = false
56+
}
57+
}
58+
view.layer.anchorPoint = .zero
59+
switch kind {
60+
case .color, .image, .shape:
61+
// view.layer.setAllowsEdgeAntialiasing = true
62+
break
63+
case .geometry, .projection, .affine3D, .mask, .platformEffect:
64+
// view.layer.setAllowsGroupOpacity = false
65+
// view.layer.setAllowsGroupBlending = false
66+
break
67+
default:
68+
break
69+
}
70+
}
2371
}
2472
#endif

Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift

Lines changed: 68 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -155,15 +155,15 @@ extension DisplayList {
155155
indirect case backdrop(BackdropEffect)
156156
indirect case color(Color.Resolved)
157157
indirect case chameleonColor(fallback: Color.Resolved, filters: [GraphicsFilter])
158-
// indirect case image(GraphicsImage)
159-
// indirect case shape(Path, AnyResolvedPaint, FillStyle)
160-
// indirect case shadow(Path, ResolvedShadowStyle)
161-
// indirect case platformView(any PlatformViewFactory)
162-
// indirect case platformLayer(any PlatformLayerFactory)
163-
// indirect case text(StyledTextContentView, CGSize)
164-
// indirect case flattened(DisplayList, CGPoint, RasterizationOptions)
165-
// indirect case drawing(any RenderBox.RBDisplayListContents, CGPoint, RasterizationOptions)
166-
// indirect case view(any _DisplayList_ViewFactory)
158+
indirect case image(GraphicsImage)
159+
indirect case shape(Path, AnyResolvedPaint, FillStyle)
160+
indirect case shadow(Path, ResolvedShadowStyle)
161+
indirect case platformView(any PlatformViewFactory)
162+
indirect case platformLayer(any PlatformLayerFactory)
163+
indirect case text(StyledTextContentView, CGSize)
164+
indirect case flattened(DisplayList, CGPoint, RasterizationOptions)
165+
indirect case drawing(any RBDisplayListContents, CGPoint, RasterizationOptions)
166+
indirect case view(any _DisplayList_ViewFactory)
167167
case placeholder(id: Identity)
168168
}
169169
package init(_ value: Content.Value, seed: Seed) {
@@ -173,30 +173,30 @@ extension DisplayList {
173173
}
174174

175175
// package typealias ViewFactory = _DisplayList_ViewFactory
176-
176+
177177
package enum Effect {
178178
case identity
179179
case geometryGroup
180180
case compositingGroup
181181
case backdropGroup(Bool)
182182
indirect case archive(ArchiveIDs?)
183183
case properties(Properties)
184-
// indirect case platformGroup(any PlatformGroupFactory)
184+
indirect case platformGroup(any PlatformGroupFactory)
185185
case opacity(Float)
186-
// case blendMode(GraphicsBlendMode)
187-
// indirect case clip(Path, FillStyle, _: GraphicsContext.ClipOptions = .init())
188-
// indirect case mask(DisplayList, _: GraphicsContext.ClipOptions = .init())
189-
// indirect case transform(Transform)
190-
// indirect case filter(GraphicsFilter)
191-
// indirect case animation(any _DisplayList_AnyEffectAnimation)
192-
// indirect case contentTransition(ContentTransition.State)
193-
// indirect case view(any _DisplayList_ViewFactory)
194-
// indirect case accessibility([AccessibilityNodeAttachment])
195-
// indirect case platform(PlatformEffect)
186+
case blendMode(GraphicsBlendMode)
187+
indirect case clip(Path, FillStyle, _: GraphicsContext.ClipOptions = .init())
188+
indirect case mask(DisplayList, _: GraphicsContext.ClipOptions = .init())
189+
indirect case transform(Transform)
190+
indirect case filter(GraphicsFilter)
191+
indirect case animation(any _DisplayList_AnyEffectAnimation)
192+
indirect case contentTransition(ContentTransition.State)
193+
indirect case view(any _DisplayList_ViewFactory)
194+
indirect case accessibility([AccessibilityNodeAttachment])
195+
indirect case platform(PlatformEffect)
196196
indirect case state(StrongHash)
197-
// indirect case interpolatorRoot(InterpolatorGroup, contentOrigin: CGPoint, contentOffset: CGSize)
198-
// case interpolatorLayer(InterpolatorGroup, serial: UInt32)
199-
// indirect case interpolatorAnimation(InterpolatorAnimation)
197+
indirect case interpolatorRoot(InterpolatorGroup, contentOrigin: CGPoint, contentOffset: CGSize)
198+
case interpolatorLayer(InterpolatorGroup, serial: UInt32)
199+
indirect case interpolatorAnimation(InterpolatorAnimation)
200200
}
201201

202202
package enum Transform {
@@ -220,10 +220,10 @@ extension DisplayList {
220220
}
221221
}
222222

223-
// package struct InterpolatorAnimation {
224-
// package var value: StrongHash?
225-
// package var animation: Animation?
226-
// }
223+
package struct InterpolatorAnimation {
224+
package var value: StrongHash?
225+
package var animation: Animation?
226+
}
227227

228228
package struct Version: Comparable, Hashable {
229229
private static var lastValue: Int = .zero
@@ -438,3 +438,43 @@ extension DisplayList.Item {
438438
[]
439439
}
440440
}
441+
442+
// TODO
443+
444+
extension DisplayList {
445+
// FIXME
446+
package class InterpolatorGroup {}
447+
}
448+
449+
package struct AccessibilityNodeAttachment {}
450+
451+
extension GraphicsContext {
452+
@frozen
453+
public struct ClipOptions: OptionSet {
454+
public let rawValue: UInt32
455+
456+
public init(rawValue: UInt32) {
457+
self.rawValue = rawValue
458+
}
459+
}
460+
}
461+
462+
package protocol PlatformGroupFactory {}
463+
package protocol _DisplayList_AnyEffectAnimation {}
464+
465+
public struct ContentTransition {
466+
package struct State {}
467+
}
468+
package protocol _DisplayList_ViewFactory {}
469+
470+
package protocol PlatformViewFactory {}
471+
package protocol PlatformLayerFactory {}
472+
473+
package struct GraphicsImage {}
474+
package struct ResolvedShadowStyle {}
475+
476+
package struct StyledTextContentView {}
477+
package struct RasterizationOptions {}
478+
package protocol RBDisplayListContents {} // RenderBox.RBDisplayListContents
479+
public struct PlatformDrawableOptions {}
480+
public protocol PlatformDrawable : AnyObject {}

0 commit comments

Comments
 (0)