CoreText Swift Academy - part 1

Ever wanted to layout letters? implement label view? create text edit component from the ground? bear with me.

CoreText is low-level framework for laying out text and handling fonts. Low level like "C language level low", but also like "Font glyph level low".

What CoreText can:

  • Manage fonts with CTFontManager* family functions
  • Work with fonts with CTFont, CTFontDescriptor, CTFontCollection, CTGlyphInfo
  • Layout font with CTFrame, CTFramesetter, CTTypesetter, CTLine, CTParagraphStyle, CTTextTab
  • Draw text with CTRun

Summary: CoreText can layout and draw text.

HelloWorld

Since CoreText is an Apple Platform engine, it provides outlets to other APIs, eg CGContext for drawing. Eg to draw "Hello World" on macOS:

class Label: NSView {
  var text: String

  init(text: String) {
    self.text = text
    super.init(frame: NSRect())
  }
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  override func draw(_ dirtyRect: NSRect) {
    super.draw(dirtyRect)

    // create CTLine from NSAttributedString
    let attributedString = NSAttributedString(string: text)
    let line = CTLineCreateWithAttributedString(attributedString)

    // Draw text
    if let context = NSGraphicsContext.current?.cgContext {
      CTLineDraw(line, context)
    }
  }
}
Label(text: "Hello World")

result:

Screenshot-2020-07-05-at-12.37.28

walk-through

The most fundamental type of CoreText is CTLine. Despite its name, it's not necessarily a single line. For the beginning, put everything in the line, CTLine. CTLine take attibuted string as an input. This is another fundation of CoreText. Attributed string (CFAttribtuedString) is the source of text for CoreText engine. CFAttribtuedString is bridged to NSAttribuedString so you probably don't have to create CoreFoundation for type most of the time.

    let attributedString = NSAttributedString(string: text)
    let line = CTLineCreateWithAttributedString(attributedString)

Next is drawing. Without going into details (yet), I can draw a line directly to CGContext available on UIKit/AppKit with one of the helper functions:

    CTLineDraw(line, context)

I'm done. The text is layout and CGContext draw it as part of my view.


Node: this is part of series (1 of many). check here tomorrow for next episode.