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
179 changes: 165 additions & 14 deletions Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// DisplayList.swift
// OpenSwiftUICore
//
// Audited for 6.0.87
// Audited for 6.5.4
// Status: WIP
// ID: F37E3733E490AA5E3BDC045E3D34D9F8 (SwiftUICore)

Expand Down Expand Up @@ -68,21 +68,18 @@ package struct DisplayList: Equatable {
}

package init(_ item: Item) {
// TODO
switch item.value {
case .empty:
if case .empty = item.value {
items = []
features = []
properties = []
default:
} else {
items = [item]
features = item.features
properties = item.properties
}
}

package init(_ items: [Item]) {
// TOOD
var features: Features = []
var properties: Properties = []
for item in items {
Expand All @@ -95,20 +92,62 @@ package struct DisplayList: Equatable {
}

package mutating func append(_ item: Item) {
_openSwiftUIUnimplementedFailure()
if case .empty = item.value {
return
}
items.append(item)
features.formUnion(item.features)
properties.formUnion(item.properties)
}

package mutating func append(contentsOf other: DisplayList) {
// TODO
items.append(contentsOf: other.items)
// _openSwiftUIUnimplementedFailure()
for item in other.items {
append(item)
}
}

package mutating func reserveCapacity(_ count: Int) {
items.reserveCapacity(count)
}

package mutating func transform(_ body: (inout Item) -> Void) {
features = []
properties = []
guard !items.isEmpty else {
return
}
var transformedFeatures: Features = []
var transformedProperties: Properties = []
for index in items.indices {
body(&items[index])
transformedFeatures.formUnion(items[index].features)
transformedProperties.formUnion(items[index].properties)
}
features = transformedFeatures
properties = transformedProperties
}

package mutating func translate(by offset: CGSize, version: Version) {
guard !items.isEmpty else {
return
}
for index in items.indices {
items[index].frame.origin += offset
items[index].version.combine(with: version)
}
}

package var isEmpty: Bool {
items.isEmpty
}

// TODO

package var version: Version {
var version = Version()
for item in items {
version.combine(with: item.version)
}
return version
}

package func nextUpdate(after time: Time) -> Time {
guard !features.contains(.animations) else {
Expand All @@ -125,6 +164,76 @@ package struct DisplayList: Equatable {
}
return nextUpdate
}

@discardableResult
package func forEachIdentity(_ body: (Identity, inout Bool) -> Void) -> Bool {
for item in items {
if item.identity != .none {
var stop = false
body(item.identity, &stop)
guard !stop else {
return false
}
}
switch item.value {
case let .content(content):
if case let .flattened(list, _, _) = content.value {
guard list.forEachIdentity(body) else {
return false
}
}
case let .effect(effect, list):
if case let .mask(mask, _) = effect {
guard mask.forEachIdentity(body) else {
return false
}
}
guard list.forEachIdentity(body) else {
return false
}
case let .states(states):
for (_, list) in states {
guard list.forEachIdentity(body) else {
return false
}
}
case .empty:
break
}
}
return true
}

package func forEachRBDisplayList(_ body: (any ORBDisplayListContents) -> Void) {
for item in items {
switch item.value {
case let .content(content):
switch content.value {
case let .flattened(list, _, _):
list.forEachRBDisplayList(body)
case let .drawing(rbList, _, _):
body(rbList)
default:
break
}
case let .effect(effect, list):
if case let .mask(mask, _) = effect {
mask.forEachRBDisplayList(body)
}
list.forEachRBDisplayList(body)
case let .states(states):
for (_, list) in states {
list.forEachRBDisplayList(body)
}
case .empty:
break
}
}
}

package static func == (a: DisplayList, b: DisplayList) -> Bool {
a.items == b.items && a.features == b.features && a.properties == b.properties
}
}

@available(*, unavailable)
Expand Down Expand Up @@ -311,7 +420,6 @@ extension DisplayList {
case rotation(_RotationEffect.Data)
case rotation3D(_Rotation3DEffect.Data)

@inline(__always)
package var affineTransform: CGAffineTransform? {
switch self {
case let .affine(transform):
Expand All @@ -323,7 +431,6 @@ extension DisplayList {
}
}

@inline(__always)
package var projectionTransform: ProjectionTransform? {
switch self {
case let .projection(transform):
Expand Down Expand Up @@ -661,6 +768,36 @@ extension DisplayList.Item {
}
}
}

package var properties: DisplayList.Properties {
switch value {
case .empty:
return []
case let .content(content):
if case let .flattened(list, _, _) = content.value {
return list.properties
} else {
return []
}
case let .effect(effect, list):
var properties = list.properties
switch effect {
case let .properties(effectProperties):
properties.formUnion(effectProperties)
case let .mask(mask, _):
properties.formUnion(mask.properties)
case let .interpolatorLayer(group, _):
properties.formUnion(group.properties)
default:
break
}
return properties
case let .states(states):
return states.reduce(into: []) { properties, state in
properties.formUnion(state.1.properties)
}
}
}
}

// TODO
Expand Down Expand Up @@ -716,6 +853,10 @@ extension DisplayList {
[]
}

var properties: Properties {
[]
}

func nextUpdate(after _: Time) -> Time {
.infinity
}
Expand All @@ -742,6 +883,10 @@ extension DisplayList {
override func nextUpdate(after time: Time) -> Time {
layer.nextUpdate(after: time)
}

override var properties: Properties {
layer.properties
}
}

struct InterpolatorLayer {
Expand Down Expand Up @@ -783,6 +928,12 @@ extension DisplayList {
func nextUpdate(after _: Time) -> Time {
removed.isEmpty ? contents.nextTime : time
}

var properties: Properties {
removed.reduce(into: contents.list.properties) { properties, removed in
properties.formUnion(removed.contents.list.properties)
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
// ID: 11125C146A81D1913BFBD53B89D010C6 (SwiftUICore)

extension DisplayList.Item {
// TODO
// var features: DisplayList.Features { [] }
var properties: DisplayList.Properties { [] }

fileprivate func print(into printer: inout SExpPrinter) {
printer.push("item")
if identity.value != .zero {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,41 @@ struct DisplayListTests {
#expect(combineVersion.value == 999)
}

@Test
func properties() {
func item(_ value: DisplayList.Item.Value) -> DisplayList.Item {
DisplayList.Item(
value,
frame: .zero,
identity: .init(decodedValue: 1),
version: .init(decodedValue: 1)
)
}

let privacyItem = item(.effect(.properties(.privacySensitive), .init()))
let ignoresEventsItem = item(.effect(.properties(.ignoresEvents), .init()))
let privacyList = DisplayList(privacyItem)
let ignoresEventsList = DisplayList(ignoresEventsItem)

#expect(privacyList.properties == .privacySensitive)
#expect(ignoresEventsList.properties == .ignoresEvents)

let maskItem = item(.effect(.mask(privacyList), ignoresEventsList))
#expect(DisplayList(maskItem).properties == [.privacySensitive, .ignoresEvents])

let flattenedItem = item(.content(.init(
.flattened(privacyList, .zero, .init()),
seed: .init(decodedValue: 1)
)))
#expect(DisplayList(flattenedItem).properties == .privacySensitive)

let statesItem = item(.states([
(StrongHash(of: 1), privacyList),
(StrongHash(of: 2), ignoresEventsList),
]))
#expect(DisplayList(statesItem).properties == [.privacySensitive, .ignoresEvents])
}

@Suite
struct DisplayListItemMatchesTopLevelStructureTests {
enum TestCase {
Expand Down
Loading