NSView の CGContextRef に ATSUI でテキストを描画する方法
Cocoa の NSView に Apple Type Services for Unicode Imaging (ATSUI) でテキストを描画する方法を紹介する。
ATSUI では描画に Quartz の CGContextRef を設定することができる。CGContextRef は NSGraphicsContext の graphicsPort で取得できるので、以下のようなコードで設定できる。
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
ATSUAttributeTag tags[] = { kATSUCGContextTag };
ByteCount sizes[] = { sizeof(CGContextRef) };
ATSUAttributeValuePtr values[] = { &context };
ATSUSetLayoutControls(layout, 1, tags, sizes, values);
以下のコードでは、NSView の drawRect: で Hello, World を描画している。
- (void) drawRect : (NSRect) rect
{
NSString *s = @"Hello, World!";
UniChar *text;
UniCharCount length;
ATSUStyle style;
ATSUTextLayout layout;
// Setup
ATSUCreateStyle(&style);
ATSUCreateTextLayout(&layout);
length = [s length];
text = (UniChar *)malloc(length * sizeof(UniChar));
[s getCharacters:text];
ATSUSetTextPointerLocation(
layout,
text,
kATSUFromTextBeginning,
kATSUToTextEnd,
length);
ATSUSetRunStyle(
layout,
style,
kATSUFromTextBeginning,
kATSUToTextEnd
);
// CGContext
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
ATSUAttributeTag tags[] = { kATSUCGContextTag };
ByteCount sizes[] = { sizeof(CGContextRef) };
ATSUAttributeValuePtr values[] = { &context };
ATSUSetLayoutControls(layout, 1, tags, sizes, values);
// Drawing
ATSUDrawText(
layout,
kATSUFromTextBeginning,
kATSUToTextEnd,
X2Fix(10.0f),
X2Fix(10.0f));
free(text);
ATSUDisposeStyle(style);
ATSUDisposeTextLayout(layout);
}
Interface Builder の NSTextView で NSLayoutManager を置き換える
Cocoa の NSLayoutManager や NSTypesetter をサブクラス化したい場合、Apple のドキュメント "Assembling the Text System by Hand" にあるように、マニュアルで NSTextView を構築してもいいが面倒だ。それに、このままではスクロールビューでデコレートもされてないのでノーグッド。
どうせなら、Interface Builder で配置した NSTextView の NSLayoutManager を置き換えるのが手っ取り早いだろう。コードは以下のようになる。
- (void) awakeFromNib {
_textStorage = [[NSTextStorage alloc] initWithString:@"Cocoa Programming Topics"];
NSLayoutManager *layoutManager = [[MyLayoutManager alloc] init];
[_textStorage addLayoutManager:layoutManager];
[layoutManager release];
NSTextContainer *textContainer = [_textView textContainer];
[layoutManager addTextContainer:textContainer];
[textContainer replaceLayoutManager:layoutManager];
}肝になるのは NSLayoutManager の addTextContainer: で元々の NSTextContainer を追加したあとに、NSTextContainer の replaceLayoutManager: を呼ぶこと。これで NSLayoutManager を置き換えられる。
Cocoa の Text System を勉強中
Mac OS X のフレームワークである Cocoa の Text System を調べるため、ドキュメントを漁り中。
そのなかで、Text System Overview: Typographical Features of the Cocoa Text System の画像 Figure 4 は、

Rendering Unicode Text With ATSUI: Text Measurements の Figure 1-4 を使うのが適切な気がする。前者だと、垂直方向の例がないので。

というか、Cocoa の Text System を理解するには ATSUI も勉強した方がいいのか? うーん、大変そうだ。