Thank you Josh for this excellent analysis. My impression is that this is somewhat of a Kubuntu bug, still it is better to fix it in our code especially if this results in a speed up. Such a speed up is really needed for slower machines.
I will look through the details of the patch tomorrow and apply it. Cheers, Fred > Am 30.05.2020 um 21:37 schrieb Josh Freeman <gnustep_li...@twilightedge.com>: > > Some users of Kubuntu (official flavor of Ubuntu with the KDE Plasma > desktop) reported that PikoPixel's missing most of its UI text; Numbers are > the only characters displayed: > https://old.reddit.com/r/Kubuntu/comments/gas88l/pikopixel_strange_graphics_bug_any_suggestions_on/ > > I can reproduce this on Kubuntu 20.04, and the missing-text issue affects > all GNUstep gui apps, whether the apps & GNUstep are from packages or from > current sources. > > This might be the same issue that Patryk found last August with KDE Neon: > https://lists.gnu.org/archive/html/gnustep-dev/2019-08/msg00019.html > (I couldn't test this, because the current x86_64 builds of KDE Neon fail > to install on a VirtualBox VM, and older versions don't seem to be available). > > Manually installing a different desktop on Kubuntu doesn't fix the issue; > Text is still missing on GS gui apps when run under GNOME or Window Maker, > however, switching GS's backend from Cairo to Art fixes the text. > > Text displays correctly on Ubuntu 20.04 - even under Plasma - and also on a > daily build of Ubuntu Studio 20.10 (Plasma is Studio's installed desktop as > of 20.10). > > The issue's caused by a combination of two factors: > > A) The Cairo backend sets up fontconfig patterns for font matching by calling > the fontconfig library's Fc...Substitute() functions twice on each pattern > instead of once: > The backend's FCFaceInfo class has two methods, matchedPattern & > characterSet, that each call FcConfigSubstitute() & FcDefaultSubstitute(), > passing the FCFaceInfo instance member, _pattern, to be modified. Both > methods in turn are called from within a single method, -[CairoFontInfo > setupAttributes] (itself called from the FcFontInfo initializer): > 1. [CairoFontInfo setupAttributes]:[FcFontInfo (super) > setupAttributes]:[FCFaceInfo characterSet] > 2. [CairoFontInfo setupAttributes]:[CairoFaceInfo fontFace]:[FCFaceInfo > matchedPattern] > Note that the font face is only generated after the second set of > Fc...Substitute() calls. > > B) The fontconfig library's font-matching functionality behaves differently > on Kubuntu vs. other distros (even with the same version installed - Kubuntu > 20.04 & Ubuntu 20.04 both have libfontconfig1 2.13.1-2ubuntu3). > > > Alone, neither factor causes the issue, however calling the > Fc...Substitute() functions twice on the same pattern on Kubuntu leaves a > modified pattern that - when passed to FcFontMatch() - always resolves to the > "Noto Color Emoji" font. (That font has no alphabet characters, but does have > digits, which explains why only numbers appear in the above linked > screenshots). > > To demonstrate this, the attached C file, fc-pattern-check.c, builds a > standalone diagnostic tool using only the fontconfig library - no GNUstep. It > creates a fontconfig pattern for matching the "DejaVu Sans" font and makes > two sets of calls to Fc...Substitute() & FcFontMatch(), duplicating the calls > made by the Cairo backend. After each call, the resulting pattern is printed. > > The attached textfiles, fcpc_out_kubuntu.txt & fcpc_out_ubuntu.txt, are the > outputs from running the fc-pattern-check tool on Kubuntu 20.04 & Ubuntu > 20.04. > > Comparing the two output files, the first difference comes after the first > call to FcConfigSubstitute(): On Kubuntu, the pattern has a "rgba" > (pixel-format) field inserted - this may not contribute to the incorrect > match, but it already shows a different behavior between Kubuntu & Ubuntu. > > Following the first set of Fc...Substitute() calls, the first call to > FcFontMatch() correctly returns a resolved pattern for the "DejaVu Sans" font > on both Ubuntu & Kubuntu. When these same first calls are made by the Cairo > backend, the resolved pattern's used only to get the font's character set, > not to generate the font face for drawing. > > After the second call to FcConfigSubstitute() on Kubuntu, the pattern's > "lang" field for some reason now contains "und-zsye" (emoji locale) before > its earlier value, "en" (english). The pattern now also contains a "color" > field with a value of "True" (requiring a match to a font that contains color > information). With those field values present, the second call to > FcFontMatch() returns a resolved pattern for "Noto Color Emoji"; On Ubuntu, > its second FcConfigSubstitute() call doesn't add those "lang" & "color" > values to the pattern, and its second call to FcFontMatch() correctly returns > a "Deja Vu Sans" resolved pattern. > > > The attached patch, libs-back_fontconfig_pattern_fix.diff, fixes the > missing text by limiting FCFaceInfo's Fc...Substitute() & FcFontMatch() calls > to once per pattern. The resolved pattern returned by FcFontMatch() is now > stored in FcFaceInfo's _pattern member (which previously only held a > pre-matched pattern), and a new bool member, _patternIsResolved, keeps track > of _pattern's pre-matched/resolved state. > > The characterSet method now gets the resolved pattern by calling the > matchedPattern method instead of calling the fontconfig functions directly; > Outside of the initializer, dealloc, & matchedPattern methods, the _pattern > member is now only accessed by the displayName method (which just reads the > pattern's fullname, postscriptname, & style fields - if those were present in > the pre-matched pattern, they should remain in the resolved pattern), so > there should be no side-effects from storing a resolved pattern instead of a > pre-matched pattern in the _pattern member. > > Loading a large set of fonts will probably also go faster now, as > FcFontMatch() is only called half as often. > > Cheers, > > Josh > > > <fc-pattern-check.c> <fcpc_out_kubuntu.txt> <fcpc_out_ubuntu.txt> > <libs-back_fontconfig_pattern_fix.diff>