ひ to り go と

OS X 10.8 で改善された Layer Backed View とテキストレンダリング

MacDev

以前 NSView (AppKit) の CALayer 対応について、テキストのサブピクセルレンダリングが上手く機能しない問題があるという記事を書いた。Sleipnir for Mac の開発ブログ記事でもこの問題に触れられている。

復習すると、

  • 古くからの描画方式では通常 1 つのウインドウにつき 1 枚のグラフィックスコンテキストがある。
  • layer-backing を有効にするとそれぞれの NSView がグラフィックスコンテキストを持つようになる。
  • サブピクセルレンダリングは背景の色に依存。必ず背景の上に描画しないといけないので Layer-backed view とは相性が悪い。

...しかし、あれは Lion の時点での話。

Mountain Lion での改善

10.8 の AppKit Release Note にはこんなことが書かれている:

NSTextField has been updated to allow LCD font smoothing to work when the view is layer-backed. Prior to 10.8, NSTextField would directly draw the text into the layer's contents; this would cause text to render incorrectly due to the LCD font smoothing algorithm not having adjacent pixels to smooth fonts with. Layer-backed applications that manually draw text should move to using NSTextField to get proper LCD font smoothing.

自分の理解:

  • NSTextField がアップデートして layer-backed でもサブピクセルレンダリングできるようになった!
  • これまで NSTextField の描画内容は、ほかの NSView サブクラスと同様、layer の contents に 1 枚のビットマップ画像として設定されていた。これでは描画するときにその背景を知りようがないので正しくサブピクセルレンダリングできない。
  • そこで 10.8 以降は何か特別な仕組みで描画するようになったみたい。
  • 今後は、自作ビュー内に自力で描画していたテキストも NSTextField に任せるといいらしい。

続きを読むとこれが機能するには条件があって:

One caveat is that NSTextField does require an ancestor which is layer-backed and opaque; it does not have to be the direct parent view, but some view in the ancestor chain must be opaque for this to be turned on and work correctly.

NSTextField の superview をたどっていったとき、先祖のどこかで「layer-backed かつ opaque」なビューが必要らしい。

実験してみよう

いくつかの疑問:

  • 本当に機能するの?
  • 10.7 との違いは?
  • 裏にあるビューの中で色が変化しても大丈夫?

まず、NSWindow を 1 つ用意。contentView の中に NSTextField と SomeView を配置。

  • contentView:ウインドウ全体を覆うビュー。
    • 背景を [NSColor windowBackgroundColor] で塗りつぶす。
  • SomeView:適当な図形を表示するビュー。
    • -isOpaque で YES を返す。
    • 2 つ用意。上には NSTextField の兄弟として、下には NSTextField の親として配置。

結果 1:Layer なし

AppKit の昔からある描画方式。

言うまでもなくサブピクセルレンダリングは正しく機能している。これが理想。

結果 2:OS X 10.7.5 での結果

これ以降は contentView が layer-backed である。

字がふにゃふにゃしていて汚い。

結果 3:OS X 10.8.2 での結果

Release Note に書かれていた通りだ。

  • NSTextField と SomeView が兄弟関係にある上では効いていない。
  • 親子関係にある下ではしっかりサブピクセルレンダリングされている。

サブピクセルレンダリングが効いていない部分(上)も Lion(結果 2)より奇麗。

結果 4

おまけ。contentView を opaque にしてみた。

これで全体にサブピクセルレンダリングが効くようだ。結果 1 との違いもないのではないか。

結論

NSView が CALayer による layer-backing をサポートしていても使うのをあきらめてしまう原因の一つだったけど、Mountain Lion で大きく改善されたようだ。ちょっとした制約はあるけれども。

Share

(参考になったらぜひ。記事を書くモチベーションの向上に役立てます。)