Hi Philip, I did some more testing and noticed an even more serious problem on macOS: I couldn’t seem to select the font weight.
jshell> Font.getFontNames("JetBrains Mono").forEach(System.out::println) JetBrains Mono ExtraLight Italic JetBrains Mono ExtraBold Italic JetBrains Mono Medium JetBrains Mono Thin Italic JetBrains Mono ExtraBold JetBrains Mono Light JetBrains Mono SemiBold JetBrains Mono Medium Italic JetBrains Mono Bold Italic JetBrains Mono SemiBold Italic JetBrains Mono Bold JetBrains Mono Regular JetBrains Mono Light Italic JetBrains Mono Italic JetBrains Mono ExtraLight JetBrains Mono Thin jshell> Font.font("JetBrains Mono Thin") $3 ==> Font[name=System Regular, family=System, style=Regular, size=13.0] jshell> Font.font("JetBrains Mono", FontWeight.THIN, 13) $4 ==> Font[name=JetBrains Mono Medium, family=JetBrains Mono Medium, style=Regular, size=13.0] jshell> Font.font("JetBrains Mono", FontWeight.THIN, FontPosture.REGULAR, 13) $5 ==> Font[name=JetBrains Mono Medium, family=JetBrains Mono Medium, style=Regular, size=13.0] jshell> Font.font("JetBrains Mono", FontWeight.THIN, FontPosture.ITALIC, 13) $6 ==> Font[name=JetBrains Mono ExtraLight Italic, family=JetBrains Mono ExtraLight, style=Italic, size=13.0] Font.font(...) is working in a way that is hard for me to understand :( Some of it may come from the platform APIs being different. > Can you give me additional examples ? I think the most serious inconsistency is: what do we mean when we talk about "the family of the font"? - On Windows, it usually means the localized name of the font family name (nameID=1); - On Linux, it usually means the non-localized font family name (nameID=1); - On macOS, it usually means the non-localized typographical family name (nameID=16). I think the behavior on macOS is relatively correct - provided that the problems I mentioned earlier are resolved. Using font family names (nameID=1) means it is difficult to select variants. If we want to get JetBrains Mono Bold on Windows, we need to use Font.font("JetBrains Mono", FontWeight.BOLD, 13), but to get JetBrains Mono ExtraBold, we need to use Font.font("JetBrains Mono ExtraBold", FontWeight.NORMAL, 13). Honestly, I feel like the entire Font API is poorly documented, extremely confusing, and lacks useful methods. If I don't test it on every platform, I have no idea how it will work. I think it really needs a huge refactor. Glavo On Wed, Jul 16, 2025 at 3:20 AM Philip Race <philip.r...@oracle.com> wrote: > I can't be sure - without inspecting the font and debugging the code - but > this looks > like in the first case you get the ID=16 typographic font family > ("JetBrains Mono") and > in the other case you get the ID=1 font family ("JetBrains Mono Medium"). > Without debugging I can't explain why there's this apparent inconsistency. > > ID=1 is the traditional 4 member font family with regular/bold/italic/bold > italic > > The typographic (some times called extended) family supports weight and > sometimes width > and these days they may even be combined into a single font via font > variations. > > There may be a bug here (can't be sure without investigating) and there > also may be a need > for API which works with the typographic family. > > > >Besides these issues, I also get tired of the subtle differences in > behavior between different platforms. > >Can we bridge the differences in how JavaFX handles font family names on > different platforms? > > Some of it may come from the platform APIs being different. > Can you give me additional examples ? > > -phil. > > On 7/15/25 7:21 AM, Glavo wrote: > > Hi Philip, > > Thanks for your reply. > > > (1) fixing this for DW wouldn't help Linux or Mac so there'd need to be > separate implementations if they also don't do it automatically > > I also tested on Linux and macOS. I think this problem does not exist on > these two platforms. > JavaFX uses the English font family names everywhere on both platforms, > rather than the localized names, so this problem does not occur. > > However, I encountered another annoying behavior on macOS: > > jshell> Font.getFamilies().stream().filter(it -> it.contains("JetBrains > Mono")).toList() > $2 ==> [JetBrains Mono, JetBrains Mono NL] > > jshell> Font.font("JetBrains Mono") > $3 ==> Font[name=JetBrains Mono Medium, family=JetBrains Mono Medium, > style=Regular, size=13.0] > > jshell> $3.getFamily() > $4 ==> "JetBrains Mono Medium" > > jshell> Font.font("JetBrains Mono Medium") > $5 ==> Font[name=System Regular, family=System, style=Regular, size=13.0] > > > As you can see, multiple weights of a font on macOS are unified into the > same font family. > We can find a Font by this font family name, but the family name returned > by Font:getFamily() includes the weight, > and we cannot find the font based on the returned name. > This problem does not occur on Linux and Windows, because those platforms > do not unify fonts into a single family. > > Besides these issues, I also get tired of the subtle differences in > behavior between different platforms. > Can we bridge the differences in how JavaFX handles font family names on > different platforms? > > Glavo > > On Tue, Jul 15, 2025 at 3:50 AM Philip Race <philip.r...@oracle.com> > wrote: > >> Font.font will, on Windows, use IDWriteFontCollection::FindFamilyName(..) >> The docs for that appear to be silent on whether the matching process >> will check all localized names, >> but it sounds like it must not. I don't see an alternative look up API, >> such as one that accepts a locale arg. >> >> >> https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritefontcollection >> >> It seems like the app (which in this case means the FX implementation) >> will have to do this itself which is going to be tedious. >> >> We would need to compare with every localized name of every font on the >> system looking for a match. >> >> And one annoying aspect of this is that until you've done that exhaustive >> search you don't >> know if the name the application supplied is present at all on the system. >> >> How would you know that someone mis-spelled Arial as Ariel and not that >> Ariel is the German localized name for Arial ? >> >> So failed lookups will be slow. >> >> In Java 2D we already do this but I'd have hoped DW used by FX was better >> than this than GDI used by 2D. >> Also note that >> (1) fixing this for DW wouldn't help Linux or Mac so there'd need to be >> separate implementations if they also don't do it automatically >> (2) There isn't any FX API which lets you enumerate or access localized >> names, so as you note, that also is an issue. >> Although I'm actually a little surprised FX finds 幼圆 but reports YouYuan. >> I would have thought it would be consistent. >> >> I'm also a little surprised that it has taken this long for anyone to >> even implicitly ask for FX to support localized font names. >> Java2D has had this support for a very long time. >> >> -phil. >> >> On 7/12/25 4:18 AM, Glavo wrote: >> >> Hi, >> >> We recently noticed a problem: For fonts with localized names, >> Font.font(String) can only find the font based on the localized name in >> the current locale. >> >> For example, the Chinese version of Windows comes with a font called >> "YouYuan", and its Chinese name is "幼圆". >> When the system language is Chinese, JavaFX has the following behaviors: >> >> jshell> Font.font("YouYuan") >> $2 ==> Font[name=System Regular, family=System, style=Regular, >> size=13.333333015441895] >> >> jshell> Font.font("幼圆") >> $3 ==> Font[name=YouYuan, family=YouYuan, style=Regular, >> size=13.333333015441895] >> >> jshell> $3.getFamily() >> $4 ==> "YouYuan" >> >> >> As you can see, we cannot find the font based on the English name, we can >> only use the Chinese name. >> But Font::getName() returns the English name, so we can't get the >> Chinese name from the Font. >> This makes it impossible to generate a style sheet based on a Font >> object, because >> >> "-fx-font-family: \"%s\";".formatted(font.getFamily()) >> >> will not work with these fonts. >> >> The only workaround I can think of is to generate a mapping table from >> English names to Chinese names like this: >> >> >> Font.getFamilies().stream().collect(Collectors.toMap(it -> >> Font.font(it).getFamily(), Function.identity())) >> >> >> But this seems like a lot of overhead :( >> >> So, I want JavaFX to provide the following features: >> >> 1. Regardless of the current system language, Font.font(String) >> should be able to find the font by its English name; >> 2. Provide a new method Font::getLocalizedFamily() to get the >> localized name of the font. >> >> Glavo >> >> >> >