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 @@ -13,13 +13,13 @@ import OpenSwiftUI_SPI
// MARK: - ContentResponder

package protocol ContentResponder {
func contains(points: UnsafeBufferPointer<CGPoint>, size: CGSize) -> BitVector64
func contains(points: UnsafeBufferPointer<PlatformPoint>, size: CGSize) -> BitVector64
func contentPath(size: CGSize) -> Path
func contentPath(size: CGSize, kind: ContentShapeKinds) -> Path
}

extension ContentResponder {
package func contains(points: UnsafeBufferPointer<CGPoint>, size: CGSize) -> BitVector64 {
package func contains(points: UnsafeBufferPointer<PlatformPoint>, size: CGSize) -> BitVector64 {
points.mapBool { size.contains(point: $0) }
}

Expand Down
31 changes: 19 additions & 12 deletions Sources/OpenSwiftUICore/Graphic/Color/ColorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,44 @@
// ColorView.swift
// OpenSwiftUICore
//
// Audited for 6.0.87
// Status: Empty
// Audited for 6.5.4
// Status: Complete

package import Foundation

package struct ColorView: RendererLeafView, Animatable {
package var color: Color.Resolved

package init(_ color: Color.Resolved) {
self.color = color
}

nonisolated package static func _makeView(view: _GraphValue<ColorView>, inputs: _ViewInputs) -> _ViewOutputs {
nonisolated package static func _makeView(
view: _GraphValue<ColorView>,
inputs: _ViewInputs
) -> _ViewOutputs {
let animatable = makeAnimatable(value: view, inputs: inputs.base)
return makeLeafView(view: .init(animatable), inputs: inputs)
}

package var descriptionAttributes: [(name: String, value: String)] {
_openSwiftUIUnimplementedFailure()
guard color != .clear else { return [] }
return [(name: "color", value: "\((color.red, color.green, color.blue, color.opacity))")]
}

package func contains(points: UnsafeBufferPointer<CGPoint>, size: CGSize) -> BitVector64 {
_openSwiftUIUnimplementedFailure()

package func contains(points: UnsafeBufferPointer<PlatformPoint>, size: CGSize) -> BitVector64 {
guard color.opacity > 0 else { return BitVector64() }
return points.mapBool {
min($0.x, $0.y) >= 0 && $0.x < size.width && $0.y < size.height
}
}

package func content() -> DisplayList.Content.Value {
.color(color)
}

package var animatableData: Color.Resolved.AnimatableData {
get { color.animatableData }
get { color.animatableData }
set { color.animatableData = newValue }
}
}
6 changes: 3 additions & 3 deletions Sources/OpenSwiftUICore/Render/RendererLeafView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ extension RendererLeafView {
package static var requiresMainThread: Bool {
false
}

package func contains(
points: UnsafeBufferPointer<CGPoint>,
points: UnsafeBufferPointer<PlatformPoint>,
size: CGSize
) -> BitVector64 {
points.mapBool { size.contains(point: $0) }
}

package static func makeLeafView(
view: _GraphValue<Self>,
inputs: _ViewInputs
Expand Down
16 changes: 15 additions & 1 deletion Sources/OpenSwiftUICore/Shape/Path.swift
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,21 @@ public struct Path: Equatable, LosslessStringConvertible, @unchecked Sendable {
_openSwiftUIUnimplementedFailure()
}

package func contains(points: [CGPoint], eoFill: Bool = false, origin: CGPoint = .zero) -> BitVector64 {
package func contains(
points: [PlatformPoint],
eoFill: Bool = false,
origin: CGPoint = .zero
) -> BitVector64 {
points.withUnsafeBufferPointer {
contains(points: $0, eoFill: eoFill, origin: origin)
}
}

package func contains(
points: UnsafeBufferPointer<PlatformPoint>,
eoFill: Bool = false,
origin: CGPoint = .zero
) -> BitVector64 {
_openSwiftUIUnimplementedFailure()
}

Expand Down
147 changes: 118 additions & 29 deletions Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyledLeafView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
// OpenSwiftUICore
//
// Audited for 6.5.4
// Status: WIP
// Status: Complete
// ID: E1641985C375D8826E6966D4F238A1B8 (SwiftUICore)

package import Foundation
package import OpenAttributeGraphShims
package import OpenCoreGraphicsShims

// MARK: - ShapeStyledLeafView

package protocol ShapeStyledLeafView: ContentResponder {
static var animatesSize: Bool { get }
Expand All @@ -33,19 +36,50 @@ extension ShapeStyledLeafView {
package static var hasBackground: Bool { false }

package func backgroundShape(in size: CGSize) -> FramedShape {
(shape: .path(Path(), FillStyle()), frame: .zero)
(shape: .empty, frame: .zero)
}

package func isClear(styles: ShapeStyle.Pack) -> Bool {
styles.isClear(name: .foreground) && styles.isClear(name: .background)
}

package func contains(points: UnsafeBufferPointer<CGPoint>, size: CGSize) -> BitVector64 {
_openSwiftUIUnimplementedFailure()
package func contains(points: UnsafeBufferPointer<PlatformPoint>, size: CGSize) -> BitVector64 {
let framedShape: FramedShape
if Self.hasBackground {
let background = backgroundShape(in: size)
if case .empty = background.shape {
framedShape = shape(in: size)
} else {
framedShape = background
}
} else {
framedShape = shape(in: size)
}
switch framedShape.shape {
case let .path(path, style):
guard points.contains(where: { framedShape.frame.contains($0) }) else {
return BitVector64()
}
return path.contains(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Deep Code Review Agent🐛

This new shape hit-test path calls Path.contains(points:eoFill:origin:), but that overload still ends in _openSwiftUIUnimplementedFailure(). Any hit test whose point is inside a path-backed shape's frame will now trigger a precondition failure instead of returning a containment mask.

Severity: high


🤖 Was this useful? React with 👍 or 👎

points: points,
eoFill: style.isEOFilled,
origin: framedShape.frame.origin
)
default:
return points.mapBool { framedShape.frame.contains($0) }
}
}

package func contentPath(size: CGSize) -> Path {
_openSwiftUIUnimplementedFailure()
let framedShape = shape(in: size)
switch framedShape.shape {
case let .path(path, _):
let origin = framedShape.frame.origin
guard origin != .zero else { return path }
return path.applying(CGAffineTransform(translationX: origin.x, y: origin.y))
default:
return Path(framedShape.frame)
}
}

package static func makeLeafView(
Expand All @@ -57,30 +91,36 @@ extension ShapeStyledLeafView {
) -> _ViewOutputs {
var outputs = _ViewOutputs()
if inputs.preferences.requiresDisplayList {

let identity = DisplayList.Identity()
inputs.pushIdentity(identity)
let displayList = Attribute(
ShapeStyledDisplayList(
group: interpolatorGroup,
identity: identity,
view: view.value,
styles: styles,
size: inputs.size.cgSize,
animatedSize: inputs.animatedSize(),
position: inputs.animatedPosition(),
containerPosition: inputs.containerPosition,
transform: inputs.transform,
environment: inputs.environment,
safeAreaInsets: inputs.safeAreaInsets,
options: inputs.displayListOptions,
data: data,
contentSeed: .init()
)
let displayList = ShapeStyledDisplayList(
group: interpolatorGroup,
identity: identity,
view: view.value,
styles: styles,
size: inputs.size.cgSize,
animatedSize: inputs.animatedSize(),
position: inputs.animatedPosition(),
containerPosition: inputs.containerPosition,
transform: inputs.transform,
environment: inputs.environment,
safeAreaInsets: inputs.safeAreaInsets,
options: inputs.displayListOptions,
data: data,
contentSeed: .init()
)
outputs.displayList = displayList
outputs.displayList = Attribute(displayList)
}
let filter = ShapeStyledResponderFilter(
view: view.value,
styles: styles,
size: inputs.animatedSize(),
position: inputs.animatedPosition(),
transform: inputs.transform
)
if inputs.preferences.requiresViewResponders {
outputs.preferences.viewResponders = Attribute(filter)
}
// TODO: Responder
return outputs
}
}
Expand Down Expand Up @@ -110,17 +150,66 @@ extension ShapeStyledLeafView where ShapeUpdateData == () {
}
}

// MARK: - ShapeStyledResponderData

package struct ShapeStyledResponderData<V>: ContentResponder where V: ShapeStyledLeafView {
package func contains(points: UnsafeBufferPointer<CGPoint>, size: CGSize) -> BitVector64 {
_openSwiftUIUnimplementedFailure()
var view: V
var styles: ShapeStyle.Pack

package func contains(points: UnsafeBufferPointer<PlatformPoint>, size: CGSize) -> BitVector64 {
guard !view.isClear(styles: styles) else { return BitVector64() }
return view.contains(points: points, size: size)
}

package func contentPath(size: CGSize) -> Path {
_openSwiftUIUnimplementedFailure()
guard !view.isClear(styles: styles) else { return Path() }
return view.contentPath(size: size)
}
}

// TODO: ShapeStyledResponderFilter
// MARK: - ShapeStyledResponderFilter

private struct ShapeStyledResponderFilter<V>: StatefulRule where V: ShapeStyledLeafView {
@Attribute var view: V
@Attribute var styles: ShapeStyle.Pack
@Attribute var size: ViewSize
@Attribute var position: ViewOrigin
@Attribute var transform: ViewTransform
let responder: LeafViewResponder<ShapeStyledResponderData<V>>

init(
view: Attribute<V>,
styles: Attribute<ShapeStyle.Pack>,
size: Attribute<ViewSize>,
position: Attribute<ViewOrigin>,
transform: Attribute<ViewTransform>
) {
self._view = view
self._styles = styles
self._size = size
self._position = position
self._transform = transform
self.responder = LeafViewResponder()
}

typealias Value = ViewRespondersKey.Value

mutating func updateValue() {
let (view, viewChanged) = $view.changedValue()
let (styles, stylesChanged) = $styles.changedValue()
let data = ShapeStyledResponderData(view: view, styles: styles)
responder.helper.update(
data: (data, viewChanged || stylesChanged),
size: $size.changedValue(),
position: $position.changedValue(),
transform: $transform.changedValue(),
parent: responder
)
if !hasValue {
value = [responder]
}
}
}

// MARK: - ShapeStyledDisplayList

Expand Down
Loading