Slow TextLayout on OSX with memory-based fonts

No, I didn’t remove any code relating to this. I did take the opportunity to rip out a pile of old legacy stuff for 10.5. But the fallback for pre-10.11 memory fonts is still there and older systems should still use it.

1 Like

Hmm unfortunately the fix destroys my tooltips which are using TextLayout and fonts stored in memory. This is using the OSX 10.11 SDK with 10.11 deployment target on a 10.11 machine.
Before the commit:
before

After the commit:
after

I have my font in BinaryData and use LookAndFeel::getTypefaceForFont(…) to override the default fonts. Obviously it is using characters from the font, but the wrong ones.

Everything else in my GUIs seems unaffected, but as far as I know the tooltip window is the only spot a textlayout is used.

Edit:: weirdly enough it looks like all the char codes are just offset by 2 for rendering.

Setting canAllTypefacesBeUsedInLayout (…) to return false fixes my issue, but I can’t do that without patching JUCE.
My font does work correctly on OSX outside Juce and the same code/font does work on windows.
My conclusion is that at least with my configuration the old workaround is still needed even on pure 10.11 and I would very much like to have a way to override the new behaviour with the old one as I have no issues with speed.

Update: I tried running the same thing on 10.13 and there it is displaying correctly. I have no access to 10.12. Anything below 10.11 will use the old workaround and probably work in my case.

1 Like

Anyone else seeing this issue? Maybe it’s just my font that’s somehow weird.

I really wonder what that bug looked like that caused the workaround to be added… was it similar to what I’m seeing?

I just updated to the latest JUCE and have garbled tooltips as well… :frowning:

This is already fixed on develop. See here:

Hot fix will appear on master soon.

2 Likes

Thanks, good to hear! BTW, the bug also affected MacOS 10.13.2 which I´m running. I´ll check out the latest develop.

I have been doing some tests in an attempt to track down where the behavioural discrepancies are arising from by building with various versions of the SDK, running on various versions of OSX and isolating different parts the changes I made. It seems to me that the reason we are observing different behaviour is because I also added some code in my LookAndFeel class which registers the font with the CoreText font manager:

#if JUCE_MAC
bool myLookAndFeel::registerCFTypeface (const char *data, size_t length)
{
    CFDataRef fontData = CFDataCreate (kCFAllocatorDefault, (uint8_t *) data, (CFIndex) length);
    
    if (fontData == nullptr)
        return false;
    
    bool result = false;
    CGDataProviderRef provider = CGDataProviderCreateWithCFData ((CFDataRef) fontData);
    if (CGFontRef font = CGFontCreateWithDataProvider (provider))
    {
        CFErrorRef error;
        result = CTFontManagerRegisterGraphicsFont (font, &error);
        CFRelease (font);
    }
    
    CFRelease (provider);
    CFRelease (fontData);
    
    return result;
}
#endif

If I don’t include this I also see garbled text on OSX 10.11 and 10.12 with both versions of the SDK. With this included the results are as mentioned in my original post (even with the 10.11 version of the SDK) – on OSX 10.11 and above, big layouts will render much faster and will not show garbled text, versions lower than 10.10 are excluded and will go via the old route (slower but still no garbled text).

2 Likes

Thanks George! So we could achieve the same thing just by adding a call to CTFontManagerRegisterGraphicsFont in the OSXTypeface constructor at line 505:

    if (fontRef != nullptr)
    {
        CTFontManagerRegisterGraphicsFont (fontRef, nullptr);

        ctFontRef = CTFontCreateWithGraphicsFont (fontRef, referenceFontSize, nullptr, nullptr);

?

FYI I think this function was the missing piece of the puzzle - rather than checking the OS version number, we can just check the return value of CTFontManagerRegisterGraphicsFont. Will push something to develop shortly and would appreciate feedback on whether it finally fixes this one!

I am pretty sure using that function fixes fallback for unknown characters too.

That would be most excellent

Great, that’ll be a double-whammy!

Jules, I tried the fix you just committed on 10.11.6 and for me it fixes the issue with the font I’m using and textlayouts inside tooltips.

1 Like

We’re still seeing garbled tooltips on the latest develop tip (on at least macOS 10.12) with memory-based fonts, though it seems to occur very infrequently — maybe 10% of the time the plugin is instantiated.

38%20PM

A workaround that worked well for me was using the GlyphArrangement class to create a Path object that draws the text with a custom font. No issues with just drawing the path as opposed to the text.

void paint (Graphics& g) override {
    GlyphArrangement textGlyph;
    Path textPath;

    // The text will be centered within the component
    textGlyph.addLineOfText (someFontToUse, someStringToDisplay,
                             proportionOfWidth(0.5f) - (someStringWidth / 2.0f),
                             proportionOfHeight(0.5f) + (someStringHeight / 2.0f));
    textGlyph.createPath (textPath);
    g.setColour (whateverColourToUse);
    g.fillPath (textPath);
}

This saved about ~20% CPU during animations as well as got rid of any weirdness with rendering memory-based fonts, especially when I took actually creating the Glyph out of paint(). This was only on necessary on Mac for me.

2 Likes

Thanks! This is essentially what we’re doing as a workaround too.

Oh, that’s bad news. I haven’t seen any problem since the last fix was applied by Jules.

That path rendering workaround will make the font look different (thinner) and have no subpixel antialiasing on OSX with the native renderer. IMHO it would be better to have the option to fall back to the slower code by a preprocessor directive or even as a property of the textlayout… or even better would be a fix that works in all cases.

Hi @jules
I am still seeing garbled text using the new method of checking the return value of CTFontManagerRegisterGraphicsFont.

I am testing with 10.10 and a 10.9 virtual machine and it appears that when I use a custom font (ProximaNova) the result of CTFontManagerRegisterGraphicsFont is true however the text displays like this: -

image

On my 10.13 machine it returns true and renders correctly, it seems like the result of CTFontManagerRegisterGraphicsFont might not be reliable for all fonts on all macOS versions. Do you think we might need to re-introduce some of the os version checks or is there another way?

3 Likes

The below change seems to fix it for me by forcing older os’s to use the slow route. However I think SDK version might be muddying the issue too. We are using ‘latest SDK’ which in my case is 10.13 and when run on 10.9 and 10.10 the text renders slower but correctly, when run on 10.12 and 10.13 it renders really quick and looks fine.

#if JUCE_MAC        
if (SystemStats::getOperatingSystemType() >= SystemStats::OperatingSystemType::MacOSX_10_11)
{
    #if JUCE_MAC && defined (MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
    canBeUsedForLayout = CTFontManagerRegisterGraphicsFont (fontRef, nullptr);
    #endif
}
#endif
2 Likes