JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
16.24k stars 1.18k forks source link

Font transform has NaN Position crash #2098

Closed samuelprince77 closed 1 month ago

samuelprince77 commented 2 years ago

I notice that occasionally my desktop application will crash on Mac if i leave it open for an extended amount of time idle (open but not in use). On rare occasions, it will crash while the application is in active use. In the kotlin slack channel someone mentioned that they experience the same thing and that it happens when there is no clipboard data and copying some text to the clip board fixes it. The application uses an OutlinedTextField and this is the stack trace:

Exception in thread "AWT-EventQueue-0" java.io.IOException: Font transform has NaN position at java.desktop/sun.lwawt.macosx.CClipboard.getClipboardData(Native Method) at java.desktop/sun.awt.datatransfer.SunClipboard.getData(SunClipboard.java:219) at org.jetbrains.skiko.Actuals_awtKt.ClipboardManager_getText(Actuals.awt.kt:62) at org.jetbrains.skiko.ClipboardManager.getText(Platform.kt:28) at androidx.compose.ui.platform.PlatformClipboardManager.getText(PlatformClipboardManager.skiko.kt:26) at androidx.compose.foundation.text.ContextMenu_desktopKt$contextMenuItems$1.invoke(ContextMenu.desktop.kt:93) at androidx.compose.foundation.text.ContextMenu_desktopKt$contextMenuItems$1.invoke(ContextMenu.desktop.kt:72) at androidx.compose.foundation.ContextMenuData$allItemsSeq$1.invokeSuspend(ContextMenuProvider.desktop.kt:184) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlin.sequences.SequenceBuilderIterator.hasNext(SequenceBuilder.kt:140) at kotlin.sequences.SequencesKt___SequencesKt.toCollection(_Sequences.kt:786) at kotlin.sequences.SequencesKt___SequencesKt.toMutableList(_Sequences.kt:816) at kotlin.sequences.SequencesKt___SequencesKt.toList(_Sequences.kt:807) at androidx.compose.foundation.ContextMenuData$allItems$2.invoke(ContextMenuProvider.desktop.kt:179) at androidx.compose.foundation.ContextMenuData$allItems$2.invoke(ContextMenuProvider.desktop.kt:178) at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) at androidx.compose.foundation.ContextMenuData.getAllItems$foundation(ContextMenuProvider.desktop.kt:178) at androidx.compose.foundation.ContextMenuProvider_desktopKt$ContextMenuArea$2.invoke(ContextMenuProvider.desktop.kt:61) at androidx.compose.foundation.ContextMenuProvider_desktopKt$ContextMenuArea$2.invoke(ContextMenuProvider.desktop.kt:57) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.foundation.ContextMenuProvider_desktopKt$ContextMenuDataProvider$2.invoke(ContextMenuProvider.desktop.kt:94) at androidx.compose.foundation.ContextMenuProvider_desktopKt$ContextMenuDataProvider$2.invoke(ContextMenuProvider.desktop.kt:93) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228) at androidx.compose.foundation.ContextMenuProvider_desktopKt.ContextMenuDataProvider(ContextMenuProvider.desktop.kt:91) at androidx.compose.foundation.ContextMenuProvider_desktopKt.ContextMenuArea(ContextMenuProvider.desktop.kt:57) at androidx.compose.foundation.text.ContextMenu_desktopKt.ContextMenuArea(ContextMenu.desktop.kt:43) at androidx.compose.foundation.text.CoreTextFieldKt.CoreTextFieldRootBox(CoreTextField.kt:604) at androidx.compose.foundation.text.CoreTextFieldKt.CoreTextField(CoreTextField.kt:521) at androidx.compose.foundation.text.BasicTextFieldKt.BasicTextField(BasicTextField.kt:275) at androidx.compose.material.OutlinedTextFieldKt.OutlinedTextField(OutlinedTextField.kt:304) at ApplicationKt.Application(Application.kt:164) at ApplicationKt$Application$2.invoke(Application.kt) at ApplicationKt$Application$2.invoke(Application.kt) at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:157) at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2320) at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2580) at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3164) at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3142) at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:252) at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source) at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3142) at androidx.compose.runtime.ComposerImpl.recompose$runtime(Composer.kt:3108) at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:724) at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:879) at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:110) at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:488) at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:457) at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:44) at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:73) at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:381) at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:236) at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:235) at androidx.compose.ui.awt.ComposeLayer.catchExceptions(ComposeLayer.desktop.kt:88) at androidx.compose.ui.awt.ComposeLayer.access$catchExceptions(ComposeLayer.desktop.kt:68) at androidx.compose.ui.awt.ComposeLayer$1.onRender(ComposeLayer.desktop.kt:235) at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:455) at org.jetbrains.skiko.redrawer.MetalRedrawer.update(MetalRedrawer.kt:66) at org.jetbrains.skiko.redrawer.MetalRedrawer.access$update(MetalRedrawer.kt:13) at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invokeSuspend(MetalRedrawer.kt:38) at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt) at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt) at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) Warning: the fonts "Times" and "Times" are not available for the Java logical font "Serif", which may have unexpected appearance or behavior. Re-enable the "Times" font to remove this warning.

asapha commented 2 years ago

Happens in my app when it Crossfades to a state/screen containing an OutlinedTextField. It either happens immediately or it doesn't crash, no need for it to be idle on my end.

compose-jb 1.2.0-alpha01-dev686 macos 12.3.1

jimgoog commented 2 years ago

@asapha Do you have a consistent minimal repro of the bug? Hard to fix+verify with just a stack trace, would be great to get a consistent minimal repro attached to this bug.

@igordmn One of our engineers within Google recently reported the same intermittent issue with their internal CFD app.

@igordmn It looks like the root cause might be within Skiko since https://youtrack.jetbrains.com/issue/FL-12239 appears to have the same root cause (uses skiko called by noria):

  Caused by: java.io.IOException: Font transform has NaN position  at java.desktop@17.0.3/sun.lwawt.macosx.CClipboard.getClipboardData(Native Method)
  at java.desktop@17.0.3/sun.awt.datatransfer.ClipboardTransferable.fetchOneFlavor(Unknown Source)
  at java.desktop@17.0.3/sun.awt.datatransfer.ClipboardTransferable.lambda$new$0(Unknown Source)
  at java.base@17.0.3/java.util.HashMap$EntrySet.forEach(Unknown Source)
  at java.desktop@17.0.3/sun.awt.datatransfer.ClipboardTransferable.<init>(Unknown Source)
  at java.desktop@17.0.3/sun.awt.datatransfer.SunClipboard.getContents(Unknown Source)
  at java.desktop@17.0.3/sun.lwawt.macosx.CClipboard.getContents(Unknown Source)
  at fleet.noria.kwinit/noria.kwinit.impl.skiko.ClipboardImpl.getContent(ClipboardImpl.kt:62)
  at fleet.noria.kwinit/noria.kwinit.ClipboardKt.getText(Clipboard.kt:47)
  at fleet.frontend.ui/fleet.frontend.ui.editor.CopyBufferPopupViewKt$pasteFromHistory$1$1$2.invoke(CopyBufferPopupView.kt:128)
  at fleet.frontend.ui/fleet.frontend.ui.editor.CopyBufferPopupViewKt$pasteFromHistory$1$1$2.invoke(CopyBufferPopupView.kt:123)
  at fleet.frontend/fleet.frontend.actions.FleetActionsKt$Action$1$1.invoke(FleetActions.kt:79)
  at fleet.frontend/fleet.frontend.actions.FleetActionsKt$Action$1$1.invoke(FleetActions.kt:78)
asapha commented 2 years ago

It seems to happen when the clipboard is busy, as the equivalent error message in Windows is cannot open system clipboard.

To repro:

  1. Run this code in another program
fun main(args: Array<String>) {
    while (true) {
        try {
            Toolkit.getDefaultToolkit().systemClipboard.setContents(StringSelection("hello"), null)
            Thread.sleep(1)
        } catch (e: Exception) {
            println(e.message)
        }
    }
}
  1. In your Compose app, try to select some text

The app should crash when trying to access the clipboard, in Windows and in macOS.

It seems like jetbrains/skiko#579 will catch the IOException thrown in macOS but not the IllegalStateException thrown in Windows.

(modifying the clipboard is also affected, see #2270)

Stacktrace from Windows:

java.lang.IllegalStateException: cannot open system clipboard
    at java.desktop/sun.awt.windows.WClipboard.openClipboard(Native Method)
    at java.desktop/sun.awt.datatransfer.SunClipboard.getData(SunClipboard.java:208)
    at org.jetbrains.skiko.Actuals_awtKt.ClipboardManager_getText(Actuals.awt.kt:60)
    at org.jetbrains.skiko.ClipboardManager.getText(Platform.kt:28)
    at androidx.compose.ui.platform.PlatformClipboardManager.getText(PlatformClipboardManager.skiko.kt:26)
    at androidx.compose.foundation.text.ContextMenu_desktopKt$contextMenuItems$1.invoke(ContextMenu.desktop.kt:93)
    at androidx.compose.foundation.text.ContextMenu_desktopKt$contextMenuItems$1.invoke(ContextMenu.desktop.kt:72)
    at androidx.compose.foundation.ContextMenuData$allItemsSeq$1.invokeSuspend(ContextMenuProvider.desktop.kt:184)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlin.sequences.SequenceBuilderIterator.hasNext(SequenceBuilder.kt:127)
    at kotlin.sequences.SequencesKt___SequencesKt.toCollection(_Sequences.kt:787)
    at kotlin.sequences.SequencesKt___SequencesKt.toMutableList(_Sequences.kt:817)
    at kotlin.sequences.SequencesKt___SequencesKt.toList(_Sequences.kt:808)
    at androidx.compose.foundation.ContextMenuData$allItems$2.invoke(ContextMenuProvider.desktop.kt:179)
    at androidx.compose.foundation.ContextMenuData$allItems$2.invoke(ContextMenuProvider.desktop.kt:178)
    at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
    at androidx.compose.foundation.ContextMenuData.getAllItems$foundation(ContextMenuProvider.desktop.kt:178)
    at androidx.compose.foundation.ContextMenuProvider_desktopKt$ContextMenuArea$2.invoke(ContextMenuProvider.desktop.kt:61)
    at androidx.compose.foundation.ContextMenuProvider_desktopKt$ContextMenuArea$2.invoke(ContextMenuProvider.desktop.kt:57)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
    at androidx.compose.foundation.ContextMenuProvider_desktopKt$ContextMenuDataProvider$2.invoke(ContextMenuProvider.desktop.kt:94)
    at androidx.compose.foundation.ContextMenuProvider_desktopKt$ContextMenuDataProvider$2.invoke(ContextMenuProvider.desktop.kt:93)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
    at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
    at androidx.compose.foundation.ContextMenuProvider_desktopKt.ContextMenuDataProvider(ContextMenuProvider.desktop.kt:91)
    at androidx.compose.foundation.ContextMenuProvider_desktopKt.ContextMenuArea(ContextMenuProvider.desktop.kt:57)
    at androidx.compose.foundation.text.ContextMenu_desktopKt.ContextMenuArea(ContextMenu.desktop.kt:43)
    at androidx.compose.foundation.text.CoreTextFieldKt.CoreTextFieldRootBox(CoreTextField.kt:618)
    at androidx.compose.foundation.text.CoreTextFieldKt.CoreTextField(CoreTextField.kt:532)
    at androidx.compose.foundation.text.BasicTextFieldKt.BasicTextField(BasicTextField.kt:275)
    at androidx.compose.material.OutlinedTextFieldKt.OutlinedTextField(OutlinedTextField.kt:304)
    [...]
    at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:252)
    at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source)
    at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3183)
    at androidx.compose.runtime.ComposerImpl.recompose$runtime(Composer.kt:3148)
    at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:746)
    at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:876)
    at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:107)
    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:485)
    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:454)
    at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:42)
    at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:71)
    at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:412)
    at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:306)
    at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:305)
    at androidx.compose.ui.awt.ComposeLayer.catchExceptions(ComposeLayer.desktop.kt:102)
    at androidx.compose.ui.awt.ComposeLayer.access$catchExceptions(ComposeLayer.desktop.kt:82)
    at androidx.compose.ui.awt.ComposeLayer$1.onRender(ComposeLayer.desktop.kt:305)
    at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:510)
    at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invokeSuspend(Direct3DRedrawer.kt:37)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
    at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
igordmn commented 2 years ago

@asapha, thanks! Indeed, we also need to catch IllegalStateException

okushnikov commented 3 months ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.