Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bad text rendering with Core Animation

First of all, I know this topic has been brought up several times before but I'm posting this question because none of the "solutions" I've used in the past have worked in this specific case. I'm drawing some text to a CALayer that is hosted by a view inside my NSToolbar. Here's what the text look likes:

Font smoothing on

I tried using a suggestion from this StackOverflow post, which is to call CGContextSetShouldSmoothFonts(ctx, false) to turn off subpixel antialiasing before drawing into the context. This is a solution that has given me acceptable results in the past, but in this case it seems to have made the text look even worse:

Font smoothing off

The other solution mentioned in that post is to fill the rect with an opaque background color before drawing, which simply isn't possible in this case because the toolbar background is a gradient. Is there anything I can do to make this text look as nice as text drawn into a plain NSView?

like image 695
indragie Avatar asked Feb 03 '23 15:02

indragie


2 Answers

The reason sub-pixel antialiasing is not possible is that behind the scenes, CALayers are essentially just OpenGL textures.

This means they are bitmaps handled and rendered directly by the GPU. The GPU knows nothing about text and so can't apply sub-pixel antialiasing.

In order to handle sub-pixel antialiasing, it would have to recalculate the pixel values of the layer content each time the layer was modified, which would be prohibitively expensive and remove the whole point of hosting the layer on the GPU, which is to make compositing and rendering extremely fast.

The reason that text on opaque backgrounds can use SPAA is that the text is pre-rendered with sub-pixel anti-aliasing before the layer texture is stored on the GPU. This is not possible if the background of the text is transparent.

You will have to live with this limitation. Thankfully, it will no longer be an issue when we eventually all get HiDPI displays… have a look at the iPhone, which does not do sub-pixel antialiasing at all. On the iPhone, text looks just fine thanks to the high screen resolution.

like image 161
Rob Keniger Avatar answered Feb 05 '23 03:02

Rob Keniger


Unfortunately there's no magic fix. At the end of the day, the text must be drawn on to an opaque background to get SPAA. It sucks, but it makes a lot of sense given how layers work. And honestly, I can't see Apple ever "fixing" this. I think this is the reason they've stuck with the old software compositing model for so long. It's a hard problem and they're hoping to ignore it by going high-DPI.

But anyways, there are a few ways to get SPAA in your specific case.

You could try to re-create the gradient and draw it yourself when you draw your text. But obviously that's brittle if the toolbar gradient changes in an OS update, and it could be hard to get the gradient to match exactly right.

Or you could actually try to grab an image of the toolbar background, either at runtime or ahead of time, and draw that as your background.

like image 37
joshaber Avatar answered Feb 05 '23 04:02

joshaber