diff --git a/Package.swift b/Package.swift index d58947a63..24b7d01a5 100644 --- a/Package.swift +++ b/Package.swift @@ -115,6 +115,19 @@ let swiftLogCondition = envEnable("OPENSWIFTUI_SWIFT_LOG", default: !buildForDar let swiftCryptoCondition = envEnable("OPENSWIFTUI_SWIFT_CRYPTO", default: !buildForDarwinPlatform) +// MARK: - [env] OPENSWIFTUI_RENDER_GTK + +let renderGTKCondition = envEnable("OPENSWIFTUI_RENDER_GTK", default: !buildForDarwinPlatform) + +let cgtkTarget = Target.systemLibrary( + name: "CGTK", + pkgConfig: "gtk4", + providers: [ + .brew(["gtk4"]), + .apt(["libgtk-4-dev clang"]), + ] +) + // MARK: - [env] OPENGSWIFTUI_SWIFTUI_RENDER let swiftUIRenderCondition = envEnable("OPENSWIFTUI_SWIFTUI_RENDER", default: buildForDarwinPlatform) @@ -153,9 +166,10 @@ if libraryEvolutionCondition && !openCombineCondition && !swiftLogCondition { // MARK: - [env] OPENSWIFTUI_COMPATIBILITY_TEST let compatibilityTestCondition = envEnable("OPENSWIFTUI_COMPATIBILITY_TEST") - -if compatibilityTestCondition { - sharedSwiftSettings.append(.define("OPENSWIFTUI_COMPATIBILITY_TEST")) +sharedCSettings.append(.define("OPENSWIFTUI", to: compatibilityTestCondition ? "0" : "1")) +sharedCxxSettings.append(.define("OPENSWIFTUI", to: compatibilityTestCondition ? "0" : "1")) +if !compatibilityTestCondition { + sharedSwiftSettings.append(.define("OPENSWIFTUI")) } // MARK: - [env] OPENSWIFTUI_IGNORE_AVAILABILITY @@ -268,6 +282,8 @@ let openSwiftUITestsSupportTarget = Target.target( dependencies: [ "OpenSwiftUI", ], + cSettings: sharedCSettings, + cxxSettings: sharedCxxSettings, swiftSettings: sharedSwiftSettings ) @@ -396,36 +412,48 @@ let package = Package( .package(url: "https://github.com/apple/swift-numerics", from: "1.0.3"), ], targets: [ - // TODO: Add SwiftGTK as an backend alternative for UIKit/AppKit on Linux and macOS - .systemLibrary( - name: "CGTK", - pkgConfig: "gtk4", - providers: [ - .brew(["gtk4"]), - .apt(["libgtk-4-dev clang"]), - ] - ), coreGraphicsShimsTarget, - coreGraphicsShimsTestTarget, - openSwiftUISPITarget, - openSwiftUISPITestTarget, - openSwiftUICoreTarget, - openSwiftUICoreTestTarget, - cOpenSwiftUITarget, openSwiftUITarget, openSwiftUITestsSupportTarget, openSwiftUIExtensionTarget, - openSwiftUITestTarget, - openSwiftUICompatibilityTestTarget, - openSwiftUIBridgeTarget, - openSwiftUIBridgeTestTarget, ] ) +if renderGTKCondition { + package.targets.append(cgtkTarget) +} + +if !compatibilityTestCondition { + package.targets.append(contentsOf: [ + coreGraphicsShimsTestTarget, + openSwiftUISPITestTarget, + openSwiftUICoreTestTarget, + openSwiftUITestTarget, + openSwiftUIBridgeTestTarget, + ]) +} + +if buildForDarwinPlatform { + package.targets.append(openSwiftUICompatibilityTestTarget) +} + +// MARK: - SymbolLocator + +if symbolLocatorCondition { + package.dependencies.append( + .package(url: "https://github.com/OpenSwiftUIProject/SymbolLocator.git", from: "0.2.0") + ) + + package.targets += [ + openSwiftUISymbolDualTestsSupportTarget, + openSwiftUISymbolDualTestsTarget, + ] +} + extension Target { func addAGSettings() { // FIXME: Weird SwiftPM behavior for test Target. Otherwize we'll get the following error message @@ -557,19 +585,6 @@ if swiftCryptoCondition { openSwiftUITarget.addSwiftCryptoSettings() } -// MARK: - SymbolLocator - -if symbolLocatorCondition { - package.dependencies.append( - .package(url: "https://github.com/OpenSwiftUIProject/SymbolLocator.git", from: "0.2.0") - ) - - package.targets += [ - openSwiftUISymbolDualTestsSupportTarget, - openSwiftUISymbolDualTestsTarget, - ] -} - extension [Platform] { static var darwinPlatforms: [Platform] { [.macOS, .iOS, .macCatalyst, .tvOS, .watchOS, .visionOS] diff --git a/Sources/OpenSwiftUI/Integration/Hosting/AppKit/Controller/NSHostingController.swift b/Sources/OpenSwiftUI/Integration/Hosting/AppKit/Controller/NSHostingController.swift index 03079e0b3..381f5cf4a 100644 --- a/Sources/OpenSwiftUI/Integration/Hosting/AppKit/Controller/NSHostingController.swift +++ b/Sources/OpenSwiftUI/Integration/Hosting/AppKit/Controller/NSHostingController.swift @@ -140,12 +140,9 @@ open class NSHostingController: NSViewController where Content: View { return result } - public func _forEachIdentifiedView(body: (_IdentifiedViewProxy) -> Void) { host.forEachIdentifiedView(body: body) } - - } #endif diff --git a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift index 81286e9d1..b0a5e98c2 100644 --- a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift +++ b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift @@ -295,7 +295,11 @@ open class _UIHostingView: UIView, XcodeViewDebugDataProvider where Con UIEdgeInsets(top: explicitSafeAreaInsets.top, left: explicitSafeAreaInsets.leading, bottom: explicitSafeAreaInsets.bottom, right: explicitSafeAreaInsets.trailing) } } - + + override dynamic open func sizeThatFits(_ size: CGSize) -> CGSize { + base._layoutSizeThatFits(size) + } + // FIXME final public func _viewDebugData() -> [_ViewDebug.Data] { // TODO diff --git a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingViewBase.swift b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingViewBase.swift index 13b944d4c..23973df22 100644 --- a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingViewBase.swift +++ b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingViewBase.swift @@ -168,6 +168,22 @@ package class UIHostingViewBase { } } + func _layoutSizeThatFits( + _ size: CGSize + // fixedAxes: _UILayoutAxes + ) -> CGSize { + guard let host else { + return .zero + } + let maxValue = 2777780.0 + let fittingSize = host.sizeThatFits(.init( + width: size.width >= maxValue ? nil : size.width, + height: size.height >= maxValue ? nil : size.height + )) + let pixelLength = host.viewGraph.environment.pixelLength + return fittingSize.rounded(.up, toMultipleOf: pixelLength) + } + // func _baselineOffsets(at: CGSize) -> _UIBaselineOffsetPair // MARK: - Update diff --git a/Sources/OpenSwiftUICore/View/Graph/ViewGraph.swift b/Sources/OpenSwiftUICore/View/Graph/ViewGraph.swift index fb55692b3..4688d0c65 100644 --- a/Sources/OpenSwiftUICore/View/Graph/ViewGraph.swift +++ b/Sources/OpenSwiftUICore/View/Graph/ViewGraph.swift @@ -466,10 +466,42 @@ extension ViewGraph { //package typealias SizeThatFitsObservers = ViewGraphGeometryObservers extension ViewGraph { + private var layoutComputer: LayoutComputer? { + guard requestedOutputs.contains(.layout) else { + preconditionFailure("Cannot fetch layout computer without layout output") + } + instantiateIfNeeded() + return rootLayoutComputer + } + + private var rootViewInsets: EdgeInsets { + guard !safeAreaInsets.elements.isEmpty else { + return .zero + } + // FIXME + return .zero + } + + static func sizeThatFits( + _ proposal: _ProposedSize, + layoutComputer: LayoutComputer?, + insets: EdgeInsets + ) -> CGSize { + var proposal = proposal + proposal.width = proposal.width.map { max($0 - insets.horizontal, .zero) } + proposal.height = proposal.width.map { max($0 - insets.vertical, .zero) } + let fittingSize = if let layoutComputer { + layoutComputer.sizeThatFits(proposal) + } else { + CGSize(width: 10.0, height: 10.0) + } + return fittingSize.outset(by: insets) + } + package func sizeThatFits(_ proposal: _ProposedSize) -> CGSize { - _openSwiftUIUnimplementedFailure() + Self.sizeThatFits(proposal, layoutComputer: layoutComputer, insets: rootViewInsets) } - + package func explicitAlignment(of guide: VerticalAlignment, at size: CGSize) -> CGFloat? { _openSwiftUIUnimplementedFailure() } diff --git a/Sources/OpenSwiftUICore/View/Graph/ViewRendererHost.swift b/Sources/OpenSwiftUICore/View/Graph/ViewRendererHost.swift index e08940735..9119760bf 100644 --- a/Sources/OpenSwiftUICore/View/Graph/ViewRendererHost.swift +++ b/Sources/OpenSwiftUICore/View/Graph/ViewRendererHost.swift @@ -373,8 +373,7 @@ extension ViewRendererHost { } package func sizeThatFits(_ proposal: _ProposedSize) -> CGSize { - updateViewGraph { $0.sizeThatFits(proposal) - } + updateViewGraph { $0.sizeThatFits(proposal) } } package func explicitAlignment(of guide: HorizontalAlignment, at size: CGSize) -> CGFloat? { updateViewGraph { $0.explicitAlignment(of: guide, at: size) } diff --git a/Sources/OpenSwiftUITestsSupport/Integration/PlatformAlias.swift b/Sources/OpenSwiftUITestsSupport/Integration/PlatformAlias.swift index 6f0d9ed19..a361a9977 100644 --- a/Sources/OpenSwiftUITestsSupport/Integration/PlatformAlias.swift +++ b/Sources/OpenSwiftUITestsSupport/Integration/PlatformAlias.swift @@ -2,10 +2,10 @@ // PlatformAlias.swift // OpenSwiftUITestsSupport -#if OPENSWIFTUI_COMPATIBILITY_TEST -package import SwiftUI -#else +#if OPENSWIFTUI package import OpenSwiftUI +#else +package import SwiftUI #endif #if os(iOS) diff --git a/Sources/OpenSwiftUITestsSupport/Integration/PlatformHostingControllerHelper.swift b/Sources/OpenSwiftUITestsSupport/Integration/PlatformHostingControllerHelper.swift index f16126298..625918dda 100644 --- a/Sources/OpenSwiftUITestsSupport/Integration/PlatformHostingControllerHelper.swift +++ b/Sources/OpenSwiftUITestsSupport/Integration/PlatformHostingControllerHelper.swift @@ -32,7 +32,7 @@ extension PlatformHostingController { // FIXME: A workaround to bypass the Issue #87 package func workaroundIssue87(_ vc: PlatformViewController) { - #if !OPENSWIFTUI_COMPATIBILITY_TEST + #if OPENSWIFTUI // TODO: Use swift-test exist test feature to detect the crash instead or sliently workaroun it CrashWorkaround.shared.objects.append(vc) #endif diff --git a/Tests/OpenSwiftUICompatibilityTests/Animation/Animation/AnimationCompatibilityTests.swift b/Tests/OpenSwiftUICompatibilityTests/Animation/Animation/AnimationCompatibilityTests.swift index 2b263da53..1beb5f419 100644 --- a/Tests/OpenSwiftUICompatibilityTests/Animation/Animation/AnimationCompatibilityTests.swift +++ b/Tests/OpenSwiftUICompatibilityTests/Animation/Animation/AnimationCompatibilityTests.swift @@ -9,10 +9,10 @@ struct AnimationCompatibilityTests { func description() { let animation = Animation.default #expect(animation.description == "DefaultAnimation()") - #if OPENSWIFTUI_COMPATIBILITY_TEST - #expect(animation.debugDescription == "AnyAnimator(SwiftUI.DefaultAnimation())") - #else + #if OPENSWIFTUI #expect(animation.debugDescription == "AnyAnimator(OpenSwiftUICore.DefaultAnimation())") + #else + #expect(animation.debugDescription == "AnyAnimator(SwiftUI.DefaultAnimation())") #endif #expect(animation.customMirror.description == "Mirror for Animation") } diff --git a/Tests/OpenSwiftUICompatibilityTests/Export.swift b/Tests/OpenSwiftUICompatibilityTests/Export.swift index 2d9c43305..444ddde3c 100644 --- a/Tests/OpenSwiftUICompatibilityTests/Export.swift +++ b/Tests/OpenSwiftUICompatibilityTests/Export.swift @@ -2,10 +2,10 @@ // Export.swift // OpenSwiftUICompatibilityTests -#if OPENSWIFTUI_COMPATIBILITY_TEST -@_exported import SwiftUI -let compatibilityTestEnabled = true -#else +#if OPENSWIFTUI @_exported import OpenSwiftUI let compatibilityTestEnabled = false +#else +@_exported import SwiftUI +let compatibilityTestEnabled = true #endif diff --git a/Tests/OpenSwiftUICompatibilityTests/Graphics/Color/ColorResolvedTests.swift b/Tests/OpenSwiftUICompatibilityTests/Graphics/Color/ColorResolvedTests.swift index d4602a251..a762597dd 100644 --- a/Tests/OpenSwiftUICompatibilityTests/Graphics/Color/ColorResolvedTests.swift +++ b/Tests/OpenSwiftUICompatibilityTests/Graphics/Color/ColorResolvedTests.swift @@ -3,7 +3,7 @@ // OpenSwiftUICompatibilityTests import Testing -#if !OPENSWIFTUI_COMPATIBILITY_TEST +#if OPENSWIFTUI @_spi(ForTestOnly) import OpenSwiftUI #endif @@ -38,23 +38,23 @@ struct ColorResolvedTests { swiftUIExpected: String, openSwiftUIExpected: String ) { - #if OPENSWIFTUI_COMPATIBILITY_TEST - guard #available(iOS 17, macOS 14, *) else { - print("This test is not available") - return - } - let resolved = Color.Resolved(colorSpace: colorSpace, red: red, green: green, blue: blue, opacity: opacity) - #expect(resolved.description == swiftUIExpected) - #else + #if OPENSWIFTUI Update.locked { Color.Resolved._alignWithSwiftUIImplementation = false let resolved = Color.Resolved(colorSpace: colorSpace, red: red, green: green, blue: blue, opacity: opacity) #expect(resolved.description == openSwiftUIExpected) - + Color.Resolved._alignWithSwiftUIImplementation = true let resolved2 = Color.Resolved(colorSpace: colorSpace, red: red, green: green, blue: blue, opacity: opacity) #expect(resolved2.description == swiftUIExpected) } + #else + guard #available(iOS 17, macOS 14, *) else { + print("This test is not available") + return + } + let resolved = Color.Resolved(colorSpace: colorSpace, red: red, green: green, blue: blue, opacity: opacity) + #expect(resolved.description == swiftUIExpected) #endif } } diff --git a/Tests/OpenSwiftUICompatibilityTests/README.md b/Tests/OpenSwiftUICompatibilityTests/README.md index f6a5a6b2d..0b1ecf0a5 100644 --- a/Tests/OpenSwiftUICompatibilityTests/README.md +++ b/Tests/OpenSwiftUICompatibilityTests/README.md @@ -3,9 +3,9 @@ Test public API of OpenSwiftUI and run it against with SwiftUI on Apple Platform. ```swift -#if OPENSWIFTUI_COMPATIBILITY_TEST -import SwiftUI -#else +#if OPENSWIFTUI import OpenSwiftUI +#else +import SwiftUI #endif ``` diff --git a/Tests/OpenSwiftUICompatibilityTests/View/Debug/ChangedBodyPropertyTests.swift b/Tests/OpenSwiftUICompatibilityTests/View/Debug/ChangedBodyPropertyTests.swift index 2ea291e7c..8047f6685 100644 --- a/Tests/OpenSwiftUICompatibilityTests/View/Debug/ChangedBodyPropertyTests.swift +++ b/Tests/OpenSwiftUICompatibilityTests/View/Debug/ChangedBodyPropertyTests.swift @@ -16,19 +16,17 @@ struct ChangedBodyPropertyTests { let entries = try store .getEntries(at: position) // getEntries's with and at param is not respected on iOS, so I have to use last then. .compactMap { $0 as? OSLogEntryLog } - #if OPENSWIFTUI_COMPATIBILITY_TEST - .filter { $0.subsystem == "com.apple.SwiftUI" && $0.category == "Changed Body Properties" } - #else + #if OPENSWIFTUI .filter { $0.subsystem == "org.OpenSwiftUIProject.OpenSwiftUI" && $0.category == "Changed Body Properties" } + #else + .filter { $0.subsystem == "com.apple.SwiftUI" && $0.category == "Changed Body Properties" } #endif .map { $0.composedMessage } #expect(entries.last == expected) } - #if OPENSWIFTUI_COMPATIBILITY_TEST + #if !OPENSWIFTUI @available(iOS 17.1, macOS 14.1, *) - #else - @available(iOS 15, macOS 12, *) #endif @Test func zeroPropertyView() throws { @@ -44,10 +42,8 @@ struct ChangedBodyPropertyTests { try verifyLog(expected: "ChangedBodyPropertyTests.ContentView: @self changed.") } - #if OPENSWIFTUI_COMPATIBILITY_TEST + #if !OPENSWIFTUI @available(iOS 17.1, macOS 14.1, *) - #else - @available(iOS 15, macOS 12, *) #endif @Test func propertyView() throws { @@ -64,10 +60,8 @@ struct ChangedBodyPropertyTests { try verifyLog(expected: "ChangedBodyPropertyTests.ContentView: @self changed.") } - #if OPENSWIFTUI_COMPATIBILITY_TEST + #if !OPENSWIFTUI @available(iOS 17.1, macOS 14.1, *) - #else - @available(iOS 15, macOS 12, *) #endif @Test func statePropertyView() throws { diff --git a/Tests/OpenSwiftUICompatibilityTests/View/EquatableViewTests.swift b/Tests/OpenSwiftUICompatibilityTests/View/EquatableViewTests.swift index 7ffd7b9c9..1016664de 100644 --- a/Tests/OpenSwiftUICompatibilityTests/View/EquatableViewTests.swift +++ b/Tests/OpenSwiftUICompatibilityTests/View/EquatableViewTests.swift @@ -137,7 +137,7 @@ struct EquatableViewTests { } } - #if !OPENSWIFTUI_COMPATIBILITY_TEST + #if OPENSWIFTUI struct Number: Equatable { var value: Int diff --git a/Tests/OpenSwiftUICoreTests/Layout/Modifier/FrameLayoutTests.swift b/Tests/OpenSwiftUICoreTests/Layout/Modifier/FrameLayoutTests.swift index 4e22474b6..782fe4870 100644 --- a/Tests/OpenSwiftUICoreTests/Layout/Modifier/FrameLayoutTests.swift +++ b/Tests/OpenSwiftUICoreTests/Layout/Modifier/FrameLayoutTests.swift @@ -2,8 +2,10 @@ // FrameLayoutTests.swift // OpenSwiftUICoreTests +import Foundation import Numerics @testable import OpenSwiftUICore +import OpenSwiftUITestsSupport import Testing // MARK: - FlexFrameLayoutTests @@ -160,4 +162,22 @@ struct FlexFrameLayoutTests { #expect(layout.idealHeight == nil) #expect(layout.maxHeight == nil) } + + #if canImport(Darwin) + @MainActor + @Test + func maxWidthInfinityExpandsToParentProposal() { + struct ContentView: View { + var body: some View { + Color.red + .frame(maxWidth: .infinity) + .frame(width: 200, height: 200) + } + } + let viewController = PlatformHostingController(rootView: ContentView()) + viewController.triggerLayout() + let size = viewController.sizeThatFits(in: .zero) + #expect(size == CGSize(width: 200, height: 200)) + } + #endif }