compose-multiplatform icon indicating copy to clipboard operation
compose-multiplatform copied to clipboard

Cannot use desktop system fonts in Theme or as a Compose Font

Open v79 opened this issue 4 years ago • 4 comments

It is currently not possible to use any user-selected font in a Jetpack Compose Desktop app, as there is no way to load a system font at runtime.

I'm trying to implement a font-picker but while I can choose a font, I cannot use it to display text.

Given:

  val graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment()
  val allFonts: List<Font> = graphicsEnvironment.allFonts.toList()

It is possible to choose any font available to the system. For instance:

 val segoeScript: Font? = allFonts.toList().find { it.name == "Segoe Script" }?.deriveFont(24f)
 println(segoeScript)

But you cannot use this java.awt.Font as a Jetpack FontFamily - e.g. val segoeFontFamily = FontFamily(androidx.compose.ui.text.platform.Font(file = __??????__ ,weight = FontWeight.Normal,style = FontStyle.Normal)) is not possible, because I have only a java.awt.Font and not a file handle to the font.

It is not possible, without reflection, to get a File handle for a system font - see https://stackoverflow.com/questions/2019249/get-font-file-as-a-file-object-or-get-its-path for more.

v79 avatar Apr 02 '21 17:04 v79

The closest I've come to getting the actual file name is via some protected methods:

val ttf = FontAccess.getFontAccess().getFont2D(segoeScript) as TrueTypeFont
println(ttf.getPublicFileName())  /////////  getPublicFileName() is a protected function

Though how's this for a creatively dangerous solution?

val ttf = FontAccess.getFontAccess().getFont2D(segoeScript) as TrueTypeFont
val ttfString = ttf.toString() // the toString() method uses getPublicFileName() internally...
println(ttfString) // ** TrueType Font: Family=Segoe Script Name=Segoe Script style=0 fileName=C:\Windows\Fonts\segoesc.ttf
val fileName = ttfString.substringAfter("fileName=")
println(fileName) // C:\Windows\Fonts\segoesc.ttf
val segoeFont = androidx.compose.ui.text.platform.Font(File(fileName))
println(segoeFont) // FileFont(file=C:\Windows\Fonts\segoesc.ttf, weight=FontWeight(weight=400), style=Normal)

v79 avatar Apr 03 '21 08:04 v79

Probably safer approach would be not rely on AWT fonts in Compose apps at all. Why it is needd?

olonho avatar Apr 05 '21 07:04 olonho

Because I am hoping to build an app (similar to https://github.com/pavius/the-dot-factory ) for a Rasperry Pi project I have. I need access to the system fonts. Surely that's not an unreasonable request for a desktop development framework? Right now, I don't think Jetpack Compose Desktop could support the simplest of text-editing apps if it doesn't have access to system fonts.

v79 avatar Apr 05 '21 08:04 v79

Just an idea, why not find the font files in the filesystem? If you're only targeting Raspberry pi, you can look in /usr/share/fonts and ~/.fonts.

sproctor avatar Jul 10 '22 13:07 sproctor