Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash when stroking a circle #322

Closed
j-f1 opened this issue Dec 5, 2020 · 8 comments
Closed

Crash when stroking a circle #322

j-f1 opened this issue Dec 5, 2020 · 8 comments
Labels
bug Something isn't working

Comments

@j-f1
Copy link
Member

j-f1 commented Dec 5, 2020

The following code:

Circle().stroke(Color.gray)  

produces this error. Explicitly specifying .colorScheme(.light) does not help.

Fatal error: _ColorSchemeKey must have a renderer-provided default value: file TokamakCore/ColorScheme.swift, line 22
Swift._assertionFailure(_: Swift.StaticString, _: Swift.String, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never
static TokamakCore._ColorSchemeKey.defaultValue.getter : TokamakCore.ColorScheme
protocol witness for static TokamakCore.EnvironmentKey.defaultValue.getter : A.Value in conformance TokamakCore._ColorSchemeKey : TokamakCore.EnvironmentKey in TokamakCore
TokamakCore.EnvironmentValues.subscript.getter : <A where A: TokamakCore.EnvironmentKey>(A.Type) -> A.Value
TokamakCore.EnvironmentValues.colorScheme.getter : TokamakCore.ColorScheme
TokamakCore._SystemColorBox.resolve(in: TokamakCore.EnvironmentValues) -> TokamakCore.AnyColorBox._RGBA
TokamakCore._ColorProxy.resolve(in: TokamakCore.EnvironmentValues) -> TokamakCore.AnyColorBox._RGBA
(extension in TokamakStaticHTML):TokamakCore.Color.cssValue(TokamakCore.EnvironmentValues) -> Swift.String
(extension in TokamakStaticHTML):TokamakCore._StrokedShape.attributes(TokamakCore.ShapeStyle) -> [TokamakStaticHTML.HTMLAttribute : Swift.String]
protocol witness for TokamakStaticHTML.ShapeAttributes.attributes(TokamakCore.ShapeStyle) -> [TokamakStaticHTML.HTMLAttribute : Swift.String] in conformance TokamakCore._StrokedShape<A> : TokamakStaticHTML.ShapeAttributes in TokamakStaticHTML
(extension in TokamakStaticHTML):TokamakCore._ShapeView.deferredBody.getter : TokamakCore.AnyView
protocol witness for TokamakCore.ViewDeferredToRenderer.deferredBody.getter : TokamakCore.AnyView in conformance TokamakCore._ShapeView<A, B> : TokamakCore.ViewDeferredToRenderer in TokamakStaticHTML
closure #1 (Any) -> TokamakCore.AnyView in TokamakCore.AnyView.init<A where A: TokamakCore.View>(A) -> TokamakCore.AnyView
TokamakCore.StackReconciler.render<A>(compositeElement: TokamakCore.MountedCompositeElement<A>, body: Swift.ReferenceWritableKeyPath<TokamakCore.MountedCompositeElement<A>, Any>, result: Swift.KeyPath<TokamakCore.MountedCompositeElement<A>, (Any) -> A1>) -> A1
TokamakCore.StackReconciler.render(compositeView: TokamakCore.MountedCompositeView<A>) -> TokamakCore.AnyView
TokamakCore.MountedCompositeView.mount(before: A.TargetType?, on: TokamakCore.MountedElement<A>?, with: TokamakCore.StackReconciler<A>) -> ()
TokamakCore.MountedScene.mount(before: A.TargetType?, on: TokamakCore.MountedElement<A>?, with: TokamakCore.StackReconciler<A>) -> ()
TokamakCore.MountedApp.mount(before: A.TargetType?, on: TokamakCore.MountedElement<A>?, with: TokamakCore.StackReconciler<A>) -> ()
TokamakCore.StackReconciler.(performInitialMount in _FCAA3CDB23B668BF64A31B25B678943F)() -> ()
TokamakCore.StackReconciler.init<A where A1: TokamakCore.App>(app: A1, target: A.TargetType, environment: TokamakCore.EnvironmentValues, renderer: A, scheduler: (() -> ()) -> ()) -> TokamakCore.StackReconciler<A>
TokamakCore.StackReconciler.__allocating_init<A where A1: TokamakCore.App>(app: A1, target: A.TargetType, environment: TokamakCore.EnvironmentValues, renderer: A, scheduler: (() -> ()) -> ()) -> TokamakCore.StackReconciler<A>
TokamakDOM.DOMRenderer.init<A where A: TokamakCore.App>(A, JavaScriptKit.JSObject, TokamakCore.EnvironmentValues?) -> TokamakDOM.DOMRenderer
TokamakDOM.DOMRenderer.__allocating_init<A where A: TokamakCore.App>(A, JavaScriptKit.JSObject, TokamakCore.EnvironmentValues?) -> TokamakDOM.DOMRenderer
static (extension in TokamakDOM):TokamakCore.App._launch(A, TokamakCore.EnvironmentValues, JavaScriptKit.JSObject) -> ()
static (extension in TokamakDOM):TokamakCore.App._launch(A, TokamakCore.EnvironmentValues) -> ()
protocol witness for static TokamakCore.App._launch(A, TokamakCore.EnvironmentValues) -> () in conformance swiftui_tut.TokamakApp : TokamakCore.App in swiftui_tut
static (extension in TokamakCore):TokamakCore.App.main() -> ()
main
__main_argc_argv
__main_void
__original_main
_start
@j-f1 j-f1 added the bug Something isn't working label Dec 5, 2020
@j-f1 j-f1 self-assigned this Dec 19, 2020
@mortenbekditlevsen
Copy link
Contributor

The issue appears to have something to do with the environment not being correctly propagated to the _ShapeView when the stroke is applied.
I experienced the same issue in TokamakGTK, but I am not familiar enough with the environment injection to figure out why it's not being injected.

mortenbekditlevsen added a commit that referenced this issue Jan 11, 2021
@mortenbekditlevsen
Copy link
Contributor

mortenbekditlevsen commented Jan 12, 2021

A bit more info that may or may not be of use for debugging:

Depending on how types are wrapped on the call site, the environment is either injected correctly or not.
I made the tests with TokamakGTK, but it should be the same with DOM/HTML.

The lines marked with '// crashes' are those that don't get the environment injected.

struct MyShape: Shape {
  func path(in rect: TokamakGTK.CGRect) -> Path {
    var path = Path()
    path.addEllipse(
      in: CGRect(origin: .zero, size: .init(width: 100, height: 150)),
      transform: TokamakCore.CGAffineTransform(rotationAngle: 0.5)
    )
    return path.applying(TokamakCore.CGAffineTransform(rotationAngle: -0.1))
  }
}

struct MyStrokedShape: View {
  var body: some View {
    MyShape()
      .stroke(
        Color.red,
        style: StrokeStyle(lineWidth: 4, lineCap: .round, lineJoin: .round, dash: [5, 5, 1])
      )
  }
}

struct MyStrokedAndFramedShape: View {
  var body: some View {
    MyShape()
      .stroke(Color.red)
      .frame(width: 50, height: 200)
  }
}

struct TokamakGTKDemo: App {
  @State var text: String = "Test"
  var body: some Scene {
    WindowGroup("Test Scene") {
      MyShape()
        .frame(width: 50, height: 200) // works

      MyShape()
        .stroke(Color.red)
        .frame(width: 50, height: 200) // crashes

      MyStrokedShape()
        .frame(width: 50, height: 200) // works

      MyStrokedAndFramedShape() // crashes
    }
  }
}

@j-f1 j-f1 removed their assignment Jan 15, 2021
@j-f1
Copy link
Member Author

j-f1 commented Jan 15, 2021

Based on that, I wonder if ModifiedContent isn’t passing the environment to its child.

@mortenbekditlevsen
Copy link
Contributor

Well, frame() applies a ModifiedContent and that is also used in some of the working examples.
Stroking is not applying ModifiedContent, but it does make a custom Shape into a _ShapeView with stroked contents.
Could it be in that 'transform' that things go wrong?

@mortenbekditlevsen
Copy link
Contributor

Hi again @j-f1 ,
You're right. I am not certain what I was seing before, but what I can see now is that the ModifiedContent appears to not pass the environment to it's child.
In the injectEnvironment function, the View (i.e. in this case the ModifiedContent) has the environment set on all it's EnvironmentReader properties, but it's Content is not itself an EnvironmentReader, but rather another View which I am guessing ought to have injectEnvironment called directly.

But I don't quite get the relationship between the MountedElement construction and ModifiedContent.
In the case of the GTK renderer and the StaticHTML renderer, ModifiedContent appears both to be a ParentView and a ViewDeferredToRenderer when it's content is a View, so I don't know which elements actually are supposed to get mounted...

@MaxDesiatov
Copy link
Collaborator

@carson-katri I think you introduced ModifiedContent originally, maybe you could help?

MaxDesiatov pushed a commit that referenced this issue Jun 28, 2021
The PR fixes multiple bugs which prevent stroked shapes from rendering correctly.

1. Allow environment injection into  `_StrokedShape`. This causes stroked shapes to no longer crash (#322).
2. Change `Path.strokedPath` and `Path.trimmedPath` to allow the `sizing` of the base shape to be inherited. Without this, stroked shapes can appear as 0x0 in size, making them invisible.
3. Change `_ShapeView` in the StaticHTML renderer to merge attributes in the `svg` rather than placing the `svg` in a `div`. This allows proper rendering when multiple shapes are in a stack.

Finally, the `Path` demo has been modified to add a stroked circle.
@MaxDesiatov
Copy link
Collaborator

@ezraberch can we close this as completely resolved by #414?

@ezraberch
Copy link
Member

Sure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Development

No branches or pull requests

4 participants