3

My app draws layer-backed labels over a NSImageView.
The image view displays an image, and a tint color over that image.

This ensures that the contrast between the labels and the background image works.

enter image description here

As you can see, subpixel antialiasing is enabled and works correctly.

When you hover over those labels, they animate the frame property (Actually the view containing them).
While animating, the subpixel antialiasing is disabled, and when done enabled again.

enter image description here

This looks incredibly weird.

The layer is never redrawn, and the subpixel antialiasing doesn't have to change.
So I don't see a good reason why it shouldn't be displayed when animating.

I've tried everything I can think of.

  • Making the NSTextField opaque
  • Making the CATextLayer opaque
  • Giving the NSTextField a background-color
  • Giving the CATextLayer a background-color

Always the same result.

Disabling subpixel antialiasing for the labels is not an option, since it's not well readable on non-retina devices.


EDIT

I forgot that the layer is replaced with a presentationLayer while animating.
This layer probably does not support subpixel antialiasing, which is why it's disabled.

Now the question is if I can replace this presentationLayer with a CATextLayer.

What I also noticed is that setting shouldRasterize to YES enabled subpixel antialiasing also for animation, but only against the background color. So no background-color will bring no subpixel antialiasing.

IluTov
  • 6,807
  • 6
  • 41
  • 103
  • This might do nothing, but have you tried doing the text drawing over a standard NSView rather than an NSImageView. I needed to do annotations over an image a few months ago and ended up using a plain NSView because I had a few odd problems when using the image view. – Daniel Farrell Mar 26 '14 at 10:16
  • @boyfarrell Nope, just tried it. No effect. – IluTov Mar 27 '14 at 08:52
  • perhaps you can grab the pixels from the text layer and animate those instead (in 1 pixel increments?) the sub-pixel AA is really dependent on what's behind the layer, so even if you get it to work it may not look right. – nielsbot Mar 27 '14 at 23:38
  • @nielsbot This is an option, yes. I will have to try it out and see how it looks. – IluTov Mar 28 '14 at 11:40
  • CoreAnimation might disable it in order to do faster compositing while animating? – Trenskow Apr 01 '14 at 11:58
  • 2
    And what are you working on?!? :) I did work for Pioneer once, and your image contains the first three letters of my last name and their name. Very suspicious. :) – Trenskow Apr 01 '14 at 12:00
  • Maybe this will help? http://stackoverflow.com/questions/6858205/faking-subpixel-antialiasing-on-text-with-core-animation – Trenskow Apr 01 '14 at 12:03
  • @Trenskow I know your deepest secrets. – IluTov Apr 01 '14 at 12:05
  • Haha! Then please don't share them... :D – Trenskow Apr 01 '14 at 12:06
  • @Trenskow Thanks for the link. This was back in the days when subpixel AA wasn't possible at all in layer-backed views. Apple has fixed this since, but unfortunately the problem remains while animating. – IluTov Apr 01 '14 at 12:07
  • @Trenskow And if you're really interested in what I'm working on, [this is it](http://www.nimblifyapp.com/). Don't worry, just music ;) – IluTov Apr 01 '14 at 12:14

2 Answers2

1

Is there any way that you can post a piece of sample code? I quickly mocked up an NSWindow, added an NSImageView, added a background-less NSTextField with setWantsLayer: set to YES. In my applicationDidFinishLaunching: I set a new rect on the NSTextField's Animator frame, but I didn't see any pixelation.

blackirishman
  • 903
  • 1
  • 10
  • 23
  • I wrote in the question that this happens while animating ;) – IluTov Mar 28 '14 at 04:26
  • Btw you need to watch closely. It's hardly visible on dark text – IluTov Mar 28 '14 at 07:25
  • I understand that it happens while animating, that's why I used an animator proxy to adjust the NSTextFields's frame which moved the frame's layer. I did see it happen when I zoomed in on the text using zoom provided by the accessibility zoom tool. I also saw it happen when I switched applications. But it appears normal if you don't zoom in on the text or switch applications. Even adjusting the window frame doesn't introduce pixillation. When I brought the application to the foreground, I found calling setNeedsDisplay on the NSTextField's layer removed any pixillation. – blackirishman Mar 28 '14 at 16:21
  • Try adding a white text to a dark background, and animating then. You'll see that then it's much more visible. After the animation has stopped subpixel AA is enabled again, and everything looks fine. – IluTov Mar 28 '14 at 17:47
  • I am curious as to what behavior you see. – blackirishman Mar 28 '14 at 18:12
  • 1. When you animate subpixel AA is disabled. 2. When it stops it's not updating. 3. When I press update it doesn't update AA. The only problem I have in my app is 1. – IluTov Mar 28 '14 at 18:18
  • In the example I posted on Github, sub pixel aa does not appear to be disabled. I don't see any artifacting unless I switch applications. When I make my application foremost, I see the artifacting. After I saw this, I made sure that NSImageView was layerBasked as well. After I set this to true. The artifacting no longer appeared. – blackirishman Mar 28 '14 at 23:54
  • Try making the whole content view of the window layer-backed. The key here is that subpixel AA needs to be enabled WHILE animating. In your demo project it's not. Make the animation slower and you'll see. ;) – IluTov Mar 29 '14 at 08:14
  • Once I made the animation smaller, I saw the aa turn off. In the project I posted, the effect was negligible, but it affected the appearance none the less. May I venture that the presentation layer is not being composited with the background layer at all and perhaps never will be until the animation stops? – blackirishman Apr 01 '14 at 04:11
  • Jep, this seems to be the problem. I'll give you the bounty, just so it doesn't go wasted. I'll leave the question opened until there's a real solution ;) – IluTov Apr 01 '14 at 12:08
0

The problem is with positioning of the text layer. Let's presume you use left alignment. The text will look good if x and y coordinates of the layer's frame origin are rounded numbers. For example:

CGFloat x = 10.6;
CGFloat y = 10.3;

textLayer.frame = CGRectMake(x, y, width, height); // the text will be blur.
textLayer.frame = CGRectMake(round(x), round(y), width, height); // the text will not be blur.

So, the first problem may be that the coordinates you assign to the layer's frame are not rounded. The tricky part is that the edge of the layer may still be not aligned with pixels even if you think you passed rounded coordinates. This may happen if the anchorPoint of your layer is (0.5, 0.5), which is the default value. If you set:

textLayer.position = CGPointMake(10.0, 10.0);

you may think it should draw the text sharp. However, position point is in the center of the layer here, and depending on the layer's width and height the left and top edge's coordinates may be fractional numbers.

If you want to make a quick test do this.

  1. Use textLayer.frame = frame instead of using position and anchor point, it will assign the coordinates directly to the frame.
  2. Make sure the numbers you use in the frame are rounded.
  3. Do not mess with rendering mechanism, remove the code that changes shouldRasterize, antialiasing, etc.

If this makes the text sharp, you can start using the anchor point and position and to see how the result changes.

Davyd Geyl
  • 4,578
  • 1
  • 28
  • 35
  • Unfortunately this isn't the problem either. Subpixel AA is even disabled when making an alpha animation, which doesn't allow for this possibility. – IluTov Apr 01 '14 at 06:07