Cocoa で独自の Text View を実装する

iPhone も盛り上がっていることだし、ひさしぶりに Cocoa プログラミングを始めてみる。

NSView の CGContextRef に ATSUI でテキストを描画する方法

Cocoa の NSViewApple Type Services for Unicode Imaging (ATSUI) でテキストを描画する方法を紹介する。

ATSUI では描画に Quartz の CGContextRef を設定することができる。CGContextRefNSGraphicsContextgraphicsPort で取得できるので、以下のようなコードで設定できる。

CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
ATSUAttributeTag tags[] = { kATSUCGContextTag };
ByteCount sizes[] = { sizeof(CGContextRef) };
ATSUAttributeValuePtr values[] = { &context };
ATSUSetLayoutControls(layout, 1, tags, sizes, values);

以下のコードでは、NSViewdrawRect: で 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 の NSLayoutManagerNSTypesetter をサブクラス化したい場合、Apple のドキュメント "Assembling the Text System by Hand" にあるように、マニュアルで NSTextView を構築してもいいが面倒だ。それに、このままではスクロールビューでデコレートもされてないのでノーグッド。

どうせなら、Interface Builder で配置した NSTextViewNSLayoutManager を置き換えるのが手っ取り早いだろう。コードは以下のようになる。

- (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];
}

肝になるのは NSLayoutManageraddTextContainer: で元々の NSTextContainer を追加したあとに、NSTextContainerreplaceLayoutManager: を呼ぶこと。これで NSLayoutManager を置き換えられる。

Cocoa の Text System を勉強中

Mac OS X のフレームワークである Cocoa の Text System を調べるため、ドキュメントを漁り中。

そのなかで、Text System Overview: Typographical Features of the Cocoa Text System の画像 Figure 4 は、

Glyph mertics

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

Terms for glyph measurements

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

Want fries with that?

Open Source Projects