setFallbackFontName broken?

HACK CODE BELOW!

(juce_mac_fonts.mm)

A little wrapper around obj-c
template <typename T>
class  JuceOBJCType
{
public:
    inline JuceOBJCType(const T* t = nil) : objCtype(t) {}
    inline JuceOBJCType(const JuceOBJCType &helper) : objCtype(helper.objCtype) { if (objCtype) [objCtype retain]; }
    inline ~JuceOBJCType() { if (objCtype) [objCtype release]; }
	
	 inline  operator T*() { return objCtype; }
	inline T * get(){
		return objCtype;
	}
    inline JuceOBJCType operator =(const JuceOBJCType &helper)
    {
		if (objCtype !=helper.objCtype)
		{	
			[helper.objCtype retain];
			[objCtype release];
			objCtype=helper.objCtype;
			
		}
		return *this;
    }
    inline T *operator&() { return &objCtype; }
protected:
    T * objCtype;
};

    void createGlyphsForString (String::CharPointerType text, const int length, HeapBlock <CGGlyph>& glyphs)
    {
		//http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/TextLayout/Tasks/DrawingStrings.html
		
		textStorage=[[NSTextStorage alloc] init];
		layoutManager=[[NSLayoutManager alloc] init];

		
		[textStorage.get() addLayoutManager:layoutManager];
		textContainer=[[NSTextContainer alloc] init];
		[layoutManager.get() addTextContainer:textContainer];
		[[textStorage.get() mutableString] setString:juceStringToNS(String(text,length))];
		
      #if SUPPORT_10_4_FONTS
       #if ! SUPPORT_ONLY_10_4_FONTS
        if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
       #endif
        {
            glyphs.malloc (sizeof (NSGlyph) * length, 1);
            NSGlyph* const nsGlyphs = reinterpret_cast<NSGlyph*> (glyphs.getData());

            for (int i = 0; i < [layoutManager.get() numberOfGlyphs]; ++i)
			{   nsGlyphs[i] = [layoutManager.get() glyphAtIndex:i];//(NSGlyph) [nsFont _defaultGlyphForChar: text.getAndAdvance()];
				
				
				jassert(textStorage !=nil);
				NSRange aRange=NSMakeRange(1,1); // Let's see what font is at the index now...
				NSLog([[textStorage.get() attribute:NSFontAttributeName
														  atIndex:1 effectiveRange:&aRange]fontName]);
			}

            return;
        }
      #endif

       #if ! SUPPORT_ONLY_10_4_FONTS
        if (charToGlyphMapper == nullptr)
            charToGlyphMapper = new CharToGlyphMapper (fontRef);

        glyphs.malloc (length);

        for (int i = 0; i < length; ++i)
            glyphs[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text.getAndAdvance());
       #endif
    }

Stuffed in the MacTypeFace class

//==============================================================================
    CGFontRef fontRef;
    float fontHeightToCGSizeFactor;
    CGAffineTransform renderingTransform;
	JuceOBJCType<NSTextStorage> textStorage;
	JuceOBJCType<NSLayoutManager> layoutManager;
	JuceOBJCType<NSTextContainer> textContainer;

Is that really what needs to be done? In our case we would like ‘Lucida Grande’ to render the text, but if one of the glyphs isn’t present it can use ‘Arial Unicode MS’ as fallback. Can’t we just render in the fallback if one of the glyphs is not present?

Thanks Justin! The main worry about your approach is that it’ll be vastly slower than the old code.
(Interesting that you wrote an obj-c wrapper - I’ve considered writing one of those many times, but never quite got around to it.)

Gekkie: well, I suppose it could just give up on the entire string and use the fallback font, but even then it’d need to be able to pass that information along to the graphics context, so it wouldn’t be a free ride.

Justin, could you explain me how you create a font (code snippet) with a cascade list using CTFontCreateForString. I dug around the apple developer site and they say you can create a cascade list but i couldn’t find exactly how to do this.

It should all be in
http://developer.apple.com/library/mac/#documentation/Carbon/Reference/CTFontDescriptorRef/Reference/reference.html

Specifically kCTFontCascadeListAttribute

This is all untested, but you should be able to get the global cascade list by calling

CTFontDescriptorCreateWithNameAndSize to get a CTFontDescriptorRef and then CTFontDescriptorCopyAttributes. The kCTFontCascadeListAttribute key will then give you an array.

I should stress though that this won’t help you because of the coregraphics stuff I mentioned earlier.

If you only had a few items to display and you didn’t know the string contents ahead of time, I suppose you could check if it is displayable with the current font by calling CTFontGetGlyphsForCharacters and manually setting the font for the component to a unicode font if it fails?

Jules wrote

[quote]Thanks Justin! The main worry about your approach is that it’ll be vastly slower than the old code.
(Interesting that you wrote an obj-c wrapper - I’ve considered writing one of those many times, but never quite got around to it.)[/quote]

All your posts stressing RAII finally sunk in I guess…
Its too bad the operator () overload doesn’t work though!

[textStorage.[b]get/b addLayoutManager:layoutManager];
vs the treacherous waters of…
[(NSTextStorage*) textStorage addLayoutManager:layoutManager];

Ah yes… Maybe that was the reason I didn’t write one, I think I might actually have started doing one, but then realised it was going to be troublesome and decided not to complicate things.

While working on the Mac software renderer for the next gen JUCE text system I noticed some messed up fonts. Sure enough this thread explained it.

This confirms what I suspected in my other post, it would seem my CoreText-CoreGraphics renderer is doing auto font fallback on its own. You can see it in action in the following links:

Arabic - http://i.minus.com/iMzFcLlsN6qvQ.png
Thai - http://i.minus.com/ikqqzV7dDYFex.png
Hindi - http://i.minus.com/iYW8NX8YqVqMq.png

The non English glyphs are definitely not in Lucia Grande, so font fall back is automatically kicking in.

With the hints that justin gave, I hope that I can get font fallback working on my CoreText-Software renderer. I should be able to save some time by checking only one glyph per run since the font family in each run should be the same.

DirectWrite (what I’ll be using on Windows) is supposed to have some sort of font fallback as well but I won’t know for sure until I get my feet wet.

So once I finish the system and then Jules integrates/rewrites it, you should have your font fallback.

Jules did you find some more time to work on this. We are nearing a release and would really love to have the fallback back.

Jules is in the process of implementing my next gen JUCE text system into the mainline.
The next gen text system supports automatic font fallback (OS X 10.5+, Vista+), so while you won’t be able to specify the exact fallback fonts to use yourself, you will get fallback fonts based on what the OS chooses.
This should satisfy most use cases.

Sonic, although i’m interested to see what this next gen text system does i’m not very pleased with the situation right now.

Jules, i know building new features like OpenGL rendering is much more fun i hope the next time you make sure all existing features are working properly before you dive into something new. The font fallback is something we and probably a lot of others benefit from without actually knowing it’s there, i don’t like to take a step back. I mean i updated the Juce version we use but we actually lost some important functionality, but i can’t go back either.

We need it. For us this poses quite a big problem atm, i mean there is not a simple solution to the problem right now.
What do you or others suggest we do?

I can come up with the following solutions:

  • use ‘Arial Unicode MS’ for all text, so all glyphs will be present, looks very bad!
  • give the user a dropdown in the preferences to choose the fonts he want to use, ouch ;-(!!!
  • use the FreeType renderer from The Vinn, does this account for the fallback Vinn?
  • pay Jules some extra pocket money to get this fixed, i would actually but i rather do this for new features
  • get font code from older Juce version, hmmm …

Any other more elegant solutions are welcome!

The problem isn’t that I’m not interested in working on this! As I think I explained earlier, the Cocoa APIs simply do not provide a way to find out if a glyph is missing, unlike the old (deprecated) font APIs that the older version used.

Why did you replace old working code (maybe not as elegant as you’d like) with code that that’s just not finished, please explain me that.
You can’t just remove functionality and say, go figure it out yourself.

I didn’t get rid of it because it was inelegant, I got replaced it because it relied on deprecated APIs that Apple no longer supports!

Well, whatever solution you pick, if it involves writing code you are probably wasting your own time and money for a feature that is coming soon.

The way I see it there are two scenarios for font fallback:

Scenario 1: I just want to see the proper glyphs, I don’t care which fonts get used.

This is essentially automatic font fallback. This will be working on both Mac OS X 10.5+, iOS 3.2+ and Vista+ when the new text system is in place. You can see it in action on the mac here. The font was set to Lucidia Console but there are no Arabic glyphs in Lucidia Console. The Arabic glyphs are from another font that the operating system automatically fell back to. This scenario should satisfy 98% of peoples use of font fallback.

Scenario 2: I need the font to fall back to a very specific font of my choosing.

While, this is not possible on Vista and greater as DirectWrite doesn’t support manual font fallback, it should be possible on OSX/iOS. I didn’t bake it in since there wasn’t a cross platform solution. But it should just be a matter of adding the kCTFontCascadeListAttribute to the font when creating the CFAttributedString.

If all you want is to fallback to Arial Unicode, I’m pretty sure that falls under scenario 1. Arial Unicode is available on both OSX and Windows and the operating system should be automatically falling back to it at the very end of its fallback list.

All I can say is be patient, it is coming. Overhauling the text system is a ton of work and will take time. But Jules is literally working on it right now, just look at git log, he’s already commited the early stages of it (11/21/11). Its not complete yet, but it certainly is not some mythical pipe dream either.

Ok, fair point, i was trying to find out why you made the changes, still doesn’t change the situation though.

[quote=“sonic59”]All I can say is be patient, it is coming. Overhauling the text system is a ton of work and will take time. But Jules is literally working on it right now, just look at git log, he’s already commited the early stages of it (11/21/11). Its not complete yet, but it certainly is not some mythical pipe dream either.
[/quote]

Sonic, i know you mean well and i saw your nice work on this new text system, but this overhaul is exactly what i’m afraid for. Ok in the end we’ll have a nice new layout system but before that’s working and thoroughly tested it will take a few months. It’s also build into the modules branch which bounds to have some hidden problems in it as well.
I mean i can’t keep on getting the latest stuff from the tip as that caused us unexpected problems each time we did. It will fix one thing but break another.
I need a stable branch where stuff is not likely to change all the time. And if parts contains bugs they have to be fixed and put in the stable branch, i think Jules already agreed on maintaining a stable branch once done with the modules branch, i really hope he can find some time to set this up.

Anyway, i don’t know what do now actually. Anyone…

While unfortunately this won’t help gekkie100, I’d just thought I’d give everyone else following this thread a heads up that the new text system has been integrated into the tip in the form of an updated TextLayout class.
So when using the TextLayout class, automatic font fallback should be working now.

However, it is important to note that most text rendering in juce is not done using TextLayout so even though the new system is in there, you won’t be seeing auto font fallback for most common controls (Labels, etc). They are all rendering text using the old system where, as gekkie100 has pointed out, font fallback isn’t working.

The TextLayout sounds good, something that springs to mind would be a syntax colored code editor. Now i just hope we can convince Jules or anyone else to help us out with the font fallback.