diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift index 77eed5913..b7c2cf11b 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift @@ -492,7 +492,45 @@ extension DisplayList.Item { extension DisplayList { // FIXME - package class InterpolatorGroup {} + package class InterpolatorGroup { + private struct Contents { + var list: DisplayList + var origin: CGPoint + var rbList: ORBDisplayListContents + var nextTime: Time + var numericValue: Float? + } + + private struct Removed { + var contents: Contents + var interpolator: ORBDisplayListInterpolator? + var transition: ORBTransition? + var animation: ORBAnimation + var listener: AnimationListener? + var begin: Time + var duration: Double + var phase: Phase + } + + private enum Phase { + case pending + case first + case second + case running + } + +// private var contents: Contents +// private var removed: [Removed] +// var time: Time +// var renderer: DisplayList.GraphicsRenderer? +// var contentSeed: DisplayList.Seed +// var supportsVFD: Bool +// var needsUpdate: Bool + + init() { +// _openSwiftUIUnimplementedFailure() + } + } } package struct AccessibilityNodeAttachment {} @@ -511,3 +549,14 @@ extension GraphicsContext { package protocol _DisplayList_AnyEffectAnimation {} package struct ResolvedShadowStyle {} + +extension DisplayList.Item { + func addDrawingGroup(contentSeed: DisplayList.Seed) { + _openSwiftUIUnimplementedWarning() + } +} + +package class ORBDisplayListContents {} +package class ORBDisplayListInterpolator {} +package struct ORBTransition {} +package class ORBAnimation {} diff --git a/Sources/OpenSwiftUICore/Render/RendererEffect/RendererEffect.swift b/Sources/OpenSwiftUICore/Render/RendererEffect/RendererEffect.swift index f455009f8..d25e5a2da 100644 --- a/Sources/OpenSwiftUICore/Render/RendererEffect/RendererEffect.swift +++ b/Sources/OpenSwiftUICore/Render/RendererEffect/RendererEffect.swift @@ -179,13 +179,13 @@ private struct RendererEffectDisplayList: Rule, AsyncAttribute, Scrapeab } let version = DisplayList.Version(forUpdate: ()) let proxy = GeometryProxy( - owner: .current!, + owner: attribute.identifier, size: $size, environment: $environment, transform: $transform, position: $position, safeAreaInsets: $safeAreaInsets, - seed: .init(bitPattern: numericCast(version.value)) + seed: UInt32(truncatingIfNeeded: version.value) ) let e: DisplayList.Effect diff --git a/Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyleRendering.swift b/Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyleRendering.swift index b0be82412..a738cb9da 100644 --- a/Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyleRendering.swift +++ b/Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyleRendering.swift @@ -2,10 +2,13 @@ // ShapeStyleRendering.swift // OpenSwiftUICore // -// Audited for 6.0.87 +// Audited for 6.5.4 // Status: WIP // ID: 3890C65F12EA82A4BC5FBD33046B67FA (SwiftUICore) +package import OpenAttributeGraphShims +package import OpenCoreGraphicsShims + extension ShapeStyle { package typealias RenderedShape = _ShapeStyle_RenderedShape package typealias RenderedLayers = _ShapeStyle_RenderedLayers @@ -21,32 +24,283 @@ package struct _ShapeStyle_RenderedShape { case image(GraphicsImage) case alphaMask(DisplayList.Item) } + + var shape: ShapeStyle.RenderedShape.Shape + + var contentSeed: DisplayList.Seed + + var frame: CGRect + + var interpolatorData: (group: DisplayList.InterpolatorGroup, serial: UInt32)? + + var item: DisplayList.Item + + var options: DisplayList.Options + + @Attribute var environment: EnvironmentValues + + var blendMode: GraphicsBlendMode = .normal + + var opacity: Float + + private struct LayerNeeds: OptionSet { + let rawValue: UInt8 + + static let drawingGroup: LayerNeeds = .init(rawValue: 1 << 0) + } + + private var layerNeedes: LayerNeeds + + package init( + _ shape: ShapeStyle.RenderedShape.Shape, + frame: CGRect, + identity: DisplayList.Identity, + version: DisplayList.Version, + contentSeed: DisplayList.Seed, + options: DisplayList.Options, + environment: Attribute + ) { + self.shape = shape + self.contentSeed = contentSeed + self.frame = frame + self.interpolatorData = nil + self.item = .init( + .empty, + frame: frame, + identity: identity, + version: version + ) + self.options = options + self._environment = environment + self.blendMode = .normal + self.opacity = 1.0 + self.layerNeedes = [] + } + + package mutating func renderItem( + name: ShapeStyle.Name, + styles: Attribute, + layers: inout ShapeStyle.RenderedLayers + ) { + switch shape { + case let .text(contentView): + // Text rendering + _ = contentView + _openSwiftUIUnimplementedWarning() + break + case let .image(graphicsImage): + if graphicsImage.isTemplate { + if case let .vectorGlyph(glygh) = graphicsImage.contents { + renderVectorGlyph( + glygh, + size: graphicsImage.size, + orientation: graphicsImage.orientation, + name: name, + styles: styles.value, + layers: &layers + ) + } else { + let style = styles.value[name, 0] + layers.beginLayer( + id: .styled(name, 0), + style: style, + shape: &self + ) + render(style: style) + layers.endLayer(shape: &self) + } + } else { + renderUnstyledImage(graphicsImage, layers: &layers) + } + case .path, .alphaMask: + let style = styles.value[name, 0] + layers.beginLayer( + id: .styled(name, 0), + style: style, + shape: &self + ) + render(style: style) + layers.endLayer(shape: &self) + case .empty: + break + } + } + + package mutating func commitItem() -> DisplayList.Item { + defer { + blendMode = .normal + opacity = 1.0 + layerNeedes = [] + item.value = .empty + } + guard opacity != .zero, !frame.isEmpty else { + item.value = .empty + if let data = interpolatorData { + addEffect(.interpolatorLayer(data.group, serial: data.serial)) + interpolatorData = nil + } + return item + } + item.canonicalize(options: options) + if let data = interpolatorData { + addEffect(.interpolatorLayer(data.group, serial: data.serial)) + interpolatorData = nil + } + if layerNeedes.contains(.drawingGroup) { + item.addDrawingGroup(contentSeed: contentSeed) + } + if blendMode != .blendMode(.normal) { + addEffect(.blendMode(blendMode)) + } + if opacity != 1.0 { + addEffect(.opacity(opacity)) + } + return item + } + + package mutating func background(_ other: inout ShapeStyle.RenderedShape) { + _openSwiftUIUnimplementedFailure() + } + + private mutating func addEffect(_ effect: DisplayList.Effect) { + let effectItem = DisplayList.Item( + item.value, + frame: CGRect(origin: .zero, size: item.size), + identity: .none, + version: item.version + ) + item.value = .effect(effect, DisplayList(effectItem)) + item.canonicalize(options: options) + } + + private func render(style: ShapeStyle.Pack.Style) { + _openSwiftUIUnimplementedFailure() + } + + private func renderVectorGlyph( + _ glyph: ResolvedVectorGlyph, + size: CGSize, + orientation: Image.Orientation, + name: ShapeStyle.Name, + styles: ShapeStyle.Pack, + layers: inout ShapeStyle.RenderedLayers + ) { + _openSwiftUIUnimplementedFailure() + } + + private mutating func renderUnstyledImage( + _ graphicsImage: GraphicsImage, + layers: inout ShapeStyle.RenderedLayers + ) { + layers.beginLayer( + id: .unstyled, + style: nil, + shape: &self + ) + item.value = .content(DisplayList.Content( + .image(graphicsImage), + seed: contentSeed + )) + layers.endLayer(shape: &self) + } } package struct _ShapeStyle_RenderedLayers { + var group: ShapeStyle.InterpolatorGroup? + + private enum Layers { + case empty + case item(DisplayList.Item) + case items([DisplayList.Item]) + } + + private var layers: Layers = .empty + + init(group: ShapeStyle.InterpolatorGroup?) { + self.group = group + } + + mutating func commit( + shape: inout ShapeStyle.RenderedShape, + options: DisplayList.Options + ) -> DisplayList { + if let group { + _openSwiftUIUnimplementedWarning() + } + switch layers { + case .empty: + return .init() + case let .item(item): + let displayList = DisplayList(item) + layers = .empty + return displayList + case let .items(items): + let displayList = DisplayList(items) + _openSwiftUIUnimplementedFailure() + layers = .empty + } + } + + mutating func beginLayer( + id: ShapeStyle.LayerID, + style: ShapeStyle.Pack.Style?, + shape: inout ShapeStyle.RenderedShape + ) { + guard let group else { + return + } + // FIXME + guard case let .interpolatorData(group: group, serial: serial) = group.addLayer(id: id, style: style) else { + _openSwiftUIUnimplementedWarning() + return + } +// shape.interpolatorData = (group, serial) + _openSwiftUIUnimplementedWarning() + } + + mutating func endLayer(shape: inout ShapeStyle.RenderedShape) { + let newItem = shape.commitItem() + switch layers { + case .empty: + layers = .item(newItem) + case let .item(item): + var oldItem = item + let offset = CGSize(shape.frame.origin) + oldItem.frame.origin -= offset + layers = .items([ + oldItem, + newItem, + ]) + case let .items(items): + var items = items + // TODO + let offset = CGSize(shape.frame.origin) + items[0].frame.origin -= offset + items.append(newItem) + layers = .items(items) + } + } } +// MARK: - _ShapeStyle_LayerID + package enum _ShapeStyle_LayerID: Equatable { case unstyled - case styled(_ShapeStyle_Name, UInt16) - case customStyle(Swift.UInt32) + case styled(ShapeStyle.Name, UInt16) + case customStyle(UInt32) case named(String?) } -final package class _ShapeStyle_InterpolatorGroup/*: DisplayList.InterpolatorGroup*/ { - struct Layer { +final package class _ShapeStyle_InterpolatorGroup: DisplayList.InterpolatorGroup { + private struct Layer { let id: ShapeStyle.LayerID - let serial: UInt32 - var style: ShapeStyle.Pack.Style - var state: DisplayList.InterpolatorLayer - var isRemoved:Bool } - var layers: [Layer] = [] + private var layers: [Layer] = [] var contentsScale: Float = .zero @@ -57,11 +311,32 @@ final package class _ShapeStyle_InterpolatorGroup/*: DisplayList.InterpolatorGro var cursor: Int32 = .zero - init() { - _openSwiftUIEmptyStub() + fileprivate enum AddLayerResult { + case interpolatorData(group: DisplayList.InterpolatorGroup, serial: UInt32) + case none // FIXME + } + + fileprivate func addLayer( + id: ShapeStyle.LayerID, + style: ShapeStyle.Pack.Style? + ) -> AddLayerResult { + _openSwiftUIUnimplementedWarning() + return .interpolatorData(group: .init(), serial: 0) } } extension DisplayList { struct InterpolatorLayer {} } + + +extension ShapeStyle.Pack.Style { + package func draw( + _ path: Path, + style: PathDrawingStyle, + in ctx: GraphicsContext, + bounds: CGRect? + ) { + _openSwiftUIUnimplementedFailure() + } +} diff --git a/Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyledLeafView.swift b/Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyledLeafView.swift index bf10f96c2..11e534c6e 100644 --- a/Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyledLeafView.swift +++ b/Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyledLeafView.swift @@ -4,7 +4,7 @@ // // Audited for 6.5.4 // Status: WIP -// ID: E1641985C375D8826E6966D4F238A1B8 +// ID: E1641985C375D8826E6966D4F238A1B8 (SwiftUICore) package import Foundation package import OpenAttributeGraphShims @@ -122,7 +122,7 @@ package struct ShapeStyledResponderData: ContentResponder where V: ShapeStyle // TODO: ShapeStyledResponderFilter -// MARK: - ShapeStyledDisplayList [WIP] +// MARK: - ShapeStyledDisplayList struct ShapeStyledDisplayList: StatefulRule, AsyncAttribute where V: ShapeStyledLeafView { let group: ShapeStyle.InterpolatorGroup? @@ -174,16 +174,79 @@ struct ShapeStyledDisplayList: StatefulRule, AsyncAttribute where V: ShapeSty typealias Value = DisplayList - func updateValue() { - // FIXME - let view = view as! StyledTextContentView - var item = DisplayList.Item( - .content(.init(.text(view, CGSize(width: 50, height: 50)), seed: .init())), - frame: .zero, + mutating func updateValue() { + var (view, viewChanged) = $view.changedValue() + + let shouldUpdateSeed: Bool + let version: DisplayList.Version + let mustUpdate = view.mustUpdate(data: data, position: $position) + + if mustUpdate || viewChanged || contentSeed.value == 0 { + shouldUpdateSeed = true + version = .init(forUpdate: ()) + } else { + let excluding = [$position.identifier, $containerPosition.identifier, $view.identifier] + shouldUpdateSeed = Graph.anyInputsChanged(excluding: excluding) + version = .init(forUpdate: ()) + } + if shouldUpdateSeed { + contentSeed = .init(version) + } + + let proxy = GeometryProxy( + owner: attribute.identifier, + size: $animatedSize, + environment: $environment, + transform: $transform, + position: $position, + safeAreaInsets: $safeAreaInsets, + seed: UInt32(truncatingIfNeeded: version.value) + ) + let position = position + let containerPosition = containerPosition + let resultSize = V.animatesSize ? animatedSize.value : size + let framedShape = proxy.asCurrent { + view.shape(in: resultSize) + } + let offset = position - containerPosition + var layers = ShapeStyle.RenderedLayers(group: group) + if V.hasBackground { + let backgroundFramedShape = proxy.asCurrent { + view.backgroundShape(in: resultSize) + } + switch backgroundFramedShape.shape { + case .empty: break + default: + var renderedShape = ShapeStyle.RenderedShape( + backgroundFramedShape.shape, + frame: backgroundFramedShape.frame.offset(by: offset), + identity: identity, + version: version, + contentSeed: contentSeed, + options: options, + environment: $environment + ) + renderedShape.renderItem( + name: .background, + styles: $styles, + layers: &layers + ) + } + } + var renderedShape = ShapeStyle.RenderedShape( + framedShape.shape, + frame: framedShape.frame.offset(by: offset), identity: identity, - version: .init() + version: version, + contentSeed: contentSeed, + options: options, + environment: $environment + ) + renderedShape.renderItem( + name: .foreground, + styles: $styles, + layers: &layers ) - item.canonicalize(options: options) - value = DisplayList(item) + value = layers.commit(shape: &renderedShape, options: options) } }