Post

Replies

Boosts

Views

Activity

Why fonts loaded using CoreText (CTFont) behave different than loaded using AppKit (NSFont)?
I tried to load font using CTFontCreateWithFontDescriptor() and it behaves differently than loaded using NSFont(). Let's say the goal is to load font using CoreText that is exactly the same as using AppKit. NSTextField If I use them in NSTextField text offsets and rendering do not match. let familyName = "Helvetica" let fontSize: CGFloat = 30 let string = "Hello, World! gÖ,|#" // Load font using AppKit let font1 = NSFont(name: familyName, size: fontSize)! // Load font using CoreText API let font2 = CTFontCreateWithFontDescriptor(CTFontDescriptorCreateWithAttributes([ kCTFontFamilyNameAttribute: familyName, kCTFontSizeAttribute: fontSize, ] as [CFString : Any] as CFDictionary), 0, nil) as NSFont // Setup text fields let field1 = NSTextField() let field2 = NSTextField() field1.setAsLabel() field2.setAsLabel() field1.font = font1 field2.font = font2 field1.stringValue = string field2.stringValue = string NSAttributedString If I use them in NSAttributedString bounding box height of text is different: let bounds1 = NSAttributedString(string: string, attributes: [ .font: font1 ]).boundingRect(with: .infinity) let bounds2 = NSAttributedString(string: string, attributes: [ .font: font2 ]).boundingRect(with: .infinity) print(bounds1) // Prints: (0.0, -7.0, 252.3486328125, 37.0) print(bounds2) // Prints: (0.0, -7.0, 252.3486328125, 31.0) Investigation I compared fonts, font attributes, traits, feature settings, even binary font tables but I didn't find any difference. It seems like there is something inside that alters behaviour. I found that if I add .usesDeviceMetrics option to NSAttributedString bounds getter, it returns the same result but also completely different frame. let bounds1 = NSAttributedString(string: "Hello, World! gÖ,|#", attributes: [.font: font1]).boundingRect(with: .infinity, options: [.usesDeviceMetrics]) let bounds2 = NSAttributedString(string: "Hello, World! gÖ,|#", attributes: [.font: font2]).boundingRect(with: .infinity, options: [.usesDeviceMetrics]) print(bounds1) // Prints: (2.3583984375, -6.6357421875, 249.9609375, 33.837890625) print(bounds2) // Prints: (2.3583984375, -6.6357421875, 249.9609375, 33.837890625) Question How to load a font using CoreText in a way that NSFont does? Minor question: Why does NSTextField set it's frame origin to -2.0? Just extensions I used in code above: extension CGSize { public static var infinity: Self { .init(width: CGFloat.infinity, height: CGFloat.infinity) } } extension NSTextField { func setAsLabel() { translatesAutoresizingMaskIntoConstraints = false isBezeled = false isBordered = false isEditable = false isSelectable = false drawsBackground = false } }
2
0
746
Nov ’23