#194 Something about the default fontconfig turns Emojis monochrome in Qt apps
Opened 2 years ago by ngraham. Modified 4 months ago

Two examples from NeoChat can be seen here: https://imgur.com/a/FKD8EUp

This started happening after I removed a user-specific fontconfig override from ~/.config/fontconfig/conf.d/.

The file contents can be found here: https://invent.kde.org/-/snippets/2154

I don't understand anything about how fontconfigs work; all I can tell you is that this fontconfig makes color emojis in Qt apps work properly, while the default stuff shipped by Fedora in /etc/fonts/ does not.


@petersen Any idea what's going on here?

all of the characters

Er, for values of "all" equal to all - 1. 🙄

Because the supplied fontconfig file is so huge, but is indeed very effective at enabling emoji support in Qt input widgets, I ended up chopping it up into almost a dozen separate fontconfig files, so that I could enable/disable them individually.

What I found was that the only piece necessary was an alias blocks (there's one each for serif, sans-serif, monospace, and ui-sans) corresponding to the type of font the input widget was using. The sans-serif alias looks like this:

<fontconfig>
  <!-- Font directory list -->
  <dir>/usr/share/fonts/croscore</dir>
  <dir>/usr/share/fonts/crosextra</dir>
  <dir>/usr/share/fonts/dejavu</dir>
  <dir>/usr/share/fonts/ko-nanum</dir>
  <dir>/usr/share/fonts/lohit-cros</dir>
  <dir>/usr/share/fonts/monotype</dir>
  <dir>/usr/share/fonts/noto</dir>
  <dir>/usr/share/fonts/notocjk</dir>
  <dir>/usr/share/fonts/roboto</dir>
  <dir>/usr/share/fonts/tibt-jomolhari</dir>
  <!-- Set preference for Noto, Droid and Monotype fonts -->
  <alias>
    <family>sans-serif</family>
    <prefer>
      <family>Arimo</family>
      <family>Noto Sans</family>
      <family>Noto Sans CJK SC</family>
      <family>Noto Sans Arabic</family>
      <family>Noto Sans Thai</family>
      <family>Noto Sans Devanagari</family>
      <family>Noto Sans Tamil</family>
      <family>Noto Sans Hebrew</family>
      <family>Noto Sans Bengali</family>
      <family>Noto Sans Telugu</family>
      <family>Noto Sans Kannada</family>
      <family>Noto Sans Malayalam</family>
      <family>Noto Sans Gurmukhi</family>
      <family>Noto Sans Gujarati</family>
      <family>Noto Sans Oriya</family>
      <family>Noto Sans Armenian</family>
      <family>Noto Sans Georgian</family>
      <family>Noto Sans Khmer</family>
      <family>Noto Sans Lao</family>
      <family>Noto Sans Ethiopic</family>
      <family>Noto Sans Myanmar</family>
      <family>Noto Sans Sinhala</family>
      <family>Jomolhari</family>
      <family>Noto Sans Coptic</family>
      <family>Noto Sans Deseret</family>
      <family>Noto Sans TaiTham</family>
      <family>Noto Sans CanadianAboriginal</family>
      <family>Noto Sans Yi</family>
      <family>Noto Sans Tifinagh</family>
      <family>Noto Sans Adlam</family>
      <family>Noto Sans Cherokee</family>
      <family>Noto Sans Chakma</family>
      <family>Noto Sans Osage</family>
      <family>Noto Color Emoji</family>
      <family>Noto Sans Symbols</family>
      <family>Noto Sans Symbols2</family>
      <family>DejaVu Sans</family>
    </prefer>
  </alias>
</fontconfig>

Add a .conf file containing that code to $HOME/.config/fontconfig/conf.d/, and suddenly any Qt input widget that uses a sans-serif font shows (nearly) all emoji, instead of hardly any of them.

The reason why it works seems fairly clear. With that config, the Noto fonts (including Noto Color Emoji are right at the top of the sans-serif match list:

$ fc-pattern -c sans|fmt -s
Pattern has 6 elts (size 16)
    family: "Arimo"(w) "Noto Sans"(w) "Droid Sans"(w) "Noto Sans
    CJK SC"(w) "Noto Sans Arabic"(w) "Noto Sans Thai"(w) "Noto Sans
    Devanagari"(w) "Noto Sans Tamil"(w) "Noto Sans Hebrew"(w) "Noto
    Sans Bengali"(w) "Noto Sans Telugu"(w) "Noto Sans Kannada"(w)
    "Noto Sans Malayalam"(w) "Noto Sans Gurmukhi"(w) "Noto Sans
    Gujarati"(w) "Noto Sans Oriya"(w) "Noto Sans Armenian"(w) "Noto
    Sans Georgian"(w) "Noto Sans Khmer"(w) "Noto Sans Lao"(w) "Noto
    Sans Ethiopic"(w) "Noto Sans Myanmar"(w) "Noto Sans Sinhala"(w)
    "Jomolhari"(w) "Noto Sans Coptic"(w) "Noto Sans Deseret"(w)
    "Noto Sans TaiTham"(w) "Noto Sans CanadianAboriginal"(w) "Noto
    Sans Yi"(w) "Noto Sans Tifinagh"(w) "Noto Sans Adlam"(w) "Noto
    Sans Cherokee"(w) "Noto Sans Chakma"(w) "Noto Sans Osage"(w) "Noto
    Color Emoji"(w) "Noto Sans Symbols"(w) "Noto Sans Symbols2"(w)
    "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu Sans"(w) "BPG 2017
    DejaVu Sans"(w) "DejaVu Sans"(w) "Arev Sans"(w) "DejaVu Sans"(w)
    "Bepa"(w) "DejaVu Sans"(w) "Hunky Sans"(w) "DejaVu Sans"(w)
    "Olwen Sans"(w) "DejaVu Sans"(w) "SUSE Sans"(w) "DejaVu Sans"(w)
    "Verajja"(w) "DejaVu Sans"(w) "VerajjaPDA"(w) "DejaVu Sans"(w)
    "Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Prima Sans"(w)
    "DejaVu Sans"(w) "DejaVu Sans"(w) "Liberation Sans Narrow"(w)
    "Snap"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany
    AMT"(w) "Luxi Sans"(w) "Nimbus Sans L"(w) "Nimbus Sans"(w)
    "Nimbus Sans"(w) "Helvetica"(w) "Nimbus Sans"(w) "Lucida Sans
    Unicode"(w) "BPG Glaho International"(w) "Tahoma"(w) "Open
    Sans"(w) "Droid Sans"(w) "Overpass"(w) "Calibri"(w) "Corbel"(w)
    "Montserrat"(w) "MgOpen Moderna"(w) "Arial"(w) "Impact"(w)
    "Tahoma"(w) "Trebuchet MS"(w) "Verdana"(w) "URW Gothic"(w) "Nimbus
    Sans"(w) "Nimbus Sans Narrow"(w) "Carlito"(w) "Source Sans 3"(w)
    "D-DIN Condensed"(w) "D-DIN Exp"(w) "D-DIN"(w) "Roboto"(w)
    "Droid Sans"(w) "Nachlieli"(w) "Lucida Sans Unicode"(w) "Yudit
    Unicode"(w) "Kerkis"(w) "ArmNet Helvetica"(w) "Artsounk"(w)
    "BPG UTF8 M"(w) "Waree"(w) "Loma"(w) "Garuda"(w) "Umpush"(w)
    "Saysettha Unicode"(w) "JG Lao Old Arial"(w) "GF Zemen Unicode"(w)
    "Pigiarniq"(w) "B Davat"(w) "B Compset"(w) "Kacst-Qr"(w)
    "Urdu Nastaliq Unicode"(w) "Raghindi"(w) "Mukti Narrow"(w)
    "malayalam"(w) "Sampige"(w) "padmaa"(w) "Hapax Berbère"(w)
    "MS Gothic"(w) "UmePlus P Gothic"(w) "Microsoft YaHei"(w)
    "Microsoft JhengHei"(w) "WenQuanYi Zen Hei"(w) "WenQuanYi Bitmap
    Song"(w) "AR PL ShanHeiSun Uni"(w) "AR PL New Sung"(w) "MgOpen
    Modata"(w) "VL Gothic"(w) "IPAMonaGothic"(w) "IPAGothic"(w)
    "Sazanami Gothic"(w) "Kochi Gothic"(w) "AR PL KaitiM GB"(w)
    "AR PL KaitiM Big5"(w) "AR PL ShanHeiSun Uni"(w) "AR PL
    SungtiL GB"(w) "AR PL Mingti2L Big5"(w) "MS ゴシック"(w)
    "ZYSong18030"(w) "TSCu_Paranar"(w) "NanumGothic"(w) "UnDotum"(w)
    "Baekmuk Dotum"(w) "Baekmuk Gulim"(w) "KacstQura"(w)
    "Lohit Bengali"(w) "Lohit Gujarati"(w) "Lohit Hindi"(w)
    "Lohit Marathi"(w) "Lohit Maithili"(w) "Lohit Kashmiri"(w)
    "Lohit Konkani"(w) "Lohit Nepali"(w) "Lohit Sindhi"(w) "Lohit
    Punjabi"(w) "Lohit Tamil"(w) "Meera"(w) "Lohit Malayalam"(w)
    "Lohit Kannada"(w) "Lohit Telugu"(w) "Lohit Oriya"(w) "LKLUG"(w)
    "Noto Sans"(w) "FreeSans"(w) "FreeSans"(w) "Arial Unicode MS"(w)
    "Arial Unicode"(w) "Code2000"(w) "Code2001"(w) "sans-serif"(w)
    "Roya"(w) "Koodak"(w) "Terafik"(w) "Bitstream Vera Sans"(w)
    "Bitstream Vera Sans"(w) "sans-serif"(s) "Noto Color Emoji"(w)
    "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w)
    "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "Lato"(w)
    "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w)
    "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w)
    "ITC Avant Garde Gothic"(w) "URW Gothic"(w) "sans-serif"(w)
    "sans-serif"(w) "Helvetica"(w) "Helvetica Narrow"(w) "Nimbus
    Sans Narrow"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w)
    "sans-serif"(w)
    hintstyle: 1(i)(w)
    lang: "en"(w)
    lcdfilter: 1(i)(w)
    prgname: "fc-pattern"(s)
    fonthashint: False(w)

Without it, Noto Color Emoji is still on the list, but waaaaaaay at the end, long after lots of other fonts have had a chance to supply the glyph:

$ fc-pattern -c sans|fmt -s
Pattern has 6 elts (size 16)
    family: "Bitstream Vera Sans"(w) "DejaVu Sans"(w) "DejaVu
    Sans"(w) "Liberation Sans Narrow"(w) "Snap"(w) "DejaVu Sans"(w)
    "Verdana"(w) "Arial"(w) "Albany AMT"(w) "Luxi Sans"(w)
    "Nimbus Sans L"(w) "Nimbus Sans"(w) "Nimbus Sans"(w)
    "Helvetica"(w) "Nimbus Sans"(w) "Lucida Sans Unicode"(w)
    "BPG Glaho International"(w) "Tahoma"(w) "Open Sans"(w)
    "Droid Sans"(w) "Overpass"(w) "Calibri"(w) "Corbel"(w)
    "Montserrat"(w) "MgOpen Moderna"(w) "Arial"(w) "Impact"(w)
    "Tahoma"(w) "Trebuchet MS"(w) "Verdana"(w) "URW Gothic"(w) "Nimbus
    Sans"(w) "Nimbus Sans Narrow"(w) "Carlito"(w) "Source Sans 3"(w)
    "D-DIN Condensed"(w) "D-DIN Exp"(w) "D-DIN"(w) "Roboto"(w)
    "Droid Sans"(w) "Nachlieli"(w) "Lucida Sans Unicode"(w) "Yudit
    Unicode"(w) "Kerkis"(w) "ArmNet Helvetica"(w) "Artsounk"(w)
    "BPG UTF8 M"(w) "Waree"(w) "Loma"(w) "Garuda"(w) "Umpush"(w)
    "Saysettha Unicode"(w) "JG Lao Old Arial"(w) "GF Zemen Unicode"(w)
    "Pigiarniq"(w) "B Davat"(w) "B Compset"(w) "Kacst-Qr"(w)
    "Urdu Nastaliq Unicode"(w) "Raghindi"(w) "Mukti Narrow"(w)
    "malayalam"(w) "Sampige"(w) "padmaa"(w) "Hapax Berbère"(w) "MS
    Gothic"(w) "UmePlus P Gothic"(w) "Microsoft YaHei"(w) "Microsoft
    JhengHei"(w) "WenQuanYi Zen Hei"(w) "WenQuanYi Bitmap Song"(w)
    "AR PL ShanHeiSun Uni"(w) "AR PL New Sung"(w) "MgOpen Modata"(w)
    "VL Gothic"(w) "IPAMonaGothic"(w) "IPAGothic"(w) "Sazanami
    Gothic"(w) "Kochi Gothic"(w) "AR PL KaitiM GB"(w) "AR PL KaitiM
    Big5"(w) "AR PL ShanHeiSun Uni"(w) "AR PL SungtiL GB"(w) "AR PL
    Mingti2L Big5"(w) "MS ゴシック"(w) "ZYSong18030"(w)
    "TSCu_Paranar"(w) "NanumGothic"(w) "UnDotum"(w) "Baekmuk
    Dotum"(w) "Baekmuk Gulim"(w) "KacstQura"(w) "Lohit Bengali"(w)
    "Lohit Gujarati"(w) "Lohit Hindi"(w) "Lohit Marathi"(w)
    "Lohit Maithili"(w) "Lohit Kashmiri"(w) "Lohit Konkani"(w)
    "Lohit Nepali"(w) "Lohit Sindhi"(w) "Lohit Punjabi"(w) "Lohit
    Tamil"(w) "Meera"(w) "Lohit Malayalam"(w) "Lohit Kannada"(w)
    "Lohit Telugu"(w) "Lohit Oriya"(w) "LKLUG"(w) "Noto Sans"(w)
    "FreeSans"(w) "FreeSans"(w) "Arial Unicode MS"(w) "Arial
    Unicode"(w) "Code2000"(w) "Code2001"(w) "sans-serif"(s) "Roya"(w)
    "Koodak"(w) "Terafik"(w) "Noto Color Emoji"(w) "sans-serif"(w)
    "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w)
    "sans-serif"(w) "sans-serif"(w) "Lato"(w) "sans-serif"(w)
    "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w)
    "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "ITC Avant Garde
    Gothic"(w) "URW Gothic"(w) "sans-serif"(w) "sans-serif"(w)
    "Helvetica"(w) "Helvetica Narrow"(w) "Nimbus Sans Narrow"(w)
    "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w)
    hintstyle: 1(i)(w)
    lang: "en"(w)
    lcdfilter: 1(i)(w)
    prgname: "fc-pattern"(s)
    fonthashint: False(w)

Metadata Update from @ngompa:
- Issue tagged with: experience

2 years ago

Qt might need to do something like this. Basically you want to tell fontconfig to prefer color fonts when displaying the emoji.

The NeoChat developers found a simpler set of changes: Simply put this file at https://invent.kde.org/network/neochat/-/blob/master/cmake/Flatpak/99-noto-mono-color-emoji.conf in ~/.config/fontconfig/conf.d

That works perfectly for me.

Ping. Is it sane to ship these as a global config in Fedora KDE so all apps benefit from it?

@justinz I guess the question is, should it be included in the Noto Color Emoji RPM itself? The Font Guidelines say, re: fontconfig, that:

✓Font packages SHOULD include the fontconfig files, that define the selection and substitution rules applying to their font files,

  • written by the packager if upstream does not provide them.

✓ Fontconfig rules SHOULD define the generic family, a font contributes to,

  • a single generic family: the packager MUST choose,

  • using the correct priority: lower takes precedence over higher.

Sounds to me like that config should be part of the font packaging for Noto Color Emoji, and IMHO it makes more sense there, than for the KDE sig to own it. Perhaps a PR to https://src.fedoraproject.org/rpms/google-noto-emoji-fonts, if someone is feeling ambitious?

(Also sounds, though, based on point 2A up there, like the "serif and sans-serif and monospace" preferential configs may have to go, in favor of just a preference in the "single generic family" of sans-serif. Unless someone can convince The Powersâ„¢ that emoji fonts straddle all of those lines, and warrant an exception.)

Metadata Update from @ngompa:
- Issue assigned to ngompa

a year ago

@tagoh is not pleased with the change, and says it's a bad workaround.

According to him, the correct fix is to have Qt actually handle the emoji font type instead.

He's got detailed feedback here: https://src.fedoraproject.org/rpms/google-noto-emoji-fonts/pull-request/9#comment-132236

Makes sense; Qt has https://bugreports.qt.io/browse/QTBUG-85744.

Once that's fixed in Qt, we would want to also add a UI to make it configurable in the fonts KCM.

All of that is quite long-term though. I don't see it happening anytime soon unless someone takes a special interest in submitting a Qt patch. Until that happens, in the absence of alternatives, I think doing it your way is acceptable.

This workaround no longer works. It now causes severely broken text rendering. We need to try to get this fixed in Qt properly.

I just posted an update to https://bugreports.qt.io/browse/QTBUG-85744 referencing the relevant Unicode Technical Report (TR51), which details how this is intended to be handled.

(As @ngompa says, font fallback isn't meant to be the mechanism at all. The configured emoji font should be used preferentially and unconditionally, when rendering any emoji characters that are to be displayed with emoji presentation rather than text presentation.)

I've removed the fontconfig snippet recommendation from the KDE wiki page for distro packaging recommendations because it now makes things worse instead of better.

Login to comment on this ticket.

Metadata