Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,14 @@

import SnapshotTesting
import Testing
@testable import TestingHost

@MainActor
@Suite(.snapshots(record: .never, diffTool: diffTool))
struct GeometryReaderUITests {
@Test(.bug("https://github.com/OpenSwiftUIProject/OpenSwiftUI/issues/474"))
func centerView() {
struct ContentView: View {
var body: some View {
GeometryReader { proxy in
Color.blue
.frame(
width: proxy.size.width / 2,
height: proxy.size.height / 2,
)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.yellow.opacity(0.3))
}
}
}
openSwiftUIAssertSnapshot(of: ContentView())
#if os(iOS)
#if OPENSWIFTUI
withKnownIssue {
openSwiftUIAssertSnapshot(of: ContentView(), as: .image)
}
#else
openSwiftUIAssertSnapshot(of: ContentView(), as: .image)
#endif
#endif
openSwiftUIAssertSnapshot(of: GeometryReaderExample())
}

@Test
Expand Down
2 changes: 0 additions & 2 deletions Example/Shared/Layout/Geometry/GeometryReaderExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import OpenSwiftUI
import SwiftUI
#endif

// FIXME: SwiftUI yellow background will ignoreSafeArea while OpenSwiftUI will have it.
// See #474
struct GeometryReaderExample: View {
var body: some View {
GeometryReader { geometry in
Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenSwiftUICore/Layout/Geometry/Anchor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ private class AnchorValueBox<T>: AnchorValueBoxBase<T.AnchorValue>, @unchecked S
}

override func convert(to transform: ViewTransform) -> T.AnchorValue {
_openSwiftUIUnimplementedFailure()
var value = value
value.convert(to: .global, transform: transform)
return value
}

override func isEqual(to other: AnchorValueBoxBase<T.AnchorValue>) -> Bool {
Expand Down
56 changes: 36 additions & 20 deletions Sources/OpenSwiftUICore/Layout/Geometry/GeometryReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
// OpenSwiftUICore
//
// Audited for 6.5.4
// Status: WIP
// Status: Complete
// ID: 7D6D22DF7076CCC1FC5284D8E2D1B049 (SwiftUICore)

public import Foundation
package import OpenAttributeGraphShims
import OpenSwiftUI_SPI

// MARK: - GeometryReader [WIP]
// MARK: - GeometryReader

/// A container view that defines its content as a function of its own size and
/// coordinate space.
Expand Down Expand Up @@ -80,7 +80,7 @@ public struct GeometryReader<Content>: View, UnaryView, PrimitiveView where Cont
mutating func updateValue() {
seed &+= 1
let proxy = GeometryProxy(
owner: .current!,
owner: attribute.identifier,
size: $size,
environment: $environment,
transform: $transform,
Expand All @@ -101,7 +101,7 @@ public struct GeometryReader<Content>: View, UnaryView, PrimitiveView where Cont
@available(*, unavailable)
extension GeometryReader: Sendable {}

// MARK: - GeometryProxy [WIP]
// MARK: - GeometryProxy

/// A proxy for access to the size and coordinate space (for anchor resolution)
/// of the container view.
Expand Down Expand Up @@ -169,7 +169,9 @@ public struct GeometryProxy {

/// Resolves the value of an anchor to the container view.
public subscript<T>(anchor: Anchor<T>) -> T {
_openSwiftUIUnimplementedFailure()
Update.perform {
placementContext.map { anchor.in($0) } ?? anchor.defaultValue
}
}

/// The safe area inset of the container view.
Expand All @@ -188,28 +190,41 @@ public struct GeometryProxy {
@available(*, deprecated, message: "use overload that accepts a CoordinateSpaceProtocol instead")
@_disfavoredOverload
public func frame(in coordinateSpace: CoordinateSpace) -> CGRect {
let size = size
return Update.perform {
guard let placementContext else {
return .zero
}
var rect = CGRect(origin: .zero, size: size)
rect.convert(from: placementContext, to: coordinateSpace)
return rect
}
rect(CGRect(origin: .zero, size: size), in: coordinateSpace)
}

@_spi(Private)
public func frameClippedToScrollViews(in space: CoordinateSpace) -> (frame: CGRect, exact: Bool) {
_openSwiftUIUnimplementedFailure()
Update.perform {
var rect = CGRect(origin: .zero, size: size)
guard let placementContext else {
return (rect, true)
}
let exact = rect.whileClippingToScrollViewsConvert(
to: space,
transform: placementContext.transform
)
return (rect, exact)
}
}

package func rect(_ r: CGRect, in coordinateSpace: CoordinateSpace) -> CGRect {
_openSwiftUIUnimplementedFailure()
Update.perform {
var rect = r
placementContext.map { rect.convert(from: $0, to: coordinateSpace) }

@augmentcode augmentcode Bot Jun 14, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GeometryProxy.rect(_:in:) returns the input rect unchanged when placementContext is nil, which can make frame(in:) report a local-space rect even when the caller requests a different coordinate space (previously this path returned .zero). Consider handling the nil-context case consistently to avoid silently incorrect frames.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

return rect
}
}

package var transform: ViewTransform {
_openSwiftUIUnimplementedFailure()
Update.perform {
guard let transform = _transform.attribute,
let position = _position.attribute
else {
return ViewTransform()
}
return context[transform].withPosition(context[position])
}
}

package var environment: EnvironmentValues {
Expand Down Expand Up @@ -244,13 +259,13 @@ extension GeometryProxy {
/// Returns the given coordinate space's bounds rectangle, converted to the
/// local coordinate space.
public func bounds(of coordinateSpace: NamedCoordinateSpace) -> CGRect? {
_openSwiftUIUnimplementedFailure()
transform.containingSizedCoordinateSpace(name: coordinateSpace.name)
}

/// Returns the container view's bounds rectangle, converted to a defined
/// coordinate space.
public func frame(in coordinateSpace: some CoordinateSpaceProtocol) -> CGRect {
_openSwiftUIUnimplementedFailure()
rect(CGRect(origin: .zero, size: size), in: coordinateSpace.coordinateSpace)
}
}

Expand All @@ -260,7 +275,8 @@ extension GeometryProxy {
globalPoint: CGPoint,
to coordinateSpace: some CoordinateSpaceProtocol,
) -> CGPoint {
_openSwiftUIUnimplementedFailure()
// TBA: ViewTransform
transform.convert(.localToSpace(coordinateSpace.coordinateSpace), point: globalPoint)
}

@augmentcode augmentcode Bot Jun 14, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GeometryProxy.convert(globalPoint:to:) takes a globalPoint but calls transform.convert(.localToSpace(...), point: globalPoint), which looks like an inverted conversion direction for this API and could yield incorrect coordinates. If this is intentional, it might be worth clarifying the expected input space here.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

}

Expand Down
6 changes: 5 additions & 1 deletion Sources/OpenSwiftUICore/Layout/View/ViewTransform.swift
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,11 @@ public struct ViewTransform: Equatable, CustomStringConvertible {
}

package func containingSizedCoordinateSpace(name: CoordinateSpace.Name) -> CGRect? {
_openSwiftUIUnimplementedFailure()
var rect: CGRect?
forEach { item, _ in
item.apply(to: &rect, name: name)
}
return rect
}

public var description: String {
Expand Down
Loading
Loading