NetNewsWire/Mac/MainWindow/Timeline/Cell/NSAttributedString+NetNewsW...

119 lines
4.3 KiB
Swift
Raw Normal View History

//
// NSAttributedString+NetNewsWire.swift
// NetNewsWire
//
// Created by Nate Weaver on 2020-04-07.
// Copyright © 2020 Ranchero Software. All rights reserved.
//
2020-04-15 23:34:16 +02:00
#if canImport(AppKit)
import AppKit
2020-04-15 23:34:16 +02:00
typealias Font = NSFont
typealias FontDescriptor = NSFontDescriptor
typealias Color = NSColor
private let boldTrait = NSFontDescriptor.SymbolicTraits.bold
private let italicTrait = NSFontDescriptor.SymbolicTraits.italic
private let monoSpaceTrait = NSFontDescriptor.SymbolicTraits.monoSpace
#else
import UIKit
typealias Font = UIFont
typealias FontDescriptor = UIFontDescriptor
typealias Color = UIColor
private let boldTrait = UIFontDescriptor.SymbolicTraits.traitBold
private let italicTrait = UIFontDescriptor.SymbolicTraits.traitItalic
private let monoSpaceTrait = UIFontDescriptor.SymbolicTraits.traitMonoSpace
#endif
extension NSAttributedString {
2020-04-15 23:34:16 +02:00
func adding(font baseFont: Font, color: Color? = nil) -> NSAttributedString {
let mutable = self.mutableCopy() as! NSMutableAttributedString
let fullRange = NSRange(location: 0, length: mutable.length)
if let color = color {
mutable.addAttribute(.foregroundColor, value: color as Any, range: fullRange)
}
let size = baseFont.pointSize
let baseDescriptor = baseFont.fontDescriptor
let baseSymbolicTraits = baseDescriptor.symbolicTraits
2020-04-15 23:34:16 +02:00
let baseTraits = baseDescriptor.object(forKey: .traits) as! [FontDescriptor.TraitKey: Any]
let baseWeight = baseTraits[.weight] as! Font.Weight
mutable.enumerateAttribute(.font, in: fullRange, options: []) { (font: Any?, range: NSRange, stop: UnsafeMutablePointer<ObjCBool>) in
2020-04-15 23:34:16 +02:00
guard let font = font as? Font else { return }
var newSymbolicTraits = baseSymbolicTraits
let symbolicTraits = font.fontDescriptor.symbolicTraits
2020-04-15 23:34:16 +02:00
if symbolicTraits.contains(italicTrait) {
newSymbolicTraits.insert(italicTrait)
}
2020-04-15 23:34:16 +02:00
if symbolicTraits.contains(monoSpaceTrait) {
newSymbolicTraits.insert(monoSpaceTrait)
}
2020-04-15 23:34:16 +02:00
#if canImport(AppKit)
var descriptor = baseDescriptor.withSymbolicTraits(newSymbolicTraits)
2020-04-15 23:34:16 +02:00
#else
var descriptor = baseDescriptor.withSymbolicTraits(newSymbolicTraits)!
#endif
2020-04-15 23:34:16 +02:00
if symbolicTraits.contains(boldTrait) {
// If the base font is semibold (as timeline titles are), make the "bold"
// text heavy for better contrast.
if baseWeight == .semibold {
2020-04-15 23:34:16 +02:00
let traits: [FontDescriptor.TraitKey: Any] = [.weight: Font.Weight.heavy]
let attributes: [FontDescriptor.AttributeName: Any] = [.traits: traits]
descriptor = descriptor.addingAttributes(attributes)
}
}
2020-04-15 23:34:16 +02:00
let newFont = Font(descriptor: descriptor, size: size)
mutable.addAttribute(.font, value: newFont as Any, range: range)
}
2020-04-15 23:34:16 +02:00
// make sup/sub smaller. `Key("NSSupeScript")` is used here because `.superscript`
2020-04-16 21:55:39 +02:00
// isn't defined in UIKit.
2020-04-15 23:52:23 +02:00
let superscriptAttribute = Key("NSSuperScript")
mutable.enumerateAttributes(in: fullRange, options: []) { (attributes: [Key : Any], range: NSRange, stop: UnsafeMutablePointer<ObjCBool>) in
2020-04-15 23:52:23 +02:00
guard let superscript = attributes[superscriptAttribute] as? Int else {
return
}
if superscript != 0 {
2020-04-15 23:34:16 +02:00
let font = mutable.attribute(.font, at: range.location, effectiveRange: nil) as! Font
#if canImport(AppKit)
let features: [FontDescriptor.FeatureKey: Any] = [.typeIdentifier: kVerticalPositionType, .selectorIdentifier: superscript > 0 ? kSuperiorsSelector : kInferiorsSelector]
#else
let features: [FontDescriptor.FeatureKey: Any] = [.featureIdentifier: kVerticalPositionType, .typeIdentifier: superscript > 0 ? kSuperiorsSelector : kInferiorsSelector]
#endif
let attributes: [FontDescriptor.AttributeName: Any] = [.featureSettings: [features]]
2020-04-08 13:50:54 +02:00
let descriptor = font.fontDescriptor.addingAttributes(attributes)
2020-04-15 23:34:16 +02:00
let newFont = Font(descriptor: descriptor, size: font.pointSize)
mutable.addAttribute(.font, value: newFont as Any, range: range)
2020-04-15 23:52:23 +02:00
mutable.addAttribute(superscriptAttribute, value: 0, range: range)
}
}
return mutable.copy() as! NSAttributedString
}
convenience init(html: String) {
let data = html.data(using: .utf8)!
let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [.characterEncoding: String.Encoding.utf8.rawValue, .documentType: NSAttributedString.DocumentType.html]
try! self.init(data: data, options: options, documentAttributes: nil)
}
}