LookAndFeel, Custom Fonts, Linux Leaks

Hello,

Sorry for the long post, but I’m having a hard time trying to figure out some issues I have with LookAndFeel. It seems like I’m not the only one, so I guess we need some kind of updated info on how to properly use and set the look and feel for plugins.
I also upgraded to JUCE 7 and I’m on the development branch.

We started porting some of our plugins to Linux and noticed that they are leaking the GlyphInfo class, which I suppose is related to the custom fonts implementation I’m using. macOS and Windows are not leaking, just Linux.

This is what we are doing right now, in PluginProcessor.h I have the following code before the actual AudioProcessor class (which I believe was suggested by Jules a few years ago):

struct MainLookAndFeel
{
    MainLookAndFeel()  { LookAndFeel::setDefaultLookAndFeel (&lnf);    }
    ~MainLookAndFeel() { LookAndFeel::setDefaultLookAndFeel (nullptr); }
    
    MyLookAndFeel lnf;
};

Then as a member of AudioProcessor, I have:

SharedResourcePointer<MainLookAndFeel> mainLookAndFeel;

And this was enough for all my needs, using also custom fonts this way:

    static const juce::Typeface::Ptr getOpenSansRegular()
    {
        static auto typeface = juce::Typeface::createSystemTypefaceFor (BinaryData::OpenSansRegular_ttf,
                                                                        BinaryData::OpenSansRegular_ttfSize);
        return typeface;
    }
    static const juce::Typeface::Ptr getOpenSansBold()
    {
        static auto typeface = juce::Typeface::createSystemTypefaceFor (BinaryData::OpenSansBold_ttf,
                                                                        BinaryData::OpenSansBold_ttfSize);
        return typeface;
    }
    
    juce::Typeface::Ptr getTypefaceForFont (const juce::Font& font) override
    {
        if (font.getStyleFlags() == juce::Font::bold)
        {
            return getOpenSansBold();
        }
        
        return getOpenSansRegular();
    }

So, again, macOS and Windows are perfectly fine with this, but Linux is leaking GlyphInfo. If I remove the custom fonts, I see no leaks on Linux.
I also tried to replace the SharedResourcePointer with a std::unique_ptr but I get the same issues.

So I created a new plugin with nothing but a custom LookAndFeel to test a few implementations and discovered another issue related to this thread.
If I’m using setDefaultLookAndFeel my popups call getParentComponentForMenuOptions on my LookAndFeel class and they open as I want. Instead, if I’m just using setLookAndFeel on the popup object, getParentComponentForMenuOptions in my LookAndFeel is NOT called, and popups open with default behavior.

So, to recap:

  • what’s the proper way of implementing and using custom LookAndFeel with custom fonts in plugins?
  • how can I avoid the leaking of GlyphInfo on Linux if I want to use custom fonts?
  • is it safe to use setDefaultLookAndFeel for plugins? if not, there’s something wrong going on as getParentComponentForMenuOptions in my LookAndFeel is not called when using setLookAndFeel on popups.
1 Like

Bump.

This is the project I’ve used to test a few things, and it leaks GlyphInfo on Linux.

VanillaTest.zip (161.7 KB)

static auto getOpenSansRegular() {
  static auto result = juce::Typeface::createSystemTypefaceFor (...);
  return result;
}

Here, result will have static storage duration, so it won’t be cleaned up until after the leaked-object-checker runs. If you want to avoid the leaked object warning, you could either just get rid of the static at function scope altogether, or you could store your cached fonts in your own singleton (use JUCE_DECLARE_SINGLETON and inherit from DeletedAtShutdown).

Yes, I think so.

Thank you for your reply.

Ok but it doesn’t leak on macOS and Windows, and making it non-static means the font is loaded everytime is requested, which doesn’t seem to be a good idea? What’s the most efficient way of implementing custom embed fonts in a plugin then?

Ok, still, I think something’s wrong when we don’t use setDefaultLookAndFeel and just use setLookAndFeel on popups, the getParentComponentForMenuOptions in our look and feel is NOT called (and as far as i know, it was called in earlier versions of JUCE 6).

Those platforms have their own typeface implementations, and don’t create GlyphInfo instances.

I can’t say without profiling. If creating fonts on demand causes performance issues in your plugin, then you could try caching the fonts in a singleton, as I suggested above.

That looks like a regression, I’ll get that fixed.

Thank you for the explanation! I also have this problem and now I finally understand why!

That’s fixed here:

Thanks for reporting!

Thanks for the fix! Does this fix the popupmenu background bug related to this post BUG? Popup Menu Background and Logic Silicon - #29 by lcapozzi ?

No, the pink menu backgrounds visible in Logic are mandatory and cannot be disabled.

Sorry to necro this kind of old thread, but it’s very much on point for an issue I’m having with custom fonts on Linux.

I want to ask where/how/when a custom font should be instantiated.

My sketchy implementation until now had the createSystemTypefaceFor just being created as a const in global scope. This worked fine in Windows and macOS, but completely blows up in Ubuntu 22.04, at some point in the font init whilst trying to do some kind of XML decoding from what I can decipher from the stack trace.

So really what I’m asking is what is the “best practise” for custom fonts that is portable across Windows/macOS/Linux?

Put the font in an object which inherit from DeletedAtShutdown

At the risk of self promo: Custom Fonts In Juce | Pull Request

TL;DR:

Implement a data structure that can hold fonts and return them. Place this data structure someplace accessible to the methods that need to know about fonts. Importantly, this needs to be done in a manner that makes lifetime easy to reason about.

In my project I implemented a simple Font Holder that is owned by my look and feel. It’s allocated on the stack, and will be destroyed when the look and feel is destroyed. The fonts themselves are held as unique pointers, and will be destroyed when the holder goes. No leaks!

Here’s what the font holder looks like:

Here’s a usage example:

2 Likes